feat: return shieldedAddresses from /multisigWallet - #34
Conversation
Consumers of a helper-generated multisig wallet had to derive the shielded scan/spend pairs live, because only /simpleWallet returned them. wallet-lib derives those keys whenever a wallet starts from a root key, with no multisig exemption, so the cost was paid on every multisig wallet start whether or not the test touched a shielded feature — measured at roughly +7.6s per wallet. The pairs are per participant, derived from that participant's own seed. Unlike `addresses`, they are not shared: the P2SH addresses come from the sorted pubkey set, while shielded keys come from the root key and the redeem script plays no part. Note this uses wallet-lib's compliant deriveChild, matching its shielded branch — not the non-compliant derivation its legacy multisig path uses. Tests assert at the wire as well as the service layer: the field is optional on MultisigWallet, so a handler projecting a subset of fields would otherwise drop it with a green typecheck. Also corrects the handler's documented cost model, which claimed a large multisig only costs the caller. The handler is synchronous, so it blocks every other client; that and the 16-participant ceiling are tracked in #32. Closes #31 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthrough
ChangesMultisig shielded addresses
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant multisigWallet
participant generateMultisigWallet
participant generateShieldedAddresses
Client->>multisigWallet: request multisig wallet
multisigWallet->>generateMultisigWallet: generate participants
generateMultisigWallet->>generateShieldedAddresses: derive pairs from each participant seed
generateShieldedAddresses-->>generateMultisigWallet: participant-specific shielded pairs
generateMultisigWallet-->>Client: shared P2SH addresses and shielded pairs
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR extends the /multisigWallet API response so each returned multisig wallet entry includes shieldedAddresses, aligning it with /simpleWallet and removing the need for consumers to derive shielded scan/spend pairs at wallet startup time.
Changes:
- Add optional
shieldedAddressesto theMultisigWallettype and populate it ingenerateMultisigWalletper participant seed. - Update
/multisigWallethandler documentation to reflect the synchronous (event-loop blocking) cost model. - Document the new field and its per-participant semantics in
README.md, and add wire-level + service-level tests asserting the new behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/wallet.service.ts | Adds shieldedAddresses to MultisigWallet and populates it per participant in generateMultisigWallet. |
| src/routes.ts | Updates the /multisigWallet handler comment to accurately describe synchronous cost/limits. |
| README.md | Documents shieldedAddresses for /multisigWallet, including why pairs are per participant. |
| tests/src/wallet-service.test.ts | Adds unit tests ensuring multisig shielded pairs are populated and per-seed. |
| tests/src/routes.test.ts | Adds wire-level assertions that /multisigWallet includes shieldedAddresses in the response. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
The rules for generating valid addresses on the multisig wallet are not closed yet. This PR will stay suspended until the actual definitions arrive. |
Note
💤 The rules for generating valid addresses on the multisig wallet are not closed yet. This PR will stay suspended until the actual definitions arrive.
Adds
shieldedAddressesto every entry of the/multisigWalletresponse, matching what/simpleWallethas returned since #22. Consumers of a helper-generated multisig wallet previously had to derive the shielded scan/spend pairs live, at roughly +7.6s per wallet.This is not a cost a consumer can opt out of. wallet-lib derives scan/spend keys whenever a wallet starts from a root key, with no multisig exemption, so a multisig wallet paid it whether or not the test touched a shielded feature.
How it works
generateMultisigWalletnow populatesshieldedAddressesfrom each participant's own seed, andMultisigWalletgains the field as optional, mirroringSimpleWallet./multisigWalletand why the pairs are per participant.The pairs are per participant, unlike
addresses. The P2SH addresses are shared because they derive from the sorted pubkey set; shielded keys derive from each participant's root key and the redeem script plays no part. Note this uses wallet-lib's compliantderiveChild, matching its shielded branch — not the non-compliant derivation its legacy multisig path uses.Behavioral change
Additive. The field is optional in the response type, so consumers pinned to a wallet-lib without shielded support are unaffected; they can prefer
entry.shieldedAddressesand fall back to whatever they use today.Acceptance criteria
/multisigWallet'swalletsarray carriesshieldedAddresseswith one pair per BIP32 index, asserted at the wire and not only at the service layer.addressesbut nevershieldedAddresses.bun run checkpasses.Closes #31
Summary by CodeRabbit