Repository navigation
Tracking: Dash Platform usernames and DashPay contacts in dash-qt (--enable-platform-gui) #7512
Description
What / why
dash-qt has no Dash Platform support. This issue tracks adding the DashPay feature set of the mobile wallets to it: usernames (DPNS), DashPay profiles, contact requests, contact-to-contact payments and seed-only recovery. It must not couple dashd to Platform, and it must interoperate with the DashPay iOS and Android wallets.
The work is landing as small, stacked, reviewable PRs across dashpay/dash and dashpay/platform. This issue is the cross-repo map.
Current status (2026-09-28)
All PRs below are open and ready for review unless noted. The whole stack was verified end to end on the live PV13 testnet on 2026-09-28, including interop with the DashPay iOS app. Screenshots and their manifest.
dashpay/platform
| PR | What | State |
|---|---|---|
| dashpay/platform#5160 | feat(sdk): route DAPI connections through a SOCKS5 proxy (plus an IPv6-endpoint panic fix) |
ready for review |
| dashpay/platform#4633 | feat(sdk): dash-platform-cxx, a thin CXX shell over dash-sdk for C++ embedders; stacked on dashpay/platform#5160 |
ready for review |
| dashpay/platform#4964 | fix(sdk): no panic in DapiClient::new on an empty address list |
merged |
| dashpay/platform#4965 | test(sdk): cargo-fuzz harness over drive-proof-verifier FromProof |
draft (fuzz campaign running) |
| dashpay/platform#4963 | feat(sdk): reject response metadata from an unexpected chain id |
closed by the maintainer; the shell does the check |
| dashpay/platform#4632 | pure DPNS/DashPay document builders shared with embedders | closed; the SDK-first shell does not need them |
dashpay/dash
Each PR's head branch ends at its own commit on one linear stack. Each body says which commit to review from.
| PR | What | Depends on |
|---|---|---|
| #7623 | C1 build: depends builds the Dash Platform CXX bindings behind PLATFORM_GUI=1 (Rust toolchain, --enable-platform-gui, Windows DLL allowlist, linux64_platform_gui CI) |
— |
| #7763 | C2 wallet: DIP-15 compact xpub, accountReference MAC and asset-lock seams | — (no Rust) |
| #7764 | C3 chainparams: Platform Tenderdash chain id | — (no Rust) |
| #7670 | C4 client library over dash-platform-cxx; sendCoins surfaces a mempool rejection; Node::isReachable |
C1, C2, C3 |
| #7671 | C5 DashPay tab, opt-in, privacy gating and network route | C4 |
| #7765 | C6 usernames: identity and DPNS registration, dashboard | C5 |
| #7766 | C7 profiles and contacts (DIP-15) | C6 |
| #7767 | C8 contact payments, seed recovery and identity details | C7 |
The Guix enablement follows as a new PR once the depends approach in #7623 is accepted.
Merged earlier: #7511 (DIP-14 Derive256), #7581 (Platform key provider, data records and DIP-15 friendship keychain seams), #7591 (masternode Platform endpoints, quorum keys and islocks through the node interface), and dashpay/platform#4344, dashpay/platform#4345 and dashpay/platform#4388.
Architecture
- Compile-time optional:
--enable-platform-gui(default off) and the depends knobPLATFORM_GUI=1, followingMULTIPROCESS. A default build is unchanged.dashd,dash-cli,dash-tx,dash-walletand the fuzz binary never link Rust, andcheck-no-rust.pyenforces that in CI. - SDK-first thin shell. The Rust code lives in dashpay/platform as
dash-platform-cxx, a thincxxshell overdash-sdkwith no protocol logic of its own. The SDK owns query construction, DAPI transport, retries and address banning, proof verification, protocol-version tracking and freshness. Core pins the shell by commit, and builds it in depends from two sha256-pinned archives, offline. - Local trust anchor. Core pushes evonode endpoints from its deterministic masternode list, the Platform quorum keys from its LLMQ store and its best ChainLock height. Every read is proved against those. There is no trusted HTTP service, no seed list and no remote quorum source. The chain id comes from
CChainParams. - Key custody. Private keys never cross the FFI. The wallet receives the full signable preimage, hashes and checks it, and signs through a kind-scoped, move-only
SigningOperation. ECDH and the accountReference MAC are computed inside the wallet, and the MASTER key is refused for both. - Network privacy. DashPay uses Core's own network settings. It connects to evonodes the way Core connects to peers (
-proxy,-onion,-onlynet, the Tor controller), through SOCKS5 with per-connection isolation for-proxyrandomize. It never falls back to a direct connection. The opt-in states what the answering evonode can see.
Decisions log
- 2026-08-01, IsMine watch-only guard deferred. fix(wallet): report public-only descriptors in signing wallets as watch-only #7510 was closed. The friendship receiving chain is private, and the contact chain is never imported.
- 2026-08-01, DIP-14 compatibility semantics. Sub-2^32 indexes use raw BIP32 index space.
- 2026-08-01, no QWizard. The depends and Guix Qt build disables the wizard feature, so dialogs use QDialog and QStackedWidget.
- 2026-08-07/08, canonical Rust crates replace C++ reimplementations. The hand-written C++ GroveDB, codec and BLAKE3 code of the first branch was dropped.
- 2026-08-08,
panic=unwindfor the bridge. Residual panics become catchable C++ exceptions. - 2026-08-12, the release target enables Platform GUI in dash-qt. Guix validation with the feature on is a release gate.
- 2026-09, SDK-first thin shell. Core's own transport (mbedTLS gRPC-Web), protobuf and CBOR encoders, and the transport-free verifier path were dropped.
dash-platform-cxx(feat(sdk): add dash-sdk-cxx, a C++ binding of dash-sdk for Dash Core platform#4633) became a thin shell overdash-sdk, and feat(sdk)!: pure DPNS and DashPay document builders shared with embedders platform#4632, refactor(drive-abci): share the v1 document-query wire decoders platform#4618, feat(sdk)!: verify document proofs against the wire request and share DPNS/DashPay document assembly platform#4619, refactor(sdk): shared wire-request decode and pure DPNS/DashPay document builders platform#4389 and feat(sdk): add transport-free CXX bindings platform#4416 were closed. - 2026-09, chain id stays in the shell. The maintainer closed feat(sdk): reject response metadata from an unexpected chain id platform#4963 (chain id checked in the SDK). The shell checks the signed
chain_idafter the SDK verifies the quorum signature, and Core supplies it fromCChainParams::PlatformChainId()(feat: add Platform Tenderdash chain id to CChainParams #7764). - 2026-09, PV13 document-id fix. Up to protocol version 13, a create's document id is sent as given and Drive refuses a mismatch, so every create now carries the id
put_to_platformwould derive. - 2026-09, sign-once registration. One passphrase prompt funds the asset lock and signs the identity create, the DPNS preorder and domain and the optional profile. All of them are persisted before the wallet is locked again, and a restart resends them without prompting.
- 2026-09, DIP-15 interop fixes and iOS interop QA. The compact xpub gets the parent fingerprint, the accountReference MAC is computed in the wallet (feat(wallet): DIP-15, accountReference, asset-lock and eligibility seams for DashPay #7763), and recipient keys are picked by the SDK's policy. Only the newest request per sender counts, ranked by
createdAtthenaccountReference. A superseding request re-establishes the contact. Recovery remembers sent requests. The dash-qt ↔ DashPay iOS round trip (requests both ways, a re-send, payments both ways, profile updates, restore from seed) passed on testnet on 2026-09-28. - 2026-09, SOCKS5 proxy support. DashPay follows
-proxyand-proxyrandomizeinstead of refusing to run under a proxy (feat(sdk): route DAPI connections through a SOCKS5 proxy platform#5160 and feat(sdk): add dash-sdk-cxx, a C++ binding of dash-sdk for Dash Core platform#4633). - 2026-09, UX rework. Platform balances are shown in Dash, never credits. Options → Wallet has a DashPay group. There is no Refresh button (reads follow ChainLocks), one filled button per state, plain-sentence errors with Show details, and pay-by-username from the Send tab with a contact picker.
- 2026-09, Guix PR paused. guix: support PLATFORM_GUI=1 release builds #7672 was closed. A new Guix PR follows once build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623's approach is accepted.
Open asks
- Core maintainer decision on build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623: can depends carry a prebuilt, sha256-pinned Rust toolchain behind
PLATFORM_GUI=1(default builds unchanged, Rust only in dash-qt)? The C4–C8 PRs build on this answer. The C2 and C3 PRs are useful either way. - Depends mirror upload: before build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623 merges, a maintainer needs to put the Platform source tarball and the crate bundle for the pinned commit on the depends sources mirror. The file names and sha256s are in build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623.
- Guix PR: after (1), a new PR enables
PLATFORM_GUI=1in Guix release builds and runs the two-builder reproducibility check. - Platform review: feat(sdk): route DAPI connections through a SOCKS5 proxy platform#5160, then feat(sdk): add dash-sdk-cxx, a C++ binding of dash-sdk for Dash Core platform#4633.
Known gaps
- In Add contact, the "Can't receive contact requests" note appears only after the row is selected. The DashPay iOS app checks each row as it scrolls into view. This is a minor UX gap.
- A superseding contact request that cannot be decrypted leaves the contact on its old chain, without an error on the row, until a newer request arrives. The payment effect matches the mobile wallets' behaviour.
- Not yet run: Guix and armhf, ppc64 and riscv64 builds of the bindings (the Guix PR's job), or a Tor round with the proxy passthrough.
Activity
PastaPastaPasta commentedon Aug 13, 2026
Seed-only recovery of Platform state — design answer
Raised at the 2026-08-12 dev sync (kwvg): DashPay wallet data is stored as opaque per-wallet records — how does mnemonic-only recovery restore Platform state? Investigated against both the current implementation and the mobile wallets' shared recovery policy (
rs-platform-wallet, the crate behind dashwallet-ios/android). Design below ships in v24 with the wallet wave; implementation is on the reference branch (PastaPastaPasta#67) first, then extracted into the train.What is derivable from seed alone: every private key (identity auth
m/9'/coin'/5'/0'/0'/i'/k', asset-lock funding, DIP-15 friendship chains). What is not: the local records — identity id/state, contact set, payment cursors, and the DPNS preorder salt (CSPRNG).Recovery flow (auto-probe on wallet load when a seed exists but no identity record; bounded ~20s, never blocks wallet function; mirrors mobile's policy):
getIdentityByPublicKeyHashquery, with a three-way outcome — found / proven-absent / network-incomplete — so an outage is never misreported as "no identity". Materialize the full on-chain key set with per-key verification against published pubkeys.namesOfIdentity(+ contested-state check) rebuilds the registration record.Documented limitation (same as both mobile wallets): an in-flight DPNS registration (preorder broadcast, domain not yet) is not recoverable seed-only — the salt is random. A
REGISTEREDidentity recovers fully; mid-registration needs the full backup. Follow-up idea recorded, not v24: derive the salt deterministically (e.g. HMAC of an auth key and the normalized label) — consensus-transparent, would make even mid-registration state recoverable, and no client does it today.Full backup/restore (
backupwallet/restorewallet) remains the complete-state path and is unaffected.🤖 Posted autonomously by Claude on behalf of pasta.
refactor: expose masternode Platform endpoints, quorum keys and isloc…
PastaPastaPasta commentedon Aug 13, 2026
Guix reproducibility confirmed for the Rust/Platform-enabled build.
Two independent builders built commit
c9d6fbd459d9withPLATFORM_GUI=1 HOSTS=x86_64-linux-gnu— the GitHub-hostedubuntu-24.04-armrunner (workflow run 31720606525) and a local OrbStack container — and all three artifacts are bit-identical, including the debug tarball:Scope of the claim: both builders are aarch64 hosts cross-compiling to
x86_64-linux-gnu, so this proves host-to-host reproducibility between independent environments, not yet reproducibility across differing build architectures — an x86_64-host run of the same commit would close that gap.Getting there required five bring-up fixes on this branch, all of which are Guix-environment issues rather than Rust-integration ones:
patchelfandzlibadded to the Guix manifest (the prebuilt rust toolchain's ELF interpreter fix silently skipped without patchelf, and rustc needs libz at runtime),lbzip2added (mbedtls is the first.tar.bz2depends package to reach the Guix path), the rustc sysroot lib dir onLD_LIBRARY_PATHfor cargo build scripts (the Guix ld wrapper strips RPATH by design), and an archive rescan for the cxxbridge↔dashrust mutual references.One latent hazard worth recording: Rust does not get a
--remap-path-prefixequivalent to the C++-ffile-prefix-map. It cannot bite in the standard flow because every builder compiles at the same in-container path, but a builder using a non-canonical mount point would see a differing debug tarball while the stripped tarball still matched.🤖 Posted autonomously by Claude on behalf of pasta.
refactor: expose masternode Platform endpoints, quorum keys and isloc…
refactor: expose masternode Platform endpoints, quorum keys and isloc…
refactor: expose masternode Platform endpoints, quorum keys and isloc…
Merge #7591: refactor: expose masternode Platform endpoints, quorum k…
Merge #7581: feat(wallet): add Platform key provider, data records an…
PastaPastaPasta commentedon Aug 20, 2026
Status update (2026-08-20): the train has been restructured around the Platform-owned CXX architecture — all Rust/CXX bindings now live in dashpay/platform (dashpay/platform#4416, packages/rs-platform-cxx) and Core consumes the prebuilt archive through depends. #7580 is closed as superseded.
Merged: #7581 (Platform key provider, records, DIP-15 friendship seams — reworked to the typed PlatformKeyResult API, descriptor-root derivation), #7591 (node seams), #7600/#7616 (provider tx interfaces).
In flight: #7617 (wallet UTXO reconcile fix).
The remaining series, extracted from the composite integration branch (PastaPastaPasta#67, CI fully green):
Gates: dashpay/platform#4388 → #4389 → #4416 for the depends pin; a descriptor-wallet E2E rerun before #7627 undrafts; a PLATFORM_GUI Guix run before #7628 undrafts.
🤖 Posted autonomously by Claude on behalf of pasta.
PastaPastaPasta commentedon Sep 8, 2026
Platform-side status update (2026-09-07): the earlier platform stack (dashpay/platform#4478, #4389, #4433, #4416, plus #4464) is closed and replaced by three PRs rebuilt to reuse the workspace's existing patterns after review:
platform-query-wiredecoder crate + a pre-authentication allocation abort fix in dpp document deserialization (affects every proof-verifying client, including this GUI)FromProof<GetDocumentsRequest>in drive-proof-verifier + pure DPNS/DashPay builders shared with dash-sdk (stacked on depends: bump bls-dash version #4618)dash-platform-cxxcrate this GUI consumes (stacked on refactor: Remove includes; backport 16659 #4619, draft until refactor: Remove includes; backport 16659 #4619 merges)Core-side consequences for #7623 and up: re-pin
platform_cxxto a commit on the #4620 branch;set_contextnow takes(network, platform_quorum_type, protocol_version, activation_height)andupdate_quorum_keysno longer takes a per-call quorum type; thestandalone/build directory andinstall.share gone — build-p dash-platform-cxxfrom the workspace root and installtarget/<profile>/include+libdash_platform_cxx.a. The DashConnect bridge additions still need porting onto the new crate.🤖 Posted autonomously by Claude on behalf of pasta.
PastaPastaPasta commentedon Sep 8, 2026
SDK-first rebuild of the Platform GUI integration (2026-09-08)
QuantumExplorer's question on dashpay/platform#4618 ("why are you not just using the SDK?") was tested rather than argued. Result: the normal
dash-sdk, networking included, passes Core's requirements, so the series is rebuilt around it. The transport-free design (C++ transport + wire-request reverse decoding) is superseded.Measured before choosing (Platform
v4.2-dev@e037d42dd6, Rust 1.92):cargo checkofdash-sdk(no default features):x86_64/aarch64-linux-musl,x86_64-pc-windows-gnu, andriscv64gc-unknown-linux-gnu(in a container with a pinnedprotoc; the distroprotocversion string breakstenderdash-proto's build script, same as depends already handles). PowerPC and armhf are outsiderust_stdlib.mk's target list in either design.x86_64-unknown-linux-muslbuild of the driver ran under emulation with identical results.Security+CoreFoundation(rustls native roots;SystemConfigurationfrom the August note is not needed), Windowsws2_32 bcrypt crypt32 userenv ntdll. All withinsymbol-check.py's allowlists.cargo vendor --lockedfails onv4.2-devfor reasons unrelated to networking (two dual-source packages); fixed in build: make the workspace lockfile vendorable with --locked platform#4631. Whole-workspace vendor: 840 crates, 150 MB archive.rs-dapi-client(tonic's connector can take one; upstream follow-up).New series (each N+1 is a draft until its base is ready):
cargo vendor --lockedfix, ready) → Backports 0.19 pr11 #4632 (pure DPNS/DashPay builders, the reusable half of refactor: Remove includes; backport 16659 #4619) → Merge #16557: [wallet] restore coinbase and confirmed/conflicted checks in SubmitMemoryPoolAndRelay() #4633 (dash-platform-cxxoverdash-sdk)Disposition of the old series (nothing closed yet):
platform-query-wirefound. Superseded once #4633 lands.FromProof<GetDocumentsRequest>half not needed. Superseded.dash-platform-cxx::client; "empty == proven absent" → SDKFromProof+ client.lbzip2, otherwise identical).🤖 Posted autonomously by Claude on behalf of pasta.
PastaPastaPasta commentedon Sep 25, 2026
Update on follow-up P1 (
SdkBuilder::with_expected_chain_idin rs-sdk): dashpay/platform#4963 is closed and won't be merged.Reasoning (full version on #4963): the chain id is already covered by the quorum signature, so the check adds no security. Forging a different chain id breaks the signature. Other networks' quorums aren't in our Core chain. Mainnet has only ever had one Platform chain (
evo1). The only case it covers is operational and testnet-only: after a Platform reset, a stale node serving the old chain can confuse a long-running client's height watermark. That isn't worth a breaking change toStaleNodeErrorin rs-sdk.Effect on this tracker: none on the critical path. P1 was never a blocker. The design keeps the chain-id check in the rs-platform-cxx shell: after signature verification,
metadata.chain_idis compared withCChainParams::platform.chain_id(C3), before the shell's own height watermark. The SDK's own height watermark stays off (with_height_tolerance(None)), so a foreign-chain proof can't advance any SDK state. Theplatform/chain-idwallet record andPLATFORM_NETWORK_CHANGED(C5) stay as designed, since they handle the testnet-reset UX. The one thing that changes is the step "when P1 merges, delete the shell check and re-enable the SDK watermark"; that step is dropped.🤖 Posted autonomously by Claude on behalf of pasta.
docs: DashPay GUI screenshots for dashpay/dash#7512 PRs
docs: final DashPay GUI screenshots for the dashpay/dash#7512 PRs
PastaPastaPasta commentedon Sep 28, 2026
The Platform GUI stack is now published and ready for review. It is rebuilt SDK-first and verified end to end on the live testnet on 2026-09-28, including interop with the DashPay iOS app.
dashpay/dash (from PastaPastaPasta/dash, stacked in this order):
PLATFORM_GUI=1. This one needs a maintainer decision on carrying a pinned Rust toolchain in depends, plus a mirror upload of two archives. Details are in the PR.CChainParams. No Rust; can merge on its own.dash-platform-cxx.dashpay/platform:
rs-dapi-client.dash-platform-cxxshell, stacked on chore: bump copyright year to 2023, add missing copyrights #5160. Core pins it at2a0a1cca31.Closed as superseded: #7669 (folded into #7623) and #7672 (Guix; a new PR follows once #7623's approach is accepted).
Screenshots: https://github.com/PastaPastaPasta/dash-ui-artifacts/tree/main/dashpay-gui-2026-09-final
🤖 Posted autonomously by Claude on behalf of pasta.