1- import { Psbt , bitgo } from '@bitgo/utxo-lib' ;
1+ import { Psbt , bitgo , networks } from '@bitgo/utxo-lib' ;
2+ import { toXOnlyPublicKey } from '@bitgo/utxo-lib/dist/src/bitgo/outputScripts' ;
23
3- import { addBip322ProofMessage , isTaprootChain } from './utils' ;
4+ import { addBip322ProofMessage } from './utils' ;
45import { BIP322_TAG , buildToSpendTransaction } from './toSpend' ;
56
67export type AddressDetails = {
@@ -14,9 +15,9 @@ export const MAX_NUM_BIP322_INPUTS = 200;
1415 * Create the base PSBT for the to_sign transaction for BIP322 signing.
1516 * There will be ever 1 output.
1617 */
17- export function createBaseToSignPsbt ( rootWalletKeys ?: bitgo . RootWalletKeys ) : Psbt {
18+ export function createBaseToSignPsbt ( rootWalletKeys ?: bitgo . RootWalletKeys ) : bitgo . UtxoPsbt {
1819 // Create PSBT object for constructing the transaction
19- const psbt = new Psbt ( ) ;
20+ const psbt = bitgo . createPsbtForNetwork ( { network : networks . bitcoin } ) ;
2021 // Set default value for nVersion and nLockTime
2122 psbt . setVersion ( 0 ) ; // nVersion = 0
2223 psbt . setLocktime ( 0 ) ; // nLockTime = 0
@@ -76,29 +77,82 @@ export function addBip322Input(psbt: Psbt, message: string, addressDetails: Addr
7677}
7778
7879export function addBip322InputWithChainAndIndex (
79- psbt : Psbt ,
80+ psbt : bitgo . UtxoPsbt ,
8081 message : string ,
8182 rootWalletKeys : bitgo . RootWalletKeys ,
82- chain : bitgo . ChainCode ,
83- index : number
84- ) : Psbt {
85- if ( isTaprootChain ( chain ) ) {
86- throw new Error ( 'BIP322 is not supported for Taproot script types.' ) ;
87- }
88- const walletKeys = rootWalletKeys . deriveForChainAndIndex ( chain , index ) ;
89- const output = bitgo . outputScripts . createOutputScript2of3 ( walletKeys . publicKeys , bitgo . scriptTypeForChain ( chain ) ) ;
83+ scriptId : bitgo . ScriptId
84+ ) : void {
85+ const scriptType = bitgo . scriptTypeForChain ( scriptId . chain ) ;
86+ const walletKeys = rootWalletKeys . deriveForChainAndIndex ( scriptId . chain , scriptId . index ) ;
87+ const output = bitgo . outputScripts . createOutputScript2of3 (
88+ walletKeys . publicKeys ,
89+ bitgo . scriptTypeForChain ( scriptId . chain )
90+ ) ;
9091
91- addBip322Input ( psbt , message , {
92+ addBip322Input ( psbt as Psbt , message , {
9293 scriptPubKey : output . scriptPubKey ,
9394 redeemScript : output . redeemScript ,
9495 witnessScript : output . witnessScript ,
9596 } ) ;
9697
9798 const inputIndex = psbt . data . inputs . length - 1 ;
98- psbt . updateInput (
99- inputIndex ,
100- bitgo . getPsbtBip32DerivationOutputUpdate ( rootWalletKeys , walletKeys , bitgo . scriptTypeForChain ( chain ) )
101- ) ;
10299
103- return psbt ;
100+ // When adding the taproot metadata, we assume that we are NOT using the backup path
101+ // For script type p2tr, it means that we are using signer and bitgo keys when creating the tap tree
102+ // spending paths. For p2trMusig2, it means that we are using the taproot key path spending
103+ const keyNames = [ 'user' , 'bitgo' ] as bitgo . KeyName [ ] ;
104+ if ( scriptType === 'p2tr' ) {
105+ const { controlBlock, witnessScript, leafVersion, leafHash } = bitgo . outputScripts . createSpendScriptP2tr (
106+ walletKeys . publicKeys ,
107+ [ walletKeys . user . publicKey , walletKeys . bitgo . publicKey ]
108+ ) ;
109+ psbt . updateInput ( inputIndex , {
110+ tapLeafScript : [ { controlBlock, script : witnessScript , leafVersion } ] ,
111+ } ) ;
112+
113+ psbt . updateInput ( inputIndex , {
114+ tapBip32Derivation : keyNames . map ( ( key ) => ( {
115+ leafHashes : [ leafHash ] ,
116+ pubkey : toXOnlyPublicKey ( walletKeys [ key ] . publicKey ) ,
117+ path : rootWalletKeys . getDerivationPath ( rootWalletKeys [ key ] , scriptId . chain , scriptId . index ) ,
118+ masterFingerprint : rootWalletKeys [ key ] . fingerprint ,
119+ } ) ) ,
120+ } ) ;
121+ } else if ( scriptType === 'p2trMusig2' ) {
122+ const {
123+ internalPubkey : tapInternalKey ,
124+ outputPubkey : tapOutputKey ,
125+ taptreeRoot,
126+ } = bitgo . outputScripts . createKeyPathP2trMusig2 ( walletKeys . publicKeys ) ;
127+
128+ const participantsKeyValData = bitgo . musig2 . encodePsbtMusig2Participants ( {
129+ tapOutputKey,
130+ tapInternalKey,
131+ participantPubKeys : [ walletKeys . user . publicKey , walletKeys . bitgo . publicKey ] ,
132+ } ) ;
133+ bitgo . addProprietaryKeyValuesFromUnknownKeyValues ( psbt , 'input' , inputIndex , participantsKeyValData ) ;
134+
135+ psbt . updateInput ( inputIndex , {
136+ tapInternalKey : tapInternalKey ,
137+ } ) ;
138+
139+ psbt . updateInput ( inputIndex , {
140+ tapMerkleRoot : taptreeRoot ,
141+ } ) ;
142+
143+ psbt . updateInput ( inputIndex , {
144+ tapBip32Derivation : keyNames . map ( ( key ) => ( {
145+ leafHashes : [ ] ,
146+ pubkey : toXOnlyPublicKey ( walletKeys [ key ] . publicKey ) ,
147+ path : rootWalletKeys . getDerivationPath ( rootWalletKeys [ key ] , scriptId . chain , scriptId . index ) ,
148+ masterFingerprint : rootWalletKeys [ key ] . fingerprint ,
149+ } ) ) ,
150+ } ) ;
151+ } else {
152+ // Add bip32 derivation information for the input
153+ psbt . updateInput (
154+ inputIndex ,
155+ bitgo . getPsbtBip32DerivationOutputUpdate ( rootWalletKeys , walletKeys , bitgo . scriptTypeForChain ( scriptId . chain ) )
156+ ) ;
157+ }
104158}
0 commit comments