-
Notifications
You must be signed in to change notification settings - Fork 17
feat: HD wallet interface with contract layer and 4-category balance model #275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: next
Are you sure you want to change the base?
Conversation
Introduces SeedIdentity and ReadonlySeedIdentity classes that derive
keys using BIP86 (Taproot) paths. This enables users to transition
to HD wallets while maintaining current single-key behavior.
- SeedIdentity.fromMnemonic() with optional passphrase support
- SeedIdentity.fromSeed() for raw 64-byte seeds
- BIP86 derivation: m/86'/{0|1}'/0'/0/0 (mainnet/testnet)
- Descriptor format: tr([fingerprint/path']xpub.../0/*)
- Strict validation requiring /0/* template for HD compatibility
- JSON serialization with xpub validation on restore
- ReadonlySeedIdentity for watch-only functionality
Add rudimentary HD wallet methods to enable multi-address derivation: SeedIdentity new methods: - deriveSigningDescriptor(index): derive descriptor at specific index - isOurs(descriptor): check if descriptor belongs to this identity - signWithDescriptor(descriptor, requests): batched transaction signing - signMessageWithDescriptor(descriptor, message): message signing at index ReadonlySeedIdentity new methods: - deriveSigningDescriptor(index): derive descriptor at specific index - isOurs(descriptor): check if descriptor belongs to this identity - xOnlyPublicKeyAtIndex(index): get x-only pubkey at index - compressedPublicKeyAtIndex(index): get compressed pubkey at index New types: - SigningRequest: interface for batched signing requests Backwards compatibility maintained - existing methods work at index 0.
- isDescriptor(): checks if string is tr(...) format - normalizeToDescriptor(): wraps hex pubkey as tr(pubkey) - extractPubKey(): extracts pubkey from simple descriptor - parseHDDescriptor(): parses HD descriptor components Enables backwards compatibility for legacy hex pubkeys.
Interface for signing with output descriptors, abstracting HD vs static key implementations.
Wraps existing Identity implementations to provide DescriptorProvider interface with static tr(pubkey) descriptors.
- Change DefaultContractParams to use string descriptors instead of Uint8Array - Add normalizeToDescriptor() for backwards compatibility with hex pubkeys - Update serializeParams/deserializeParams for descriptor format - Update test helpers to use valid secp256k1 public keys - All existing tests pass with the new format
- Add walletDescriptor field to PathContext (preferred over walletPubKey) - Mark walletPubKey as @deprecated with migration note - Update resolveRole to use walletDescriptor with fallback to walletPubKey - Handle descriptor-to-pubkey extraction for role matching
Design document for HD wallet support covering: - Interface hierarchy (IBaseWallet, ISingleKeyWallet, IHDWallet) - Contract-based balance model with boarding as contract type - Handler-based descriptor resolution for multi-path contracts - PathSelection with descriptor for signing
- Add IBaseWallet, ISingleKeyWallet, IHDWallet interfaces - Add HDWallet class with getAddresses(index) and contract-based getBalance() - Add AddressInfo, ContractBalance, HDWalletBalance types - Add WalletDescriptorInfo for multi-path descriptor resolution - Add descriptor field to PathSelection for HD signing - Implement getWalletDescriptors in DefaultContractHandler and VHTLCContractHandler - Add deriveSigningDescriptor to DescriptorProvider interface - Create BoardingContractHandler for unified balance model - Refactor Wallet to implement ISingleKeyWallet (IWallet is now deprecated alias)
- Add ScriptType = "onchain" | "offchain" | "both" to contracts/types.ts - Add scriptType property to ContractHandler interface - DefaultContractHandler: scriptType = "offchain" (VTXOs via indexer) - VHTLCContractHandler: scriptType = "offchain" (VTXOs via indexer) - BoardingContractHandler: scriptType = "onchain" (UTXOs via esplora) This enables ContractWatcher and balance aggregation to know which provider to use for monitoring each contract type.
- Add ContractLayer type ("onchain" | "offchain" | "both") to Contract
- Add layer index to IndexedDB schema for fast contract lookups
- Update ContractFilter and repositories to support layer filtering
- Remove BoardingContractHandler (boarding uses DefaultVtxo with longer timelock)
- Remove scriptType from ContractHandler (moved to Contract.layer)
Balance model now categorizes coins by spend path:
- offchainSpendable: instant Ark transfers (settled/preconfirmed VTXOs)
- batchSpendable: requires batch round (swept, confirmed boarding)
- onchainSpendable: requires unilateral exit (expired batch)
- locked: not spendable yet (unconfirmed, timelocked)
This provides UIs with actionable balance information:
- "Send instantly" → offchainSpendable
- "Available after next batch" → batchSpendable
- "Requires onchain withdrawal" → onchainSpendable
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the
✨ Finishing touches🧪 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 |
Add required `layer` property to all Contract object creations: - arkcontract.ts: both contractFromArkContract functions - request.ts: CreateContract interface - wallet.ts: default contract initialization
Extends ContractWatcher to support watching onchain UTXOs based on the contract's layer field: - layer: "offchain" -> watched via IndexerProvider subscription - layer: "onchain" -> watched via OnchainProvider.watchAddresses - layer: "both" -> watched via both providers New event types: - coin_received: emitted when new onchain coins arrive - coin_confirmed: emitted when pending coins are confirmed This enables unified contract watching where contracts can receive both offchain VTXOs and onchain UTXOs through the same event system.
Tests were failing because mock contracts lacked the layer field, which is now required for subscription filtering.
Summary
This PR adds HD wallet support infrastructure with two major changes:
1. Contract Layer Field
ContractLayertype ("onchain" | "offchain" | "both") toContractinterfacelayerindex to IndexedDB schema for fast contract lookups at wallet startupContractFilterand both repository implementations to support layer filteringBoardingContractHandler(boarding is justDefaultVtxowith longer timelock)scriptTypefromContractHandler(replaced byContract.layer)2. Four-Category Balance Model
Replaced the confusing
spendable/unspendable/recoverablemodel with clear spend-path categories:offchainSpendablebatchSpendableonchainSpendablelockedThis gives wallet UIs actionable information:
offchainSpendablebatchSpendableonchainSpendableTest plan