@bitgo/wasm-utxo 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/cjs/js/bip32.d.ts +140 -0
  2. package/dist/cjs/js/bip32.js +177 -0
  3. package/dist/cjs/js/ecpair.d.ts +96 -0
  4. package/dist/cjs/js/ecpair.js +134 -0
  5. package/dist/cjs/js/fixedScriptWallet/BitGoPsbt.d.ts +242 -0
  6. package/dist/cjs/js/fixedScriptWallet/BitGoPsbt.js +274 -0
  7. package/dist/cjs/js/fixedScriptWallet/ReplayProtection.d.ts +58 -0
  8. package/dist/cjs/js/fixedScriptWallet/ReplayProtection.js +89 -0
  9. package/dist/cjs/js/fixedScriptWallet/RootWalletKeys.d.ts +66 -0
  10. package/dist/cjs/js/fixedScriptWallet/RootWalletKeys.js +108 -0
  11. package/dist/cjs/js/fixedScriptWallet/address.d.ts +20 -0
  12. package/dist/cjs/js/fixedScriptWallet/address.js +29 -0
  13. package/dist/cjs/js/fixedScriptWallet/index.d.ts +4 -0
  14. package/dist/cjs/js/fixedScriptWallet/index.js +12 -0
  15. package/dist/cjs/js/index.d.ts +5 -1
  16. package/dist/cjs/js/index.js +11 -2
  17. package/dist/cjs/js/utxolibCompat.d.ts +0 -18
  18. package/dist/cjs/js/wasm/wasm_utxo.d.ts +333 -15
  19. package/dist/cjs/js/wasm/wasm_utxo.js +1311 -201
  20. package/dist/cjs/js/wasm/wasm_utxo_bg.wasm +0 -0
  21. package/dist/cjs/js/wasm/wasm_utxo_bg.wasm.d.ts +64 -15
  22. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  23. package/dist/esm/js/bip32.d.ts +140 -0
  24. package/dist/esm/js/bip32.js +173 -0
  25. package/dist/esm/js/ecpair.d.ts +96 -0
  26. package/dist/esm/js/ecpair.js +130 -0
  27. package/dist/esm/js/fixedScriptWallet/BitGoPsbt.d.ts +242 -0
  28. package/dist/esm/js/fixedScriptWallet/BitGoPsbt.js +270 -0
  29. package/dist/esm/js/fixedScriptWallet/ReplayProtection.d.ts +58 -0
  30. package/dist/esm/js/fixedScriptWallet/ReplayProtection.js +85 -0
  31. package/dist/esm/js/fixedScriptWallet/RootWalletKeys.d.ts +66 -0
  32. package/dist/esm/js/fixedScriptWallet/RootWalletKeys.js +104 -0
  33. package/dist/esm/js/fixedScriptWallet/address.d.ts +20 -0
  34. package/dist/esm/js/fixedScriptWallet/address.js +25 -0
  35. package/dist/esm/js/fixedScriptWallet/index.d.ts +4 -0
  36. package/dist/esm/js/fixedScriptWallet/index.js +4 -0
  37. package/dist/esm/js/index.d.ts +5 -1
  38. package/dist/esm/js/index.js +8 -1
  39. package/dist/esm/js/utxolibCompat.d.ts +0 -18
  40. package/dist/esm/js/wasm/wasm_utxo.d.ts +333 -15
  41. package/dist/esm/js/wasm/wasm_utxo_bg.js +1301 -199
  42. package/dist/esm/js/wasm/wasm_utxo_bg.wasm +0 -0
  43. package/dist/esm/js/wasm/wasm_utxo_bg.wasm.d.ts +64 -15
  44. package/dist/esm/test/bip32.js +242 -0
  45. package/dist/esm/test/ecpair.d.ts +1 -0
  46. package/dist/esm/test/ecpair.js +137 -0
  47. package/dist/esm/test/fixedScript/fixtureUtil.d.ts +12 -2
  48. package/dist/esm/test/fixedScript/fixtureUtil.js +28 -7
  49. package/dist/esm/test/fixedScript/musig2Nonces.d.ts +1 -0
  50. package/dist/esm/test/fixedScript/musig2Nonces.js +77 -0
  51. package/dist/esm/test/fixedScript/parseTransactionWithWalletKeys.js +7 -7
  52. package/dist/esm/test/fixedScript/signAndVerifySignature.d.ts +1 -0
  53. package/dist/esm/test/fixedScript/signAndVerifySignature.js +268 -0
  54. package/dist/esm/test/fixedScript/walletKeys.util.d.ts +12 -0
  55. package/dist/esm/test/fixedScript/walletKeys.util.js +17 -0
  56. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +1 -1
  58. package/dist/cjs/js/fixedScriptWallet.d.ts +0 -146
  59. package/dist/cjs/js/fixedScriptWallet.js +0 -138
  60. package/dist/esm/js/fixedScriptWallet.d.ts +0 -146
  61. package/dist/esm/js/fixedScriptWallet.js +0 -132
  62. package/dist/esm/test/fixedScript/verifySignature.js +0 -141
  63. /package/dist/esm/test/{fixedScript/verifySignature.d.ts → bip32.d.ts} +0 -0
@@ -0,0 +1,242 @@
1
+ import { type WalletKeysArg } from "./RootWalletKeys.js";
2
+ import { type ReplayProtectionArg } from "./ReplayProtection.js";
3
+ import { type BIP32Arg } from "../bip32.js";
4
+ import { type ECPairArg } from "../ecpair.js";
5
+ import type { UtxolibName } from "../utxolibCompat.js";
6
+ import type { CoinName } from "../coinName.js";
7
+ export type NetworkName = UtxolibName | CoinName;
8
+ export type ScriptId = {
9
+ chain: number;
10
+ index: number;
11
+ };
12
+ export type InputScriptType = "p2shP2pk" | "p2sh" | "p2shP2wsh" | "p2wsh" | "p2trLegacy" | "p2trMusig2ScriptPath" | "p2trMusig2KeyPath";
13
+ export type ParsedInput = {
14
+ address: string;
15
+ script: Uint8Array;
16
+ value: bigint;
17
+ scriptId: ScriptId | null;
18
+ scriptType: InputScriptType;
19
+ };
20
+ export type ParsedOutput = {
21
+ address: string | null;
22
+ script: Uint8Array;
23
+ value: bigint;
24
+ scriptId: ScriptId | null;
25
+ };
26
+ export type ParsedTransaction = {
27
+ inputs: ParsedInput[];
28
+ outputs: ParsedOutput[];
29
+ spendAmount: bigint;
30
+ minerFee: bigint;
31
+ virtualSize: number;
32
+ };
33
+ export declare class BitGoPsbt {
34
+ private wasm;
35
+ private constructor();
36
+ /**
37
+ * Deserialize a PSBT from bytes
38
+ * @param bytes - The PSBT bytes
39
+ * @param network - The network to use for deserialization (either utxolib name like "bitcoin" or coin name like "btc")
40
+ * @returns A BitGoPsbt instance
41
+ */
42
+ static fromBytes(bytes: Uint8Array, network: NetworkName): BitGoPsbt;
43
+ /**
44
+ * Get the unsigned transaction ID
45
+ * @returns The unsigned transaction ID
46
+ */
47
+ unsignedTxid(): string;
48
+ /**
49
+ * Parse transaction with wallet keys to identify wallet inputs/outputs
50
+ * @param walletKeys - The wallet keys to use for identification
51
+ * @param replayProtection - Scripts that are allowed as inputs without wallet validation
52
+ * @returns Parsed transaction information
53
+ */
54
+ parseTransactionWithWalletKeys(walletKeys: WalletKeysArg, replayProtection: ReplayProtectionArg): ParsedTransaction;
55
+ /**
56
+ * Parse outputs with wallet keys to identify which outputs belong to a wallet
57
+ * with the given wallet keys.
58
+ *
59
+ * This is useful in cases where we want to identify outputs that belong to a different
60
+ * wallet than the inputs.
61
+ *
62
+ * @param walletKeys - The wallet keys to use for identification
63
+ * @returns Array of parsed outputs
64
+ * @note This method does NOT validate wallet inputs. It only parses outputs.
65
+ */
66
+ parseOutputsWithWalletKeys(walletKeys: WalletKeysArg): ParsedOutput[];
67
+ /**
68
+ * Verify if a valid signature exists for a given key at the specified input index.
69
+ *
70
+ * This method can verify signatures using either:
71
+ * - Extended public key (xpub): Derives the public key using the derivation path from PSBT
72
+ * - ECPair (private key): Extracts the public key and verifies directly
73
+ *
74
+ * When using xpub, it supports:
75
+ * - ECDSA signatures (for legacy/SegWit inputs)
76
+ * - Schnorr signatures (for Taproot script path inputs)
77
+ * - MuSig2 partial signatures (for Taproot keypath MuSig2 inputs)
78
+ *
79
+ * When using ECPair, it supports:
80
+ * - ECDSA signatures (for legacy/SegWit inputs)
81
+ * - Schnorr signatures (for Taproot script path inputs)
82
+ * Note: MuSig2 inputs require xpubs for derivation
83
+ *
84
+ * @param inputIndex - The index of the input to check (0-based)
85
+ * @param key - Either an extended public key (base58 string, BIP32 instance, or WasmBIP32) or an ECPair (private key Buffer, ECPair instance, or WasmECPair)
86
+ * @returns true if a valid signature exists, false if no signature exists
87
+ * @throws Error if input index is out of bounds, key is invalid, or verification fails
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * // Verify wallet input signature with xpub
92
+ * const hasUserSig = psbt.verifySignature(0, userXpub);
93
+ *
94
+ * // Verify signature with ECPair (private key)
95
+ * const ecpair = ECPair.fromPrivateKey(privateKeyBuffer);
96
+ * const hasReplaySig = psbt.verifySignature(1, ecpair);
97
+ *
98
+ * // Or pass private key directly
99
+ * const hasReplaySig2 = psbt.verifySignature(1, privateKeyBuffer);
100
+ * ```
101
+ */
102
+ verifySignature(inputIndex: number, key: BIP32Arg | ECPairArg): boolean;
103
+ /**
104
+ * Sign a single input with a private key
105
+ *
106
+ * This method signs a specific input using the provided key. It accepts either:
107
+ * - An xpriv (BIP32Arg: base58 string, BIP32 instance, or WasmBIP32) for wallet inputs - derives the key and signs
108
+ * - A raw privkey (ECPairArg: Buffer, ECPair instance, or WasmECPair) for replay protection inputs - signs directly
109
+ *
110
+ * This method automatically detects and handles different input types:
111
+ * - For regular inputs: uses standard PSBT signing
112
+ * - For MuSig2 inputs: uses the FirstRound state stored by generateMusig2Nonces()
113
+ * - For replay protection inputs: signs with legacy P2SH sighash
114
+ *
115
+ * @param inputIndex - The index of the input to sign (0-based)
116
+ * @param key - Either an xpriv (BIP32Arg) or a raw privkey (ECPairArg)
117
+ * @throws Error if signing fails, or if generateMusig2Nonces() was not called first for MuSig2 inputs
118
+ *
119
+ * @example
120
+ * ```typescript
121
+ * // Parse transaction to identify input types
122
+ * const parsed = psbt.parseTransactionWithWalletKeys(walletKeys, replayProtection);
123
+ *
124
+ * // Sign regular wallet inputs with xpriv
125
+ * for (let i = 0; i < parsed.inputs.length; i++) {
126
+ * const input = parsed.inputs[i];
127
+ * if (input.scriptId !== null && input.scriptType !== "p2shP2pk") {
128
+ * psbt.sign(i, userXpriv);
129
+ * }
130
+ * }
131
+ *
132
+ * // Sign replay protection inputs with raw privkey
133
+ * const userPrivkey = bip32.fromBase58(userXpriv).privateKey!;
134
+ * for (let i = 0; i < parsed.inputs.length; i++) {
135
+ * const input = parsed.inputs[i];
136
+ * if (input.scriptType === "p2shP2pk") {
137
+ * psbt.sign(i, userPrivkey);
138
+ * }
139
+ * }
140
+ * ```
141
+ */
142
+ sign(inputIndex: number, key: BIP32Arg | ECPairArg): void;
143
+ /**
144
+ * @deprecated - use verifySignature with the replay protection key instead
145
+ *
146
+ * Verify if a replay protection input has a valid signature.
147
+ *
148
+ * This method checks if a given input is a replay protection input (like P2shP2pk) and verifies
149
+ * the signature. Replay protection inputs don't use standard derivation paths, so this method
150
+ * verifies signatures without deriving from xpub.
151
+ *
152
+ * For P2PK replay protection inputs, this:
153
+ * - Extracts the signature from final_script_sig
154
+ * - Extracts the public key from redeem_script
155
+ * - Computes the legacy P2SH sighash
156
+ * - Verifies the ECDSA signature cryptographically
157
+ *
158
+ * @param inputIndex - The index of the input to check (0-based)
159
+ * @param replayProtection - Scripts that identify replay protection inputs (same format as parseTransactionWithWalletKeys)
160
+ * @returns true if the input is a replay protection input and has a valid signature, false if no valid signature
161
+ * @throws Error if the input is not a replay protection input, index is out of bounds, or scripts are invalid
162
+ */
163
+ verifyReplayProtectionSignature(inputIndex: number, replayProtection: ReplayProtectionArg): boolean;
164
+ /**
165
+ * Serialize the PSBT to bytes
166
+ *
167
+ * @returns The serialized PSBT as a byte array
168
+ */
169
+ serialize(): Uint8Array;
170
+ /**
171
+ * Generate and store MuSig2 nonces for all MuSig2 inputs
172
+ *
173
+ * This method generates nonces using the State-Machine API and stores them in the PSBT.
174
+ * The nonces are stored as proprietary fields in the PSBT and will be included when serialized.
175
+ * After ALL participants have generated their nonces, you can sign MuSig2 inputs using
176
+ * sign().
177
+ *
178
+ * @param key - The extended private key (xpriv) for signing. Can be a base58 string, BIP32 instance, or WasmBIP32
179
+ * @param sessionId - Optional 32-byte session ID for nonce generation. **Only allowed on testnets**.
180
+ * On mainnets, a secure random session ID is always generated automatically.
181
+ * Must be unique per signing session.
182
+ * @throws Error if nonce generation fails, sessionId length is invalid, or custom sessionId is
183
+ * provided on a mainnet (security restriction)
184
+ *
185
+ * @security The sessionId MUST be cryptographically random and unique for each signing session.
186
+ * Never reuse a sessionId with the same key! On mainnets, sessionId is always randomly
187
+ * generated for security. Custom sessionId is only allowed on testnets for testing purposes.
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * // Phase 1: Both parties generate nonces (with auto-generated session ID)
192
+ * psbt.generateMusig2Nonces(userXpriv);
193
+ * // Nonces are stored in the PSBT
194
+ * // Send PSBT to counterparty
195
+ *
196
+ * // Phase 2: After receiving counterparty PSBT with their nonces
197
+ * const counterpartyPsbt = BitGoPsbt.fromBytes(counterpartyPsbtBytes, network);
198
+ * psbt.combineMusig2Nonces(counterpartyPsbt);
199
+ * // Sign MuSig2 key path inputs
200
+ * const parsed = psbt.parseTransactionWithWalletKeys(walletKeys, replayProtection);
201
+ * for (let i = 0; i < parsed.inputs.length; i++) {
202
+ * if (parsed.inputs[i].scriptType === "p2trMusig2KeyPath") {
203
+ * psbt.sign(i, userXpriv);
204
+ * }
205
+ * }
206
+ * ```
207
+ */
208
+ generateMusig2Nonces(key: BIP32Arg, sessionId?: Uint8Array): void;
209
+ /**
210
+ * Combine/merge data from another PSBT into this one
211
+ *
212
+ * This method copies MuSig2 nonces and signatures (proprietary key-value pairs) from the
213
+ * source PSBT to this PSBT. This is useful for merging PSBTs during the nonce exchange
214
+ * and signature collection phases.
215
+ *
216
+ * @param sourcePsbt - The source PSBT containing data to merge
217
+ * @throws Error if networks don't match
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * // After receiving counterparty's PSBT with their nonces
222
+ * const counterpartyPsbt = BitGoPsbt.fromBytes(counterpartyPsbtBytes, network);
223
+ * psbt.combineMusig2Nonces(counterpartyPsbt);
224
+ * // Now can sign with all nonces present
225
+ * psbt.sign(0, userXpriv);
226
+ * ```
227
+ */
228
+ combineMusig2Nonces(sourcePsbt: BitGoPsbt): void;
229
+ /**
230
+ * Finalize all inputs in the PSBT
231
+ *
232
+ * @throws Error if any input failed to finalize
233
+ */
234
+ finalizeAllInputs(): void;
235
+ /**
236
+ * Extract the final transaction from a finalized PSBT
237
+ *
238
+ * @returns The serialized transaction bytes
239
+ * @throws Error if the PSBT is not fully finalized or extraction fails
240
+ */
241
+ extractTransaction(): Uint8Array;
242
+ }
@@ -0,0 +1,274 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BitGoPsbt = void 0;
4
+ const wasm_utxo_js_1 = require("../wasm/wasm_utxo.js");
5
+ const RootWalletKeys_js_1 = require("./RootWalletKeys.js");
6
+ const ReplayProtection_js_1 = require("./ReplayProtection.js");
7
+ const bip32_js_1 = require("../bip32.js");
8
+ const ecpair_js_1 = require("../ecpair.js");
9
+ class BitGoPsbt {
10
+ wasm;
11
+ constructor(wasm) {
12
+ this.wasm = wasm;
13
+ }
14
+ /**
15
+ * Deserialize a PSBT from bytes
16
+ * @param bytes - The PSBT bytes
17
+ * @param network - The network to use for deserialization (either utxolib name like "bitcoin" or coin name like "btc")
18
+ * @returns A BitGoPsbt instance
19
+ */
20
+ static fromBytes(bytes, network) {
21
+ const wasm = wasm_utxo_js_1.BitGoPsbt.from_bytes(bytes, network);
22
+ return new BitGoPsbt(wasm);
23
+ }
24
+ /**
25
+ * Get the unsigned transaction ID
26
+ * @returns The unsigned transaction ID
27
+ */
28
+ unsignedTxid() {
29
+ return this.wasm.unsigned_txid();
30
+ }
31
+ /**
32
+ * Parse transaction with wallet keys to identify wallet inputs/outputs
33
+ * @param walletKeys - The wallet keys to use for identification
34
+ * @param replayProtection - Scripts that are allowed as inputs without wallet validation
35
+ * @returns Parsed transaction information
36
+ */
37
+ parseTransactionWithWalletKeys(walletKeys, replayProtection) {
38
+ const keys = RootWalletKeys_js_1.RootWalletKeys.from(walletKeys);
39
+ const rp = ReplayProtection_js_1.ReplayProtection.from(replayProtection, this.wasm.network());
40
+ return this.wasm.parse_transaction_with_wallet_keys(keys.wasm, rp.wasm);
41
+ }
42
+ /**
43
+ * Parse outputs with wallet keys to identify which outputs belong to a wallet
44
+ * with the given wallet keys.
45
+ *
46
+ * This is useful in cases where we want to identify outputs that belong to a different
47
+ * wallet than the inputs.
48
+ *
49
+ * @param walletKeys - The wallet keys to use for identification
50
+ * @returns Array of parsed outputs
51
+ * @note This method does NOT validate wallet inputs. It only parses outputs.
52
+ */
53
+ parseOutputsWithWalletKeys(walletKeys) {
54
+ const keys = RootWalletKeys_js_1.RootWalletKeys.from(walletKeys);
55
+ return this.wasm.parse_outputs_with_wallet_keys(keys.wasm);
56
+ }
57
+ /**
58
+ * Verify if a valid signature exists for a given key at the specified input index.
59
+ *
60
+ * This method can verify signatures using either:
61
+ * - Extended public key (xpub): Derives the public key using the derivation path from PSBT
62
+ * - ECPair (private key): Extracts the public key and verifies directly
63
+ *
64
+ * When using xpub, it supports:
65
+ * - ECDSA signatures (for legacy/SegWit inputs)
66
+ * - Schnorr signatures (for Taproot script path inputs)
67
+ * - MuSig2 partial signatures (for Taproot keypath MuSig2 inputs)
68
+ *
69
+ * When using ECPair, it supports:
70
+ * - ECDSA signatures (for legacy/SegWit inputs)
71
+ * - Schnorr signatures (for Taproot script path inputs)
72
+ * Note: MuSig2 inputs require xpubs for derivation
73
+ *
74
+ * @param inputIndex - The index of the input to check (0-based)
75
+ * @param key - Either an extended public key (base58 string, BIP32 instance, or WasmBIP32) or an ECPair (private key Buffer, ECPair instance, or WasmECPair)
76
+ * @returns true if a valid signature exists, false if no signature exists
77
+ * @throws Error if input index is out of bounds, key is invalid, or verification fails
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * // Verify wallet input signature with xpub
82
+ * const hasUserSig = psbt.verifySignature(0, userXpub);
83
+ *
84
+ * // Verify signature with ECPair (private key)
85
+ * const ecpair = ECPair.fromPrivateKey(privateKeyBuffer);
86
+ * const hasReplaySig = psbt.verifySignature(1, ecpair);
87
+ *
88
+ * // Or pass private key directly
89
+ * const hasReplaySig2 = psbt.verifySignature(1, privateKeyBuffer);
90
+ * ```
91
+ */
92
+ verifySignature(inputIndex, key) {
93
+ // Try to parse as BIP32Arg first (string or BIP32 instance)
94
+ if (typeof key === "string" || ("derive" in key && typeof key.derive === "function")) {
95
+ const wasmKey = bip32_js_1.BIP32.from(key).wasm;
96
+ return this.wasm.verify_signature_with_xpub(inputIndex, wasmKey);
97
+ }
98
+ // Otherwise it's an ECPairArg (Uint8Array, ECPair, or WasmECPair)
99
+ const wasmECPair = ecpair_js_1.ECPair.from(key).wasm;
100
+ return this.wasm.verify_signature_with_pub(inputIndex, wasmECPair);
101
+ }
102
+ /**
103
+ * Sign a single input with a private key
104
+ *
105
+ * This method signs a specific input using the provided key. It accepts either:
106
+ * - An xpriv (BIP32Arg: base58 string, BIP32 instance, or WasmBIP32) for wallet inputs - derives the key and signs
107
+ * - A raw privkey (ECPairArg: Buffer, ECPair instance, or WasmECPair) for replay protection inputs - signs directly
108
+ *
109
+ * This method automatically detects and handles different input types:
110
+ * - For regular inputs: uses standard PSBT signing
111
+ * - For MuSig2 inputs: uses the FirstRound state stored by generateMusig2Nonces()
112
+ * - For replay protection inputs: signs with legacy P2SH sighash
113
+ *
114
+ * @param inputIndex - The index of the input to sign (0-based)
115
+ * @param key - Either an xpriv (BIP32Arg) or a raw privkey (ECPairArg)
116
+ * @throws Error if signing fails, or if generateMusig2Nonces() was not called first for MuSig2 inputs
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * // Parse transaction to identify input types
121
+ * const parsed = psbt.parseTransactionWithWalletKeys(walletKeys, replayProtection);
122
+ *
123
+ * // Sign regular wallet inputs with xpriv
124
+ * for (let i = 0; i < parsed.inputs.length; i++) {
125
+ * const input = parsed.inputs[i];
126
+ * if (input.scriptId !== null && input.scriptType !== "p2shP2pk") {
127
+ * psbt.sign(i, userXpriv);
128
+ * }
129
+ * }
130
+ *
131
+ * // Sign replay protection inputs with raw privkey
132
+ * const userPrivkey = bip32.fromBase58(userXpriv).privateKey!;
133
+ * for (let i = 0; i < parsed.inputs.length; i++) {
134
+ * const input = parsed.inputs[i];
135
+ * if (input.scriptType === "p2shP2pk") {
136
+ * psbt.sign(i, userPrivkey);
137
+ * }
138
+ * }
139
+ * ```
140
+ */
141
+ sign(inputIndex, key) {
142
+ // Detect key type
143
+ // If string or has 'derive' method → BIP32Arg
144
+ // Otherwise → ECPairArg
145
+ if (typeof key === "string" ||
146
+ (typeof key === "object" &&
147
+ key !== null &&
148
+ "derive" in key &&
149
+ typeof key.derive === "function")) {
150
+ // It's a BIP32Arg
151
+ const wasmKey = bip32_js_1.BIP32.from(key);
152
+ this.wasm.sign_with_xpriv(inputIndex, wasmKey.wasm);
153
+ }
154
+ else {
155
+ // It's an ECPairArg
156
+ const wasmKey = ecpair_js_1.ECPair.from(key);
157
+ this.wasm.sign_with_privkey(inputIndex, wasmKey.wasm);
158
+ }
159
+ }
160
+ /**
161
+ * @deprecated - use verifySignature with the replay protection key instead
162
+ *
163
+ * Verify if a replay protection input has a valid signature.
164
+ *
165
+ * This method checks if a given input is a replay protection input (like P2shP2pk) and verifies
166
+ * the signature. Replay protection inputs don't use standard derivation paths, so this method
167
+ * verifies signatures without deriving from xpub.
168
+ *
169
+ * For P2PK replay protection inputs, this:
170
+ * - Extracts the signature from final_script_sig
171
+ * - Extracts the public key from redeem_script
172
+ * - Computes the legacy P2SH sighash
173
+ * - Verifies the ECDSA signature cryptographically
174
+ *
175
+ * @param inputIndex - The index of the input to check (0-based)
176
+ * @param replayProtection - Scripts that identify replay protection inputs (same format as parseTransactionWithWalletKeys)
177
+ * @returns true if the input is a replay protection input and has a valid signature, false if no valid signature
178
+ * @throws Error if the input is not a replay protection input, index is out of bounds, or scripts are invalid
179
+ */
180
+ verifyReplayProtectionSignature(inputIndex, replayProtection) {
181
+ const rp = ReplayProtection_js_1.ReplayProtection.from(replayProtection, this.wasm.network());
182
+ return this.wasm.verify_replay_protection_signature(inputIndex, rp.wasm);
183
+ }
184
+ /**
185
+ * Serialize the PSBT to bytes
186
+ *
187
+ * @returns The serialized PSBT as a byte array
188
+ */
189
+ serialize() {
190
+ return this.wasm.serialize();
191
+ }
192
+ /**
193
+ * Generate and store MuSig2 nonces for all MuSig2 inputs
194
+ *
195
+ * This method generates nonces using the State-Machine API and stores them in the PSBT.
196
+ * The nonces are stored as proprietary fields in the PSBT and will be included when serialized.
197
+ * After ALL participants have generated their nonces, you can sign MuSig2 inputs using
198
+ * sign().
199
+ *
200
+ * @param key - The extended private key (xpriv) for signing. Can be a base58 string, BIP32 instance, or WasmBIP32
201
+ * @param sessionId - Optional 32-byte session ID for nonce generation. **Only allowed on testnets**.
202
+ * On mainnets, a secure random session ID is always generated automatically.
203
+ * Must be unique per signing session.
204
+ * @throws Error if nonce generation fails, sessionId length is invalid, or custom sessionId is
205
+ * provided on a mainnet (security restriction)
206
+ *
207
+ * @security The sessionId MUST be cryptographically random and unique for each signing session.
208
+ * Never reuse a sessionId with the same key! On mainnets, sessionId is always randomly
209
+ * generated for security. Custom sessionId is only allowed on testnets for testing purposes.
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * // Phase 1: Both parties generate nonces (with auto-generated session ID)
214
+ * psbt.generateMusig2Nonces(userXpriv);
215
+ * // Nonces are stored in the PSBT
216
+ * // Send PSBT to counterparty
217
+ *
218
+ * // Phase 2: After receiving counterparty PSBT with their nonces
219
+ * const counterpartyPsbt = BitGoPsbt.fromBytes(counterpartyPsbtBytes, network);
220
+ * psbt.combineMusig2Nonces(counterpartyPsbt);
221
+ * // Sign MuSig2 key path inputs
222
+ * const parsed = psbt.parseTransactionWithWalletKeys(walletKeys, replayProtection);
223
+ * for (let i = 0; i < parsed.inputs.length; i++) {
224
+ * if (parsed.inputs[i].scriptType === "p2trMusig2KeyPath") {
225
+ * psbt.sign(i, userXpriv);
226
+ * }
227
+ * }
228
+ * ```
229
+ */
230
+ generateMusig2Nonces(key, sessionId) {
231
+ const wasmKey = bip32_js_1.BIP32.from(key);
232
+ this.wasm.generate_musig2_nonces(wasmKey.wasm, sessionId);
233
+ }
234
+ /**
235
+ * Combine/merge data from another PSBT into this one
236
+ *
237
+ * This method copies MuSig2 nonces and signatures (proprietary key-value pairs) from the
238
+ * source PSBT to this PSBT. This is useful for merging PSBTs during the nonce exchange
239
+ * and signature collection phases.
240
+ *
241
+ * @param sourcePsbt - The source PSBT containing data to merge
242
+ * @throws Error if networks don't match
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * // After receiving counterparty's PSBT with their nonces
247
+ * const counterpartyPsbt = BitGoPsbt.fromBytes(counterpartyPsbtBytes, network);
248
+ * psbt.combineMusig2Nonces(counterpartyPsbt);
249
+ * // Now can sign with all nonces present
250
+ * psbt.sign(0, userXpriv);
251
+ * ```
252
+ */
253
+ combineMusig2Nonces(sourcePsbt) {
254
+ this.wasm.combine_musig2_nonces(sourcePsbt.wasm);
255
+ }
256
+ /**
257
+ * Finalize all inputs in the PSBT
258
+ *
259
+ * @throws Error if any input failed to finalize
260
+ */
261
+ finalizeAllInputs() {
262
+ this.wasm.finalize_all_inputs();
263
+ }
264
+ /**
265
+ * Extract the final transaction from a finalized PSBT
266
+ *
267
+ * @returns The serialized transaction bytes
268
+ * @throws Error if the PSBT is not fully finalized or extraction fails
269
+ */
270
+ extractTransaction() {
271
+ return this.wasm.extract_transaction();
272
+ }
273
+ }
274
+ exports.BitGoPsbt = BitGoPsbt;
@@ -0,0 +1,58 @@
1
+ import { WasmReplayProtection } from "../wasm/wasm_utxo.js";
2
+ import { type ECPairArg } from "../ecpair.js";
3
+ /**
4
+ * ReplayProtectionArg represents the various forms that replay protection can take
5
+ * before being converted to a WasmReplayProtection instance
6
+ */
7
+ export type ReplayProtectionArg = ReplayProtection | WasmReplayProtection | {
8
+ publicKeys: ECPairArg[];
9
+ } | {
10
+ /** @deprecated - use publicKeys instead */
11
+ outputScripts: Uint8Array[];
12
+ } | {
13
+ /** @deprecated - use publicKeys instead */
14
+ addresses: string[];
15
+ };
16
+ /**
17
+ * ReplayProtection wrapper class for PSBT replay protection inputs
18
+ */
19
+ export declare class ReplayProtection {
20
+ private _wasm;
21
+ private constructor();
22
+ /**
23
+ * Create a ReplayProtection instance from a WasmReplayProtection instance (internal use)
24
+ * @internal
25
+ */
26
+ static fromWasm(wasm: WasmReplayProtection): ReplayProtection;
27
+ /**
28
+ * Convert ReplayProtectionArg to ReplayProtection instance
29
+ * @param arg - The replay protection in various formats
30
+ * @param network - Optional network string (required for addresses variant)
31
+ * @returns ReplayProtection instance
32
+ */
33
+ static from(arg: ReplayProtectionArg, network?: string): ReplayProtection;
34
+ /**
35
+ * Create from public keys (derives P2SH-P2PK output scripts)
36
+ * @param publicKeys - Array of ECPair instances or arguments
37
+ * @returns ReplayProtection instance
38
+ */
39
+ static fromPublicKeys(publicKeys: ECPairArg[]): ReplayProtection;
40
+ /**
41
+ * Create from output scripts
42
+ * @param outputScripts - Array of output script buffers
43
+ * @returns ReplayProtection instance
44
+ */
45
+ static fromOutputScripts(outputScripts: Uint8Array[]): ReplayProtection;
46
+ /**
47
+ * Create from addresses
48
+ * @param addresses - Array of address strings
49
+ * @param network - Network string (e.g., "bitcoin", "testnet", "btc", "tbtc")
50
+ * @returns ReplayProtection instance
51
+ */
52
+ static fromAddresses(addresses: string[], network: string): ReplayProtection;
53
+ /**
54
+ * Get the underlying WASM instance (internal use only)
55
+ * @internal
56
+ */
57
+ get wasm(): WasmReplayProtection;
58
+ }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReplayProtection = void 0;
4
+ const wasm_utxo_js_1 = require("../wasm/wasm_utxo.js");
5
+ const ecpair_js_1 = require("../ecpair.js");
6
+ /**
7
+ * ReplayProtection wrapper class for PSBT replay protection inputs
8
+ */
9
+ class ReplayProtection {
10
+ _wasm;
11
+ constructor(_wasm) {
12
+ this._wasm = _wasm;
13
+ }
14
+ /**
15
+ * Create a ReplayProtection instance from a WasmReplayProtection instance (internal use)
16
+ * @internal
17
+ */
18
+ static fromWasm(wasm) {
19
+ return new ReplayProtection(wasm);
20
+ }
21
+ /**
22
+ * Convert ReplayProtectionArg to ReplayProtection instance
23
+ * @param arg - The replay protection in various formats
24
+ * @param network - Optional network string (required for addresses variant)
25
+ * @returns ReplayProtection instance
26
+ */
27
+ static from(arg, network) {
28
+ // Short-circuit if already a ReplayProtection instance
29
+ if (arg instanceof ReplayProtection) {
30
+ return arg;
31
+ }
32
+ // If it's a WasmReplayProtection instance, wrap it
33
+ if (arg instanceof wasm_utxo_js_1.WasmReplayProtection) {
34
+ return new ReplayProtection(arg);
35
+ }
36
+ // Handle object variants
37
+ if ("publicKeys" in arg) {
38
+ // Convert ECPairArg to public key bytes
39
+ const publicKeyBytes = arg.publicKeys.map((key) => ecpair_js_1.ECPair.from(key).publicKey);
40
+ const wasm = wasm_utxo_js_1.WasmReplayProtection.from_public_keys(publicKeyBytes);
41
+ return new ReplayProtection(wasm);
42
+ }
43
+ if ("outputScripts" in arg) {
44
+ const wasm = wasm_utxo_js_1.WasmReplayProtection.from_output_scripts(arg.outputScripts);
45
+ return new ReplayProtection(wasm);
46
+ }
47
+ if ("addresses" in arg) {
48
+ if (!network) {
49
+ throw new Error("Network is required when using addresses variant");
50
+ }
51
+ const wasm = wasm_utxo_js_1.WasmReplayProtection.from_addresses(arg.addresses, network);
52
+ return new ReplayProtection(wasm);
53
+ }
54
+ throw new Error("Invalid ReplayProtectionArg type");
55
+ }
56
+ /**
57
+ * Create from public keys (derives P2SH-P2PK output scripts)
58
+ * @param publicKeys - Array of ECPair instances or arguments
59
+ * @returns ReplayProtection instance
60
+ */
61
+ static fromPublicKeys(publicKeys) {
62
+ return ReplayProtection.from({ publicKeys });
63
+ }
64
+ /**
65
+ * Create from output scripts
66
+ * @param outputScripts - Array of output script buffers
67
+ * @returns ReplayProtection instance
68
+ */
69
+ static fromOutputScripts(outputScripts) {
70
+ return ReplayProtection.from({ outputScripts });
71
+ }
72
+ /**
73
+ * Create from addresses
74
+ * @param addresses - Array of address strings
75
+ * @param network - Network string (e.g., "bitcoin", "testnet", "btc", "tbtc")
76
+ * @returns ReplayProtection instance
77
+ */
78
+ static fromAddresses(addresses, network) {
79
+ return ReplayProtection.from({ addresses }, network);
80
+ }
81
+ /**
82
+ * Get the underlying WASM instance (internal use only)
83
+ * @internal
84
+ */
85
+ get wasm() {
86
+ return this._wasm;
87
+ }
88
+ }
89
+ exports.ReplayProtection = ReplayProtection;