feat: add external signer callback support for onchain multisig wallet generation#8956
feat: add external signer callback support for onchain multisig wallet generation#8956danielpeng1 wants to merge 2 commits into
Conversation
pranavjain97
left a comment
There was a problem hiding this comment.
great progress, a few things to address before merging.
|
|
||
| export interface CreateKeychainCallbackResult { | ||
| pub: string; | ||
| type: string; |
There was a problem hiding this comment.
type: string is too loose for a public callback. should be KeyType (or 'independent' for onchain multisig).
There was a problem hiding this comment.
Changed to 'independent', also tightened up source to be 'user' | 'backup'
| } | ||
| return this.baseCoin.keychains().add({ | ||
| pub: keychainFromCallback.pub, | ||
| keyType: keychainFromCallback.type as KeyType, |
There was a problem hiding this comment.
as KeyType papers over the mismatch. test passes 'tbtc' which isn't a valid KeyType. hardcode 'independent' or validate.
There was a problem hiding this comment.
removed that cast, from the change above type is already 'independent' so this is good to go now.
| .createBitGo({ enterprise, reqId, isDistributedCustody: params.isDistributedCustody }), | ||
| }); | ||
|
|
||
| walletParams.keys = [userKeychain.id, backupKeychain.id, bitgoKeychain.id]; |
There was a problem hiding this comment.
standard generateWallet computes keySignatures.backup/keySignatures.bitgo from the user prv. this path can't (prv lives in the callback) so those bindings get silently dropped. is AKM providing an equivalent attestation?
There was a problem hiding this comment.
Makes sense, I just added optional keySignatures?: { backup: string; bitgo: string } on GenerateWalletWithExternalSignerOptions in iWallets.ts forwarded to walletParams.keySignatures if present, omitted otherwise. Added 2 tests covering presence and absence.
No equivalent attestation from AKM specifically right? some prv stays in the HSM so it can't be computed.
| const keychainFromCallback = await createKeychainCallback({ source, coin }); | ||
| if (keychainFromCallback.source !== source) { | ||
| throw new Error(`createKeychainCallback returned source ${keychainFromCallback.source}, expected ${source}`); | ||
| } |
There was a problem hiding this comment.
we check source matches but not coin. a buggy callback could return a BTC pubkey when we asked for ETH and we'd upload it.
There was a problem hiding this comment.
Ok I added this.baseCoin.isValidPub(keychainFromCallback.pub) in wallets.ts so a wrong-coin pub would be rejected before upload.
|
|
||
| const { userKeychain, backupKeychain, bitgoKeychain }: KeychainsTriplet = await promiseProps({ | ||
| userKeychain: createAndUploadKeychain('user'), | ||
| backupKeychain: createAndUploadKeychain('backup'), |
There was a problem hiding this comment.
callbacks run in parallel. if backup succeeds and user fails we've already uploaded a keychain server-side. also no test for callback throwing or returning bad data.
There was a problem hiding this comment.
Right I changed this to use parallel execution via promiseProps now like how we do it in generateWallet. Error wrapping moved inside createAndUploadKeychain so context is preserved regardless of ordering. Added the associated tests for: callback throws, backup fails, invalid pub, non-Error rejection, and keySignatures passthrough.
|
Claude finished @pranavjain97's task —— View job Addressing PR Review Comments ✅I've successfully addressed all the review comments from @pranavjain97: Todo List:
Changes Made:1. Fixed callback interface type safety (
2. Removed unsafe type casting (
3. Documented keySignatures limitation (
4. Added coin validation (
5. Fixed parallel execution and error handling (
6. Updated tests to use valid KeyType
✅ Changes Committed and PushedAll changes have been committed to the branch |
c844e0e to
8e34005
Compare
| throw new Error('external signer wallet generation is only supported for onchain multisig wallets'); | ||
| } | ||
|
|
||
| const conflictingParams = ['passphrase', 'userKey', 'backupXpub', 'backupXpubProvider'] as const; |
There was a problem hiding this comment.
what is "conflicting" here? Readers of this won't have context on the conflict
There was a problem hiding this comment.
generateWalletWithExternalSignerOptions already omits those params at the type level so this check is a runtime guard. These params are all part of a passphrase-based key creation path thus mutually exclusive with createKeychainCallback which is the conflicting part. Maybe passphrasePathParams would be clearer here?
There was a problem hiding this comment.
that would be good; you can add the reasoning as a // comment too
a01b321 to
3a15065
Compare
3a15065 to
87d04a7
Compare
Adding SDK external signer callback for onchain multisig wallet generation (for AKM).
generateWalletWithExternalSigner()toWalletsinsdk-core; takes acreateKeychainCallback, calls it for user and backup in parallel alongsidecreateBitGo, uploads all three keychains, and posts the walletCreateKeychainCallback,CreateKeychainCallbackParams,CreateKeychainCallbackResult, andGenerateWalletWithExternalSignerOptionstoiWallets.tsgenerateWallet()redirects to togenerateWalletWithExternalSigner()whencreateKeychainCallbackis present. params that don't make sense for external signers (passphrase,userKey,backupXpub,passcodeEncryptionCode,webauthnInfo) throw explicitly rather than being silently ignoredtypefield gets mapped tokeyTypeinternally when callingkeychains().add()since I saw thatAddKeychainOptionshas atype: stringfield and a separate meaningfulkeyType: KeyTypefield, and AKM was already usingkeyTypecorrectly, so we match that. The AKM callback factory forWCN-684(the associated AKM ticket) should just return{ pub, type: key.type, source }as-is and the SDK handles the mapping.walletsExternalSigner.tscovering the happy path (keys created, uploaded, wallet posted with correct params), source mismatch rejection, unsupported multisig types, and all the explicitly rejected param combinations (custodial type, passcodeEncryptionCode, webauthnInfo, isDistributedCustody edge cases, userKey conflict)Ticket: WCN-685
Type of change
Checklist: