@@ -31,6 +31,7 @@ export type ParsedInput = {
3131 value : bigint ;
3232 scriptId : ScriptId | null ;
3333 scriptType : InputScriptType ;
34+ sequence : number ;
3435} ;
3536
3637export type ParsedOutput = {
@@ -63,10 +64,10 @@ export type AddInputOptions = {
6364 vout : number ;
6465 /** Value in satoshis (for witness_utxo) */
6566 value : bigint ;
66- /** Output script of UTXO being spent */
67- script : Uint8Array ;
6867 /** Sequence number (default: 0xFFFFFFFE for RBF) */
6968 sequence ?: number ;
69+ /** Full previous transaction (for non-segwit strict compliance) */
70+ prevTx ?: Uint8Array ;
7071} ;
7172
7273export type AddOutputOptions = {
@@ -76,27 +77,68 @@ export type AddOutputOptions = {
7677 value : bigint ;
7778} ;
7879
80+ /** Key identifier for signing ("user", "backup", or "bitgo") */
81+ export type SignerKey = "user" | "backup" | "bitgo" ;
82+
83+ /** Specifies signer and cosigner for Taproot inputs */
84+ export type SignPath = {
85+ /** Key that will sign */
86+ signer : SignerKey ;
87+ /** Key that will co-sign */
88+ cosigner : SignerKey ;
89+ } ;
90+
91+ export type AddWalletInputOptions = {
92+ /** Script location in wallet (chain + index) */
93+ scriptId : ScriptId ;
94+ /** Sign path - required for p2tr/p2trMusig2 (chains 30-41) */
95+ signPath ?: SignPath ;
96+ } ;
97+
98+ export type AddWalletOutputOptions = {
99+ /** Chain code (0/1=p2sh, 10/11=p2shP2wsh, 20/21=p2wsh, 30/31=p2tr, 40/41=p2trMusig2) */
100+ chain : number ;
101+ /** Derivation index */
102+ index : number ;
103+ /** Value in satoshis */
104+ value : bigint ;
105+ } ;
106+
79107export class BitGoPsbt {
80108 private constructor ( private wasm : WasmBitGoPsbt ) { }
81109
82110 /**
83- * Create an empty PSBT for the given network
111+ * Create an empty PSBT for the given network with wallet keys
112+ *
113+ * The wallet keys are used to set global xpubs in the PSBT, which identifies
114+ * the keys that will be used for signing.
84115 *
85116 * @param network - Network name (utxolib name like "bitcoin" or coin name like "btc")
117+ * @param walletKeys - The wallet's root keys (sets global xpubs in the PSBT)
86118 * @param options - Optional transaction parameters (version, lockTime)
87119 * @returns A new empty BitGoPsbt instance
88120 *
89121 * @example
90122 * ```typescript
91- * // Create empty PSBT with defaults (version 2, lockTime 0)
92- * const psbt = BitGoPsbt.createEmpty("bitcoin");
123+ * // Create empty PSBT with wallet keys
124+ * const psbt = BitGoPsbt.createEmpty("bitcoin", walletKeys );
93125 *
94126 * // Create with custom version and lockTime
95- * const psbt = BitGoPsbt.createEmpty("bitcoin", { version: 1, lockTime: 500000 });
127+ * const psbt = BitGoPsbt.createEmpty("bitcoin", walletKeys, { version: 1, lockTime: 500000 });
96128 * ```
97129 */
98- static createEmpty ( network : NetworkName , options ?: CreateEmptyOptions ) : BitGoPsbt {
99- const wasm = WasmBitGoPsbt . create_empty ( network , options ?. version , options ?. lockTime ) ;
130+ static createEmpty (
131+ network : NetworkName ,
132+ walletKeys : WalletKeysArg ,
133+ options ?: CreateEmptyOptions ,
134+ ) : BitGoPsbt {
135+ const keys = RootWalletKeys . from ( walletKeys ) ;
136+ const wasm = WasmBitGoPsbt . create_empty (
137+ network ,
138+ keys . wasm ,
139+ options ?. version ,
140+ options ?. lockTime ,
141+ ) ;
100142 return new BitGoPsbt ( wasm ) ;
101143 }
102144
@@ -117,7 +159,8 @@ export class BitGoPsbt {
117159 * This adds a transaction input and corresponding PSBT input metadata.
118160 * The witness_utxo is automatically populated for modern signing compatibility.
119161 *
120- * @param options - Input options (txid, vout, value, script, sequence)
162+ * @param options - Input options (txid, vout, value, sequence)
163+ * @param script - Output script of the UTXO being spent
121164 * @returns The index of the newly added input
122165 *
123166 * @example
@@ -126,17 +169,17 @@ export class BitGoPsbt {
126169 * txid: "abc123...",
127170 * vout: 0,
128171 * value: 100000n,
129- * script: outputScript,
130- * });
172+ * }, outputScript);
131173 * ```
132174 */
133- addInput ( options : AddInputOptions ) : number {
175+ addInput ( options : AddInputOptions , script : Uint8Array ) : number {
134176 return this . wasm . add_input (
135177 options . txid ,
136178 options . vout ,
137179 options . value ,
138- options . script ,
180+ script ,
139181 options . sequence ,
182+ options . prevTx ,
140183 ) ;
141184 }
142185
@@ -158,6 +201,130 @@ export class BitGoPsbt {
158201 return this . wasm . add_output ( options . script , options . value ) ;
159202 }
160203
204+ /**
205+ * Add a wallet input with full PSBT metadata
206+ *
207+ * This is a higher-level method that adds an input and populates all required
208+ * PSBT fields (scripts, derivation info, etc.) based on the wallet's chain type.
209+ *
210+ * For p2sh/p2shP2wsh/p2wsh: Sets bip32Derivation, witnessScript, redeemScript (signPath not needed)
211+ * For p2tr/p2trMusig2 script path: Sets tapLeafScript, tapBip32Derivation (signPath required)
212+ * For p2trMusig2 key path: Sets tapInternalKey, tapMerkleRoot, tapBip32Derivation, musig2 participants (signPath required)
213+ *
214+ * @param inputOptions - Common input options (txid, vout, value, sequence)
215+ * @param walletKeys - The wallet's root keys
216+ * @param walletOptions - Wallet-specific options (scriptId, signPath, prevTx)
217+ * @returns The index of the newly added input
218+ *
219+ * @example
220+ * ```typescript
221+ * // Add a p2shP2wsh input (signPath not needed)
222+ * const inputIndex = psbt.addWalletInput(
223+ * { txid: "abc123...", vout: 0, value: 100000n },
224+ * walletKeys,
225+ * { scriptId: { chain: 10, index: 0 } }, // p2shP2wsh external
226+ * );
227+ *
228+ * // Add a p2trMusig2 key path input (signPath required)
229+ * const inputIndex = psbt.addWalletInput(
230+ * { txid: "def456...", vout: 1, value: 50000n },
231+ * walletKeys,
232+ * { scriptId: { chain: 40, index: 5 }, signPath: { signer: "user", cosigner: "bitgo" } },
233+ * );
234+ *
235+ * // Add p2trMusig2 with backup key (script path spend)
236+ * const inputIndex = psbt.addWalletInput(
237+ * { txid: "ghi789...", vout: 0, value: 75000n },
238+ * walletKeys,
239+ * { scriptId: { chain: 40, index: 3 }, signPath: { signer: "user", cosigner: "backup" } },
240+ * );
241+ * ```
242+ */
243+ addWalletInput (
244+ inputOptions : AddInputOptions ,
245+ walletKeys : WalletKeysArg ,
246+ walletOptions : AddWalletInputOptions ,
247+ ) : number {
248+ const keys = RootWalletKeys . from ( walletKeys ) ;
249+ return this . wasm . add_wallet_input (
250+ inputOptions . txid ,
251+ inputOptions . vout ,
252+ inputOptions . value ,
253+ keys . wasm ,
254+ walletOptions . scriptId . chain ,
255+ walletOptions . scriptId . index ,
256+ walletOptions . signPath ?. signer ,
257+ walletOptions . signPath ?. cosigner ,
258+ inputOptions . sequence ,
259+ inputOptions . prevTx ,
260+ ) ;
261+ }
262+
263+ /**
264+ * Add a wallet output with full PSBT metadata
265+ *
266+ * This creates a verifiable wallet output (typically for change) with all required
267+ * PSBT fields (scripts, derivation info) based on the wallet's chain type.
268+ *
269+ * For p2sh/p2shP2wsh/p2wsh: Sets bip32Derivation, witnessScript, redeemScript
270+ * For p2tr/p2trMusig2: Sets tapInternalKey, tapBip32Derivation
271+ *
272+ * @param walletKeys - The wallet's root keys
273+ * @param options - Output options including chain, index, and value
274+ * @returns The index of the newly added output
275+ *
276+ * @example
277+ * ```typescript
278+ * // Add a p2shP2wsh change output
279+ * const outputIndex = psbt.addWalletOutput(walletKeys, {
280+ * chain: 11, // p2shP2wsh internal (change)
281+ * index: 0,
282+ * value: 50000n,
283+ * });
284+ *
285+ * // Add a p2trMusig2 change output
286+ * const outputIndex = psbt.addWalletOutput(walletKeys, {
287+ * chain: 41, // p2trMusig2 internal (change)
288+ * index: 5,
289+ * value: 25000n,
290+ * });
291+ * ```
292+ */
293+ addWalletOutput ( walletKeys : WalletKeysArg , options : AddWalletOutputOptions ) : number {
294+ const keys = RootWalletKeys . from ( walletKeys ) ;
295+ return this . wasm . add_wallet_output ( options . chain , options . index , options . value , keys . wasm ) ;
296+ }
297+
298+ /**
299+ * Add a replay protection input to the PSBT
300+ *
301+ * Replay protection inputs are P2SH-P2PK inputs used on forked networks to prevent
302+ * transaction replay attacks. They use a simple pubkey script without wallet derivation.
303+ *
304+ * @param inputOptions - Common input options (txid, vout, value, sequence)
305+ * @param key - ECPair containing the public key for the replay protection input
306+ * @returns The index of the newly added input
307+ *
308+ * @example
309+ * ```typescript
310+ * // Add a replay protection input using ECPair
311+ * const inputIndex = psbt.addReplayProtectionInput(
312+ * { txid: "abc123...", vout: 0, value: 1000n },
313+ * replayProtectionKey,
314+ * );
315+ * ```
316+ */
317+ addReplayProtectionInput ( inputOptions : AddInputOptions , key : ECPairArg ) : number {
318+ const ecpair = ECPair . from ( key ) ;
319+ return this . wasm . add_replay_protection_input (
320+ ecpair . wasm ,
321+ inputOptions . txid ,
322+ inputOptions . vout ,
323+ inputOptions . value ,
324+ inputOptions . sequence ,
325+ ) ;
326+ }
327+
161328 /**
162329 * Get the unsigned transaction ID
163330 * @returns The unsigned transaction ID
@@ -166,6 +333,22 @@ export class BitGoPsbt {
166333 return this . wasm . unsigned_txid ( ) ;
167334 }
168335
336+ /**
337+ * Get the transaction version
338+ * @returns The transaction version number
339+ */
340+ get version ( ) : number {
341+ return this . wasm . version ( ) ;
342+ }
343+
344+ /**
345+ * Get the transaction lock time
346+ * @returns The transaction lock time
347+ */
348+ get lockTime ( ) : number {
349+ return this . wasm . lock_time ( ) ;
350+ }
351+
169352 /**
170353 * Parse transaction with wallet keys to identify wallet inputs/outputs
171354 * @param walletKeys - The wallet keys to use for identification
0 commit comments