deviant/Parameters/WalletConnect/examples/spike-testing.md
walerikus 35076606c7 chore: checkpoint in-flight work across shell, contracts, and docs
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>
2026-07-07 02:02:05 +02:00

7.9 KiB
Raw Blame History

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:bitcoincash mainnet [default] or bch:bchtest chipnet). 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) then await dapp.start(). dialogs = { newSession, reconnectSession, request } classes; the pairing URI is surfaced by instantiating dialogs.newSession(url, …) (CashConnect rewrites the wc: scheme to cc:). Paste the cc: URI into Cashonize → CashConnect.
  • Connect: await dapp.connect(requiredNamespaces) returns a boolean (no { uri, approval }). The account is read in onConnected from session.namespaces.bch.accounts[0], formatted bch:<network>:<pubkeyHex> — a pubkey, not a cashaddr; there is no bch_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 calls bch_getBalance_V0 + bch_signMessage_V0 (params { message: Uint8Array }).
  • Serialization: dapp.request(method, params) applies libauth stringify to params internally and parseExtendedJsones the response — pass raw objects (Uint8Array/bigint); do not pre-apply toWcParams (that is WalletConnect-only).
  • Co-sign is wallet-orchestrated, not dApp-pass-through. Reading the wallet's CashRPC_V0.signTransaction handler (lines 995–1112 of the installed dist):
    1. Inputs/outputs are either template-scoped (uses the BchNamespace template — a libauth WalletTemplate the 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).
    2. 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.
    3. The wallet runs a libauth VM verify on 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 (tote bet(), 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's bch_signTransaction (validated 0057, true pass-through) remains the path for those flows. Cashonize speaks both, so users never see the routing decision.
  • Bundle patch (cashconnect@0.0.25): the bundle does import Client from '@walletconnect/sign-client'; sign-client's ESM build sets default to the package namespace (object), not the SignClient class — so under ESM Client.init is undefined. patches/apply-cashconnect-fix.mjs rewrites the bundle to import { SignClient as Client } …. Idempotent; wired as postinstall.
  • Project ID (WC_PROJECT_ID=c4ac…3de0) validated against the WC2 relay — dApp initializes, dapp.start() succeeds, connect() produces a cc: 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.mjs may pair with Paytaca directly (try npm run connect:wc against Paytaca). If (a), get its dApp SDK + the connect/sign API, then add an adapter mirroring cashconnect.mjs.
  • The WalletSession interface (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:bchtest but 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.