@@ -19,7 +19,7 @@ export type PsbtBackend = 'wasm-utxo' | 'utxolib';
1919/**
2020 * Check if a chain code is for a taproot script type
2121 */
22- function isTaprootChain ( chain : ChainCode ) : boolean {
22+ export function isTaprootChain ( chain : ChainCode ) : boolean {
2323 return (
2424 ( chainCodesP2tr as readonly number [ ] ) . includes ( chain ) || ( chainCodesP2trMusig2 as readonly number [ ] ) . includes ( chain )
2525 ) ;
@@ -28,7 +28,7 @@ function isTaprootChain(chain: ChainCode): boolean {
2828/**
2929 * Convert utxolib Network to wasm-utxo network name
3030 */
31- function toNetworkName ( network : utxolib . Network ) : utxolibCompat . UtxolibName {
31+ export function toNetworkName ( network : utxolib . Network ) : utxolibCompat . UtxolibName {
3232 const networkName = utxolib . getNetworkName ( network ) ;
3333 if ( ! networkName ) {
3434 throw new Error ( `Invalid network` ) ;
@@ -129,32 +129,53 @@ const ZCASH_DEFAULT_BLOCK_HEIGHTS: Record<string, number> = {
129129} ;
130130
131131/**
132- * Create a backup key recovery PSBT using wasm-utxo
132+ * Options for creating an empty wasm-utxo PSBT
133133 */
134- function createBackupKeyRecoveryPsbtWasm (
134+ export interface CreateEmptyWasmPsbtOptions {
135+ /** Block height for Zcash networks (required to determine consensus branch ID) */
136+ blockHeight ?: number ;
137+ }
138+
139+ /**
140+ * Create an empty wasm-utxo BitGoPsbt for a given network.
141+ * Handles Zcash networks specially by using ZcashBitGoPsbt.
142+ *
143+ * @param network - The network for the PSBT
144+ * @param rootWalletKeys - The wallet keys
145+ * @param options - Optional settings (e.g., blockHeight for Zcash)
146+ * @returns A wasm-utxo BitGoPsbt instance
147+ */
148+ export function createEmptyWasmPsbt (
135149 network : utxolib . Network ,
136150 rootWalletKeys : RootWalletKeys ,
137- unspents : WalletUnspent < bigint > [ ] ,
138- options : CreateBackupKeyRecoveryPsbtOptions
139- ) : utxolib . bitgo . UtxoPsbt {
140- const { feeRateSatVB, recoveryDestination, keyRecoveryServiceFee, keyRecoveryServiceFeeAddress } = options ;
141-
151+ options ?: CreateEmptyWasmPsbtOptions
152+ ) : fixedScriptWallet . BitGoPsbt {
142153 const networkName = toNetworkName ( network ) ;
143154
144- // Create PSBT with wasm-utxo and add wallet inputs
145- // wasm-utxo's RootWalletKeys.from() accepts utxolib's RootWalletKeys format (IWalletKeys interface)
146- let wasmPsbt : fixedScriptWallet . BitGoPsbt ;
147-
148155 if ( isZcashNetwork ( networkName ) ) {
149156 // For Zcash, use ZcashBitGoPsbt which requires block height to determine consensus branch ID
150- const blockHeight = options . blockHeight ?? ZCASH_DEFAULT_BLOCK_HEIGHTS [ networkName ] ;
151- wasmPsbt = fixedScriptWallet . ZcashBitGoPsbt . createEmpty ( networkName as 'zcash' | 'zcashTest' , rootWalletKeys , {
157+ const blockHeight = options ? .blockHeight ?? ZCASH_DEFAULT_BLOCK_HEIGHTS [ networkName ] ;
158+ return fixedScriptWallet . ZcashBitGoPsbt . createEmpty ( networkName as 'zcash' | 'zcashTest' , rootWalletKeys , {
152159 blockHeight,
153160 } ) ;
154- } else {
155- wasmPsbt = fixedScriptWallet . BitGoPsbt . createEmpty ( networkName , rootWalletKeys ) ;
156161 }
157162
163+ return fixedScriptWallet . BitGoPsbt . createEmpty ( networkName , rootWalletKeys ) ;
164+ }
165+
166+ /**
167+ * Add wallet inputs from unspents to a wasm-utxo BitGoPsbt.
168+ * Handles taproot inputs by setting the appropriate signPath.
169+ *
170+ * @param wasmPsbt - The wasm-utxo BitGoPsbt to add inputs to
171+ * @param unspents - The wallet unspents to add as inputs
172+ * @param rootWalletKeys - The wallet keys
173+ */
174+ export function addWalletInputsToWasmPsbt (
175+ wasmPsbt : fixedScriptWallet . BitGoPsbt ,
176+ unspents : WalletUnspent < bigint > [ ] ,
177+ rootWalletKeys : RootWalletKeys
178+ ) : void {
158179 unspents . forEach ( ( unspent ) => {
159180 const { txid, vout } = utxolib . bitgo . parseOutputId ( unspent . id ) ;
160181 const signPath : fixedScriptWallet . SignPath | undefined = isTaprootChain ( unspent . chain )
@@ -178,11 +199,59 @@ function createBackupKeyRecoveryPsbtWasm(
178199 }
179200 ) ;
180201 } ) ;
202+ }
181203
182- // Convert wasm-utxo PSBT to utxolib PSBT for dimension calculation and output addition
183- const psbt = utxolib . bitgo . createPsbtFromBuffer ( Buffer . from ( wasmPsbt . serialize ( ) ) , network ) ;
204+ /**
205+ * Add an output to a wasm-utxo BitGoPsbt.
206+ *
207+ * @param wasmPsbt - The wasm-utxo BitGoPsbt to add the output to
208+ * @param address - The destination address
209+ * @param value - The output value in satoshis
210+ * @param network - The network (used to convert address to script)
211+ * @returns The output index
212+ */
213+ export function addOutputToWasmPsbt (
214+ wasmPsbt : fixedScriptWallet . BitGoPsbt ,
215+ address : string ,
216+ value : bigint ,
217+ network : utxolib . Network
218+ ) : number {
219+ const script = utxolib . address . toOutputScript ( address , network ) ;
220+ return wasmPsbt . addOutput ( { script : new Uint8Array ( script ) , value } ) ;
221+ }
184222
185- let dimensions = Dimensions . fromPsbt ( psbt ) . plus (
223+ /**
224+ * Convert a wasm-utxo BitGoPsbt to a utxolib UtxoPsbt.
225+ *
226+ * @param wasmPsbt - The wasm-utxo BitGoPsbt to convert
227+ * @param network - The network
228+ * @returns A utxolib UtxoPsbt
229+ */
230+ export function wasmPsbtToUtxolibPsbt (
231+ wasmPsbt : fixedScriptWallet . BitGoPsbt ,
232+ network : utxolib . Network
233+ ) : utxolib . bitgo . UtxoPsbt {
234+ return utxolib . bitgo . createPsbtFromBuffer ( Buffer . from ( wasmPsbt . serialize ( ) ) , network ) ;
235+ }
236+
237+ /**
238+ * Create a backup key recovery PSBT using wasm-utxo
239+ */
240+ function createBackupKeyRecoveryPsbtWasm (
241+ network : utxolib . Network ,
242+ rootWalletKeys : RootWalletKeys ,
243+ unspents : WalletUnspent < bigint > [ ] ,
244+ options : CreateBackupKeyRecoveryPsbtOptions
245+ ) : utxolib . bitgo . UtxoPsbt {
246+ const { feeRateSatVB, recoveryDestination, keyRecoveryServiceFee, keyRecoveryServiceFeeAddress } = options ;
247+
248+ // Create PSBT with wasm-utxo and add wallet inputs using shared utilities
249+ const wasmPsbt = createEmptyWasmPsbt ( network , rootWalletKeys , { blockHeight : options . blockHeight } ) ;
250+ addWalletInputsToWasmPsbt ( wasmPsbt , unspents , rootWalletKeys ) ;
251+
252+ // Convert to utxolib PSBT temporarily for dimension calculation
253+ const tempPsbt = wasmPsbtToUtxolibPsbt ( wasmPsbt , network ) ;
254+ let dimensions = Dimensions . fromPsbt ( tempPsbt ) . plus (
186255 Dimensions . fromOutput ( { script : utxolib . address . toOutputScript ( recoveryDestination , network ) } )
187256 ) ;
188257
@@ -202,16 +271,15 @@ function createBackupKeyRecoveryPsbtWasm(
202271 throw new InsufficientFundsError ( totalInputAmount , approximateFee , keyRecoveryServiceFee , recoveryAmount ) ;
203272 }
204273
205- psbt . addOutput ( { script : utxolib . address . toOutputScript ( recoveryDestination , network ) , value : recoveryAmount } ) ;
274+ // Add outputs to wasm PSBT
275+ addOutputToWasmPsbt ( wasmPsbt , recoveryDestination , recoveryAmount , network ) ;
206276
207277 if ( keyRecoveryServiceFeeAddress ) {
208- psbt . addOutput ( {
209- script : utxolib . address . toOutputScript ( keyRecoveryServiceFeeAddress , network ) ,
210- value : keyRecoveryServiceFee ,
211- } ) ;
278+ addOutputToWasmPsbt ( wasmPsbt , keyRecoveryServiceFeeAddress , keyRecoveryServiceFee , network ) ;
212279 }
213280
214- return psbt ;
281+ // Convert to utxolib PSBT for signing and return
282+ return wasmPsbtToUtxolibPsbt ( wasmPsbt , network ) ;
215283}
216284
217285/**
0 commit comments