Snapshot of the shared working tree's outstanding changes (multiple concurrent workstreams), excluding generated runtime state files (.football-tote-state.json, .tote-platform-state.json, .usdm-historical-chart.html). Spans: wallet shell (connect/, keystore MultiKeyStore+vault, screens, currency picker, sign-message), verify artifacts, new Potidaea/DRA/tote contracts + regtest suites, cross-chain/T6 + WalletConnect Parameters, a telegram-orderbook subproject, design mockups, and docs. See shells/app/WALLET-COORDINATION.md for the per-file ownership split. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.9 KiB
Testing the wallet-connector adapters (WalletConnect · CashConnect · WizardConnect)
How to test each adapter on a device with a real wallet (the relay + signing can't run from a headless box). Covers prerequisites, run commands, expected results, the gotchas we already hit live, and — for the two protocols whose dApp API isn't yet pinned — exactly what to confirm against the installed SDK.
0. Prerequisites (once)
cd spike/wc-connect
npm install
- Project ID (WalletConnect/CashConnect, both ride the WC2 relay): free at
https://cloud.reown.com → create a project → copy the 32-char id. Export it:
export WC_PROJECT_ID=<id>(it's a public client id, not a secret; don't commit it). - A wallet that speaks the protocol (Cashonize for WC + CashConnect; Paytaca for WizardConnect). Import a key (e.g. a chipnet WIF) if you want chipnet.
- Network: the dApp advertises
WC_CHAIN(bch:bitcoincashmainnet [default] orbch:bchtestchipnet). The wallet must be on the same network.
1. WalletConnect (wc2-bch-bcr) — VALIDATED
Two tests, both connect.mjs-family:
Handshake (✅ device-validated, snapshot 0055):
WC_PROJECT_ID=$WC_PROJECT_ID npm run connect:wc
Paste the printed wc:… URI into Cashonize → WalletConnect, approve. Expect:
Paired with: Cashonize, then bch_getAddresses → [address] and a bch_signMessage
signature. (Earlier success: address bitcoincash:qqlqsl7s2…, a valid base64 sig.)
Co-sign (bch_signTransaction, the tote/checkers stake path — SAFE, nothing
broadcast):
WC_PROJECT_ID=$WC_PROJECT_ID npm run connect:signtx
It builds a self-send of one of your own UTXOs, marks that input as a placeholder
for the wallet, and requests signing with broadcast: false → the wallet signs,
no funds move, you see the signed tx hex. (Needs the address to hold ≥1 UTXO; on
mainnet a few thousand sats, on chipnet your faucet funds. Set WC_CHAIN=bch:bchtest
- put the wallet on chipnet to test the tote's real network.)
2. CashConnect — API pinned to cashconnect@0.0.25; pair to test handshake
WC_PROJECT_ID=$WC_PROJECT_ID npm run connect:cc
cashconnect.mjs is rewritten against the installed dApp API (resolved from
node_modules/cashconnect/dist/index.d.ts + compiled source) — no more CONFIRM
guesses. Confirmed facts, and how CashConnect differs from WalletConnect:
- Construction:
new CashConnectDapp({ projectId, metadata }, chain, dialogs)thenawait dapp.start().dialogs={ newSession, reconnectSession, request }classes; the pairing URI is surfaced by instantiatingdialogs.newSession(url, …)(CashConnect rewrites thewc:scheme tocc:). Paste thecc:URI into Cashonize → CashConnect. - Connect:
await dapp.connect(requiredNamespaces)returns a boolean (no{ uri, approval }). The account is read inonConnectedfromsession.namespaces.bch.accounts[0], formattedbch:<network>:<pubkeyHex>— a pubkey, not a cashaddr; there is nobch_getAddresses. - Methods (CashRPC,
_V0-suffixed):bch_getBalance_V0,bch_getChangeLockingBytecode_V0,bch_getTokens_V0,bch_signMessage_V0,bch_signTransaction_V0,wc_authRequest. The handshake test callsbch_getBalance_V0+bch_signMessage_V0(params{ message: Uint8Array }). - Serialization:
dapp.request(method, params)applies libauthstringifytoparamsinternally andparseExtendedJsones the response — pass raw objects (Uint8Array/bigint); do not pre-applytoWcParams(that is WalletConnect-only). - Co-sign is wallet-orchestrated, not dApp-pass-through. Reading the wallet's
CashRPC_V0.signTransactionhandler (lines 995–1112 of the installed dist):- Inputs/outputs are either template-scoped (uses the BchNamespace
template— a libauthWalletTemplatethe dApp can provide at session establishment, so a CashScript covenant CAN be exported to a template and referenced) or wallet-scoped (wallet looks up its own UTXO). - After parsing dApp-provided inputs/outputs the wallet auto-runs
usingUnspents → addTokensFromUnspents → addTokenChangeOutputs → addSatoshisFromUnspents → addSatoshiChangeOutput— it adds its own UTXOs + change, taking control of input/output composition. - The wallet runs a libauth VM
verifyon the assembled tx and rejects on fail. Net: CashConnect V0 is designed for wallet-orchestrated standard flows — plain BCH sends and CashTokens FT/NFT sends — which it does cleanly. For dApp-built covenant txs (totebet(),GamePoolEscrowFlat.fund()), the dApp-supplied- template path is technically open but blocked in practice by the auto-orchestration breaking covenant input/output structure, wallets' reasonable refusal to run arbitrary dApp templates, and the VM verify gate. WalletConnect'sbch_signTransaction(validated 0057, true pass-through) remains the path for those flows. Cashonize speaks both, so users never see the routing decision.
- Inputs/outputs are either template-scoped (uses the BchNamespace
- Bundle patch (cashconnect@0.0.25): the bundle does
import Client from '@walletconnect/sign-client'; sign-client's ESM build setsdefaultto the package namespace (object), not theSignClientclass — so under ESMClient.initis undefined.patches/apply-cashconnect-fix.mjsrewrites the bundle toimport { SignClient as Client } …. Idempotent; wired aspostinstall. - Project ID (
WC_PROJECT_ID=c4ac…3de0) validated against the WC2 relay — dApp initializes,dapp.start()succeeds,connect()produces acc:pairing URI. Pair it in Cashonize → CashConnect to complete the handshake on-device.
3. WizardConnect — confirm protocol/SDK, then adapter
Not yet scaffolded — pin the protocol first:
- Sources: Riften Labs docs https://docs.riftenlabs.com/ (Cauldron / wallets); it ships in Paytaca (paytaca/paytaca-app releases mention WizardConnect: parallel broadcast via watchtower, duplicate-request suppression). ParionUSD uses it.
- Confirm: is WizardConnect (a) a distinct protocol with its own SDK, or (b)
Paytaca's branding over WalletConnect v2? If (b), the existing
connect.mjsmay pair with Paytaca directly (trynpm run connect:wcagainst Paytaca). If (a), get its dApp SDK + the connect/sign API, then add an adapter mirroringcashconnect.mjs. - The
WalletSessioninterface (src/connect/proposer.ts) is the seam the adapter implements either way.
4. Troubleshooting (from live runs)
Proposal expired— pairing URIs last ~5 min. Generate, then paste/scan immediately; don't switch networks mid-pairing. If it expires, just re-run.- "Dapp requires wallet to be on chipnet" — the dApp advertised
bch:bchtestbut the wallet is on mainnet. Switch the wallet's network, OR (for a wiring test) run the dApp on mainnet:WC_CHAIN=bch:bitcoincash. The handshake/co-sign prove the adapter regardless of network; only a real broadcast needs matching networks. - No QR / can't scan — copy the
wc:…URI text and use the wallet's "paste URI". No plain-BCH UTXOs(signtx) — the connected address is empty; fund it with a tiny amount (nothing is spent —broadcast:false).- Relay/init hangs — check outbound access to the WC2 relay; retry.
5. What "validated" means per adapter
| Adapter | Handshake | Co-sign (signTransaction) |
|---|---|---|
| WalletConnect | ✅ on-device (0055) | ✅ on-device (0057), connect:signtx |
| CashConnect | API pinned to v0.0.25; project ID + relay validated; pair to validate on-device | ✅ for standard BCH / token sends; dApp covenant txs route through WC (auto-orchestration blocks them in practice) |
| WizardConnect | confirm protocol first | via the same WalletSession seam |
The dApp-side co-sign core is shared + unit-tested (src/connect/proposer.ts,
snapshot 0056) — each adapter only supplies connect + the signTransaction transport.