@@ -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 = {
@@ -49,9 +50,98 @@ export type ParsedTransaction = {
4950 virtualSize : number ;
5051} ;
5152
53+ export type CreateEmptyOptions = {
54+ /** Transaction version (default: 2) */
55+ version ?: number ;
56+ /** Lock time (default: 0) */
57+ lockTime ?: number ;
58+ } ;
59+
60+ export type AddInputOptions = {
61+ /** Previous transaction ID (hex string) */
62+ txid : string ;
63+ /** Output index being spent */
64+ vout : number ;
65+ /** Value in satoshis (for witness_utxo) */
66+ value : bigint ;
67+ /** Sequence number (default: 0xFFFFFFFE for RBF) */
68+ sequence ?: number ;
69+ /** Full previous transaction (for non-segwit strict compliance) */
70+ prevTx ?: Uint8Array ;
71+ } ;
72+
73+ export type AddOutputOptions = {
74+ /** Output script (scriptPubKey) */
75+ script : Uint8Array ;
76+ /** Value in satoshis */
77+ value : bigint ;
78+ } ;
79+
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+
52107export class BitGoPsbt {
53108 private constructor ( private wasm : WasmBitGoPsbt ) { }
54109
110+ /**
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.
115+ *
116+ * @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)
118+ * @param options - Optional transaction parameters (version, lockTime)
119+ * @returns A new empty BitGoPsbt instance
120+ *
121+ * @example
122+ * ```typescript
123+ * // Create empty PSBT with wallet keys
124+ * const psbt = BitGoPsbt.createEmpty("bitcoin", walletKeys);
125+ *
126+ * // Create with custom version and lockTime
127+ * const psbt = BitGoPsbt.createEmpty("bitcoin", walletKeys, { version: 1, lockTime: 500000 });
128+ * ```
129+ */
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+ ) ;
142+ return new BitGoPsbt ( wasm ) ;
143+ }
144+
55145 /**
56146 * Deserialize a PSBT from bytes
57147 * @param bytes - The PSBT bytes
@@ -63,6 +153,178 @@ export class BitGoPsbt {
63153 return new BitGoPsbt ( wasm ) ;
64154 }
65155
156+ /**
157+ * Add an input to the PSBT
158+ *
159+ * This adds a transaction input and corresponding PSBT input metadata.
160+ * The witness_utxo is automatically populated for modern signing compatibility.
161+ *
162+ * @param options - Input options (txid, vout, value, sequence)
163+ * @param script - Output script of the UTXO being spent
164+ * @returns The index of the newly added input
165+ *
166+ * @example
167+ * ```typescript
168+ * const inputIndex = psbt.addInput({
169+ * txid: "abc123...",
170+ * vout: 0,
171+ * value: 100000n,
172+ * }, outputScript);
173+ * ```
174+ */
175+ addInput ( options : AddInputOptions , script : Uint8Array ) : number {
176+ return this . wasm . add_input (
177+ options . txid ,
178+ options . vout ,
179+ options . value ,
180+ script ,
181+ options . sequence ,
182+ options . prevTx ,
183+ ) ;
184+ }
185+
186+ /**
187+ * Add an output to the PSBT
188+ *
189+ * @param options - Output options (script, value)
190+ * @returns The index of the newly added output
191+ *
192+ * @example
193+ * ```typescript
194+ * const outputIndex = psbt.addOutput({
195+ * script: outputScript,
196+ * value: 50000n,
197+ * });
198+ * ```
199+ */
200+ addOutput ( options : AddOutputOptions ) : number {
201+ return this . wasm . add_output ( options . script , options . value ) ;
202+ }
203+
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+
66328 /**
67329 * Get the unsigned transaction ID
68330 * @returns The unsigned transaction ID
@@ -71,6 +333,22 @@ export class BitGoPsbt {
71333 return this . wasm . unsigned_txid ( ) ;
72334 }
73335
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+
74352 /**
75353 * Parse transaction with wallet keys to identify wallet inputs/outputs
76354 * @param walletKeys - The wallet keys to use for identification
0 commit comments