@bitgo/wasm-utxo 1.27.0 → 1.29.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 (41) hide show
  1. package/dist/cjs/js/bip32.d.ts +7 -0
  2. package/dist/cjs/js/bip32.js +16 -0
  3. package/dist/cjs/js/fixedScriptWallet/BitGoPsbt.d.ts +60 -26
  4. package/dist/cjs/js/fixedScriptWallet/BitGoPsbt.js +56 -36
  5. package/dist/cjs/js/fixedScriptWallet/chains.d.ts +5 -0
  6. package/dist/cjs/js/fixedScriptWallet/chains.js +6 -2
  7. package/dist/cjs/js/fixedScriptWallet/index.d.ts +19 -2
  8. package/dist/cjs/js/fixedScriptWallet/index.js +25 -1
  9. package/dist/cjs/js/fixedScriptWallet/scriptType.d.ts +15 -5
  10. package/dist/cjs/js/fixedScriptWallet/scriptType.js +28 -0
  11. package/dist/cjs/js/testutils/AcidTest.d.ts +132 -0
  12. package/dist/cjs/js/testutils/AcidTest.js +306 -0
  13. package/dist/cjs/js/testutils/index.d.ts +2 -0
  14. package/dist/cjs/js/testutils/index.js +18 -0
  15. package/dist/cjs/js/testutils/keys.d.ts +76 -0
  16. package/dist/cjs/js/testutils/keys.js +154 -0
  17. package/dist/cjs/js/wasm/wasm_utxo.d.ts +183 -0
  18. package/dist/cjs/js/wasm/wasm_utxo.js +354 -0
  19. package/dist/cjs/js/wasm/wasm_utxo_bg.wasm +0 -0
  20. package/dist/cjs/js/wasm/wasm_utxo_bg.wasm.d.ts +67 -56
  21. package/dist/esm/js/bip32.d.ts +7 -0
  22. package/dist/esm/js/bip32.js +15 -0
  23. package/dist/esm/js/fixedScriptWallet/BitGoPsbt.d.ts +60 -26
  24. package/dist/esm/js/fixedScriptWallet/BitGoPsbt.js +57 -37
  25. package/dist/esm/js/fixedScriptWallet/chains.d.ts +5 -0
  26. package/dist/esm/js/fixedScriptWallet/chains.js +6 -3
  27. package/dist/esm/js/fixedScriptWallet/index.d.ts +19 -2
  28. package/dist/esm/js/fixedScriptWallet/index.js +21 -1
  29. package/dist/esm/js/fixedScriptWallet/scriptType.d.ts +15 -5
  30. package/dist/esm/js/fixedScriptWallet/scriptType.js +27 -1
  31. package/dist/esm/js/testutils/AcidTest.d.ts +132 -0
  32. package/dist/esm/js/testutils/AcidTest.js +302 -0
  33. package/dist/esm/js/testutils/index.d.ts +2 -0
  34. package/dist/esm/js/testutils/index.js +2 -0
  35. package/dist/esm/js/testutils/keys.d.ts +76 -0
  36. package/dist/esm/js/testutils/keys.js +113 -0
  37. package/dist/esm/js/wasm/wasm_utxo.d.ts +183 -0
  38. package/dist/esm/js/wasm/wasm_utxo_bg.js +354 -0
  39. package/dist/esm/js/wasm/wasm_utxo_bg.wasm +0 -0
  40. package/dist/esm/js/wasm/wasm_utxo_bg.wasm.d.ts +67 -56
  41. package/package.json +2 -1
@@ -0,0 +1,132 @@
1
+ import { BitGoPsbt } from "../fixedScriptWallet/BitGoPsbt.js";
2
+ import { RootWalletKeys } from "../fixedScriptWallet/RootWalletKeys.js";
3
+ import { BIP32 } from "../bip32.js";
4
+ import { inputScriptTypes, outputScriptTypes, type InputScriptType, type OutputScriptType, type ScriptId } from "../fixedScriptWallet/index.js";
5
+ import type { CoinName } from "../coinName.js";
6
+ import type { Triple } from "../triple.js";
7
+ export declare const signStages: readonly ["unsigned", "halfsigned", "fullsigned"];
8
+ export type SignStage = (typeof signStages)[number];
9
+ export declare const txFormats: readonly ["psbt", "psbt-lite"];
10
+ export type TxFormat = (typeof txFormats)[number];
11
+ /**
12
+ * Utility type to make union variants mutually exclusive.
13
+ * For each variant T in the union, adds `?: never` for all keys from other variants.
14
+ */
15
+ type Exclusive<T, U = T> = T extends unknown ? T & Partial<Record<Exclude<U extends unknown ? keyof U : never, keyof T>, never>> : never;
16
+ /** Base input fields */
17
+ type InputBase = {
18
+ value: bigint;
19
+ /** Wallet keys to use. Defaults to root wallet keys */
20
+ walletKeys?: RootWalletKeys;
21
+ };
22
+ /** Input variant types */
23
+ type InputVariant = {
24
+ scriptType: InputScriptType;
25
+ index?: number;
26
+ } | {
27
+ scriptId: ScriptId;
28
+ };
29
+ /**
30
+ * Input configuration for AcidTest PSBT
31
+ *
32
+ * Either specify `scriptType` (chain derived from type, index defaults to position)
33
+ * or specify `scriptId` (explicit chain + index).
34
+ */
35
+ export type Input = InputBase & Exclusive<InputVariant>;
36
+ /** Base output fields */
37
+ type OutputBase = {
38
+ value: bigint;
39
+ /** Wallet keys to use. Defaults to root wallet keys. null = external output (no bip32 derivation) */
40
+ walletKeys?: RootWalletKeys | null;
41
+ };
42
+ /** Output variant types */
43
+ type OutputVariant = {
44
+ scriptType: OutputScriptType;
45
+ index?: number;
46
+ } | {
47
+ scriptId: ScriptId;
48
+ } | {
49
+ opReturn: string;
50
+ } | {
51
+ address: string;
52
+ } | {
53
+ script: Uint8Array;
54
+ };
55
+ /**
56
+ * Output configuration for AcidTest PSBT
57
+ *
58
+ * Specify one of:
59
+ * - `scriptType` (chain derived from type, index defaults to position)
60
+ * - `scriptId` (explicit chain + index)
61
+ * - `opReturn` for OP_RETURN data output
62
+ * - `address` for address-based output
63
+ * - `script` for raw script output
64
+ */
65
+ export type Output = OutputBase & Exclusive<OutputVariant>;
66
+ type SuiteConfig = {
67
+ /**
68
+ * By default, we exclude p2trMusig2ScriptPath from the inputs since
69
+ * it uses user + backup keys (not typical 2-of-3 with user + bitgo).
70
+ * Set to true to include this input type.
71
+ */
72
+ includeP2trMusig2ScriptPath?: boolean;
73
+ };
74
+ export { inputScriptTypes, outputScriptTypes };
75
+ /**
76
+ * Creates a valid PSBT with as many features as possible (kitchen sink).
77
+ *
78
+ * - Inputs:
79
+ * - All wallet script types supported by the network
80
+ * - A p2shP2pk input (for replay protection)
81
+ * - Outputs:
82
+ * - All wallet script types supported by the network
83
+ * - A p2sh output with derivation info of a different wallet
84
+ * - A p2sh output with no derivation info (external output)
85
+ * - An OP_RETURN output
86
+ *
87
+ * Signature stages:
88
+ * - unsigned: No signatures
89
+ * - halfsigned: One signature per input (user key)
90
+ * - fullsigned: Two signatures per input (user + bitgo)
91
+ *
92
+ * Transaction formats:
93
+ * - psbt: Full PSBT with non_witness_utxo
94
+ * - psbt-lite: Only witness_utxo (no non_witness_utxo)
95
+ */
96
+ export declare class AcidTest {
97
+ readonly network: CoinName;
98
+ readonly signStage: SignStage;
99
+ readonly txFormat: TxFormat;
100
+ readonly rootWalletKeys: RootWalletKeys;
101
+ readonly otherWalletKeys: RootWalletKeys;
102
+ readonly inputs: Input[];
103
+ readonly outputs: Output[];
104
+ private readonly userXprv;
105
+ private readonly backupXprv;
106
+ private readonly bitgoXprv;
107
+ constructor(network: CoinName, signStage: SignStage, txFormat: TxFormat, rootWalletKeys: RootWalletKeys, otherWalletKeys: RootWalletKeys, inputs: Input[], outputs: Output[], xprvTriple: Triple<BIP32>);
108
+ /**
109
+ * Create an AcidTest with specific configuration
110
+ */
111
+ static withConfig(network: CoinName, signStage: SignStage, txFormat: TxFormat, suiteConfig?: SuiteConfig): AcidTest;
112
+ /**
113
+ * Get a human-readable name for this test configuration
114
+ */
115
+ get name(): string;
116
+ /**
117
+ * Get the BIP32 user key for replay protection (p2shP2pk)
118
+ */
119
+ getReplayProtectionKey(): BIP32;
120
+ /**
121
+ * Create the actual PSBT with all inputs and outputs
122
+ */
123
+ createPsbt(): BitGoPsbt;
124
+ /**
125
+ * Sign the PSBT according to the sign stage
126
+ */
127
+ private signPsbt;
128
+ /**
129
+ * Generate test suite for all networks, sign stages, and tx formats
130
+ */
131
+ static forAllNetworksSignStagesTxFormats(suiteConfig?: SuiteConfig): AcidTest[];
132
+ }
@@ -0,0 +1,302 @@
1
+ import { BitGoPsbt } from "../fixedScriptWallet/BitGoPsbt.js";
2
+ import { ZcashBitGoPsbt } from "../fixedScriptWallet/ZcashBitGoPsbt.js";
3
+ import { ECPair } from "../ecpair.js";
4
+ import { assertChainCode, ChainCode, createOpReturnScript, inputScriptTypes, outputScript, outputScriptTypes, supportsScriptType, } from "../fixedScriptWallet/index.js";
5
+ import { coinNames, isMainnet } from "../coinName.js";
6
+ import { getDefaultWalletKeys, getWalletKeysForSeed, getKeyTriple } from "./keys.js";
7
+ export const signStages = ["unsigned", "halfsigned", "fullsigned"];
8
+ export const txFormats = ["psbt", "psbt-lite"];
9
+ // Re-export for convenience
10
+ export { inputScriptTypes, outputScriptTypes };
11
+ /**
12
+ * Creates a valid PSBT with as many features as possible (kitchen sink).
13
+ *
14
+ * - Inputs:
15
+ * - All wallet script types supported by the network
16
+ * - A p2shP2pk input (for replay protection)
17
+ * - Outputs:
18
+ * - All wallet script types supported by the network
19
+ * - A p2sh output with derivation info of a different wallet
20
+ * - A p2sh output with no derivation info (external output)
21
+ * - An OP_RETURN output
22
+ *
23
+ * Signature stages:
24
+ * - unsigned: No signatures
25
+ * - halfsigned: One signature per input (user key)
26
+ * - fullsigned: Two signatures per input (user + bitgo)
27
+ *
28
+ * Transaction formats:
29
+ * - psbt: Full PSBT with non_witness_utxo
30
+ * - psbt-lite: Only witness_utxo (no non_witness_utxo)
31
+ */
32
+ export class AcidTest {
33
+ network;
34
+ signStage;
35
+ txFormat;
36
+ rootWalletKeys;
37
+ otherWalletKeys;
38
+ inputs;
39
+ outputs;
40
+ // Store private keys for signing
41
+ userXprv;
42
+ backupXprv;
43
+ bitgoXprv;
44
+ constructor(network, signStage, txFormat, rootWalletKeys, otherWalletKeys, inputs, outputs, xprvTriple) {
45
+ this.network = network;
46
+ this.signStage = signStage;
47
+ this.txFormat = txFormat;
48
+ this.rootWalletKeys = rootWalletKeys;
49
+ this.otherWalletKeys = otherWalletKeys;
50
+ this.inputs = inputs;
51
+ this.outputs = outputs;
52
+ this.userXprv = xprvTriple[0];
53
+ this.backupXprv = xprvTriple[1];
54
+ this.bitgoXprv = xprvTriple[2];
55
+ }
56
+ /**
57
+ * Create an AcidTest with specific configuration
58
+ */
59
+ static withConfig(network, signStage, txFormat, suiteConfig = {}) {
60
+ const rootWalletKeys = getDefaultWalletKeys();
61
+ const otherWalletKeys = getWalletKeysForSeed("too many secrets");
62
+ // Filter inputs based on network support
63
+ const inputs = inputScriptTypes
64
+ .filter((scriptType) => {
65
+ // p2shP2pk is always supported (single-sig replay protection)
66
+ if (scriptType === "p2shP2pk")
67
+ return true;
68
+ // Map input script types to output script types for support check
69
+ if (scriptType === "p2trMusig2KeyPath" || scriptType === "p2trMusig2ScriptPath") {
70
+ return supportsScriptType(network, "p2trMusig2");
71
+ }
72
+ return supportsScriptType(network, scriptType);
73
+ })
74
+ .filter((scriptType) => (suiteConfig.includeP2trMusig2ScriptPath ?? false) ||
75
+ scriptType !== "p2trMusig2ScriptPath")
76
+ .map((scriptType, index) => ({
77
+ scriptType,
78
+ value: BigInt(10000 + index * 10000), // Deterministic amounts
79
+ }));
80
+ // Filter outputs based on network support
81
+ const outputs = outputScriptTypes
82
+ .filter((scriptType) => supportsScriptType(network, scriptType))
83
+ .map((scriptType, index) => ({
84
+ scriptType,
85
+ value: BigInt(900 + index * 100), // Deterministic amounts
86
+ }));
87
+ // Test other wallet output (with derivation info)
88
+ outputs.push({ scriptType: "p2sh", value: BigInt(800), walletKeys: otherWalletKeys });
89
+ // Test non-wallet output (no derivation info)
90
+ outputs.push({ scriptType: "p2sh", value: BigInt(700), walletKeys: null });
91
+ // Test OP_RETURN output
92
+ outputs.push({ opReturn: "setec astronomy", value: BigInt(0) });
93
+ // Get private keys for signing
94
+ const xprvTriple = getKeyTriple("default");
95
+ return new AcidTest(network, signStage, txFormat, rootWalletKeys, otherWalletKeys, inputs, outputs, xprvTriple);
96
+ }
97
+ /**
98
+ * Get a human-readable name for this test configuration
99
+ */
100
+ get name() {
101
+ return `${this.network} ${this.signStage} ${this.txFormat}`;
102
+ }
103
+ /**
104
+ * Get the BIP32 user key for replay protection (p2shP2pk)
105
+ */
106
+ getReplayProtectionKey() {
107
+ return this.rootWalletKeys.userKey();
108
+ }
109
+ /**
110
+ * Create the actual PSBT with all inputs and outputs
111
+ */
112
+ createPsbt() {
113
+ // Use ZcashBitGoPsbt for Zcash networks
114
+ const isZcash = this.network === "zec" || this.network === "tzec";
115
+ const psbt = isZcash
116
+ ? ZcashBitGoPsbt.createEmptyWithConsensusBranchId(this.network, this.rootWalletKeys, {
117
+ version: 2,
118
+ lockTime: 0,
119
+ consensusBranchId: 0xc2d6d0b4, // NU5
120
+ })
121
+ : BitGoPsbt.createEmpty(this.network, this.rootWalletKeys, {
122
+ version: 2,
123
+ lockTime: 0,
124
+ });
125
+ // Add inputs with deterministic outpoints
126
+ this.inputs.forEach((input, index) => {
127
+ // Resolve scriptId: either from explicit scriptId or from scriptType + index
128
+ const scriptId = input.scriptId ?? {
129
+ chain: ChainCode.value("p2sh", "external"),
130
+ index: input.index ?? index,
131
+ };
132
+ const walletKeys = input.walletKeys ?? this.rootWalletKeys;
133
+ // Get scriptType: either explicit or derive from scriptId chain
134
+ const scriptType = input.scriptType ?? ChainCode.scriptType(assertChainCode(scriptId.chain));
135
+ if (scriptType === "p2shP2pk") {
136
+ // Add replay protection input
137
+ const replayKey = this.getReplayProtectionKey();
138
+ // Convert BIP32 to ECPair using public key
139
+ const ecpair = ECPair.fromPublicKey(replayKey.publicKey);
140
+ psbt.addReplayProtectionInput({
141
+ txid: "0".repeat(64),
142
+ vout: index,
143
+ value: input.value,
144
+ }, ecpair);
145
+ }
146
+ else {
147
+ // Determine signing path based on input type
148
+ let signPath;
149
+ if (scriptType === "p2trMusig2ScriptPath") {
150
+ // Script path uses user + backup
151
+ signPath = { signer: "user", cosigner: "backup" };
152
+ }
153
+ else {
154
+ // Default: user + bitgo
155
+ signPath = { signer: "user", cosigner: "bitgo" };
156
+ }
157
+ psbt.addWalletInput({
158
+ txid: "0".repeat(64),
159
+ vout: index,
160
+ value: input.value,
161
+ }, walletKeys, {
162
+ scriptId,
163
+ signPath,
164
+ });
165
+ }
166
+ });
167
+ // Add outputs
168
+ this.outputs.forEach((output, index) => {
169
+ if (output.opReturn !== undefined) {
170
+ // OP_RETURN output
171
+ const data = new TextEncoder().encode(output.opReturn);
172
+ const script = createOpReturnScript(data);
173
+ psbt.addOutput(script, output.value);
174
+ }
175
+ else if (output.address !== undefined) {
176
+ // Address-based output
177
+ psbt.addOutput(output.address, output.value);
178
+ }
179
+ else if (output.script !== undefined) {
180
+ // Raw script output
181
+ psbt.addOutput(output.script, output.value);
182
+ }
183
+ else {
184
+ // Wallet output: resolve scriptId from scriptType or explicit scriptId
185
+ const scriptId = output.scriptId ?? {
186
+ chain: output.scriptType ? ChainCode.value(output.scriptType, "external") : 0,
187
+ index: output.index ?? index,
188
+ };
189
+ if (output.walletKeys === null) {
190
+ // External output (no wallet keys, no bip32 derivation)
191
+ // Use high index for external outputs if not specified
192
+ const externalScriptId = output.scriptId ?? {
193
+ chain: scriptId.chain,
194
+ index: output.index ?? 1000 + index,
195
+ };
196
+ const script = outputScript(this.rootWalletKeys, externalScriptId.chain, externalScriptId.index, this.network);
197
+ psbt.addOutput(script, output.value);
198
+ }
199
+ else {
200
+ // Wallet output (with or without different wallet keys)
201
+ const walletKeys = output.walletKeys ?? this.rootWalletKeys;
202
+ psbt.addWalletOutput(walletKeys, {
203
+ chain: scriptId.chain,
204
+ index: scriptId.index,
205
+ value: output.value,
206
+ });
207
+ }
208
+ }
209
+ });
210
+ // Apply signing based on stage
211
+ if (this.signStage !== "unsigned") {
212
+ this.signPsbt(psbt);
213
+ }
214
+ return psbt;
215
+ }
216
+ /**
217
+ * Sign the PSBT according to the sign stage
218
+ */
219
+ signPsbt(psbt) {
220
+ // Use private keys stored in constructor
221
+ const userKey = this.userXprv;
222
+ const backupKey = this.backupXprv;
223
+ const bitgoKey = this.bitgoXprv;
224
+ // Generate MuSig2 nonces for user if needed
225
+ const hasMusig2Inputs = this.inputs.some((input) => input.scriptType === "p2trMusig2KeyPath" || input.scriptType === "p2trMusig2ScriptPath");
226
+ if (hasMusig2Inputs) {
227
+ const isZcash = this.network === "zec" || this.network === "tzec";
228
+ if (isZcash) {
229
+ throw new Error("Zcash does not support MuSig2/Taproot inputs");
230
+ }
231
+ // Generate nonces with user key
232
+ psbt.generateMusig2Nonces(userKey);
233
+ if (this.signStage === "fullsigned") {
234
+ // Create a second PSBT with cosigner nonces for combination
235
+ // For p2trMusig2ScriptPath use backup, for p2trMusig2KeyPath use bitgo
236
+ // Since we might have both types, we need to generate nonces separately
237
+ const bytes = psbt.serialize();
238
+ const hasKeyPath = this.inputs.some((input) => input.scriptType === "p2trMusig2KeyPath");
239
+ const hasScriptPath = this.inputs.some((input) => input.scriptType === "p2trMusig2ScriptPath");
240
+ if (hasKeyPath && !hasScriptPath) {
241
+ // Only key path inputs - generate bitgo nonces for all
242
+ const psbt2 = BitGoPsbt.fromBytes(bytes, this.network);
243
+ psbt2.generateMusig2Nonces(bitgoKey);
244
+ psbt.combineMusig2Nonces(psbt2);
245
+ }
246
+ else if (hasScriptPath && !hasKeyPath) {
247
+ // Only script path inputs - generate backup nonces for all
248
+ const psbt2 = BitGoPsbt.fromBytes(bytes, this.network);
249
+ psbt2.generateMusig2Nonces(backupKey);
250
+ psbt.combineMusig2Nonces(psbt2);
251
+ }
252
+ else {
253
+ const psbt2 = BitGoPsbt.fromBytes(bytes, this.network);
254
+ psbt2.generateMusig2Nonces(bitgoKey);
255
+ psbt.combineMusig2Nonces(psbt2);
256
+ }
257
+ }
258
+ }
259
+ // Sign all wallet inputs with user key (bulk - more efficient)
260
+ psbt.sign(userKey);
261
+ // Sign replay protection inputs with raw private key
262
+ const hasReplayProtection = this.inputs.some((input) => input.scriptType === "p2shP2pk");
263
+ if (hasReplayProtection) {
264
+ if (!userKey.privateKey) {
265
+ throw new Error("User key must have private key for signing replay protection inputs");
266
+ }
267
+ psbt.sign(userKey.privateKey);
268
+ }
269
+ // For fullsigned, sign with cosigner
270
+ if (this.signStage === "fullsigned") {
271
+ const hasScriptPath = this.inputs.some((input) => input.scriptType === "p2trMusig2ScriptPath");
272
+ if (hasScriptPath) {
273
+ // Mixed case: script path uses backup, others use bitgo
274
+ // Need per-input signing (slow) to handle different cosigners
275
+ this.inputs.forEach((input, index) => {
276
+ if (input.scriptType === "p2shP2pk") {
277
+ // Replay protection is single-sig, already fully signed
278
+ return;
279
+ }
280
+ if (input.scriptType === "p2trMusig2ScriptPath") {
281
+ psbt.signInput(index, backupKey);
282
+ }
283
+ else {
284
+ psbt.signInput(index, bitgoKey);
285
+ }
286
+ });
287
+ }
288
+ else {
289
+ // No script path - can use bulk signing with bitgo (fast)
290
+ psbt.sign(bitgoKey);
291
+ }
292
+ }
293
+ }
294
+ /**
295
+ * Generate test suite for all networks, sign stages, and tx formats
296
+ */
297
+ static forAllNetworksSignStagesTxFormats(suiteConfig = {}) {
298
+ return coinNames
299
+ .filter((network) => isMainnet(network) && network !== "bsv") // Exclude bitcoinsv
300
+ .flatMap((network) => signStages.flatMap((signStage) => txFormats.map((txFormat) => AcidTest.withConfig(network, signStage, txFormat, suiteConfig))));
301
+ }
302
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./keys.js";
2
+ export * from "./AcidTest.js";
@@ -0,0 +1,2 @@
1
+ export * from "./keys.js";
2
+ export * from "./AcidTest.js";
@@ -0,0 +1,76 @@
1
+ import { BIP32 } from "../bip32.js";
2
+ import { RootWalletKeys } from "../fixedScriptWallet/RootWalletKeys.js";
3
+ import type { Triple } from "../triple.js";
4
+ /**
5
+ * Generate a deterministic BIP32 key from a seed string.
6
+ * Uses SHA256 hash of the seed to create the key, matching utxo-lib's implementation.
7
+ *
8
+ * @param seed - Seed string for deterministic key generation
9
+ * @returns BIP32 key derived from the seed
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const key = getKey("user");
14
+ * const xpub = key.neutered().toBase58();
15
+ * ```
16
+ */
17
+ export declare function getKey(seed: string): BIP32;
18
+ /**
19
+ * Generate a triple of BIP32 keys for a 2-of-3 multisig wallet.
20
+ * Keys are generated deterministically from the seed string with suffixes .0, .1, .2
21
+ * for user, backup, and bitgo keys respectively.
22
+ *
23
+ * @param seed - Base seed string for key generation
24
+ * @returns Triple of BIP32 keys [user, backup, bitgo]
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const keys = getKeyTriple("default");
29
+ * const [user, backup, bitgo] = keys;
30
+ * ```
31
+ */
32
+ export declare function getKeyTriple(seed: string): Triple<BIP32>;
33
+ /**
34
+ * Create RootWalletKeys from a seed string.
35
+ * Uses standard derivation prefixes ["m/0/0", "m/0/0", "m/0/0"].
36
+ *
37
+ * @param seed - Seed string for key generation
38
+ * @returns RootWalletKeys instance
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const walletKeys = getWalletKeysForSeed("default");
43
+ * ```
44
+ */
45
+ export declare function getWalletKeysForSeed(seed: string): RootWalletKeys;
46
+ /**
47
+ * Get the default wallet keys for testing.
48
+ * Equivalent to getWalletKeysForSeed("default").
49
+ *
50
+ * @returns RootWalletKeys instance with default seed
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const walletKeys = getDefaultWalletKeys();
55
+ * ```
56
+ */
57
+ export declare function getDefaultWalletKeys(): RootWalletKeys;
58
+ /**
59
+ * Get the key name (user, backup, or bitgo) for a given key in a triple.
60
+ *
61
+ * @param triple - Triple of BIP32 keys
62
+ * @param key - Key to find in the triple
63
+ * @returns "user", "backup", "bitgo", or undefined if not found
64
+ */
65
+ export declare function getKeyName(triple: Triple<BIP32>, key: BIP32): "user" | "backup" | "bitgo" | undefined;
66
+ /**
67
+ * Get the default cosigner for a given signer key.
68
+ * - If signer is user, returns bitgo
69
+ * - If signer is backup, returns bitgo
70
+ * - If signer is bitgo, returns user
71
+ *
72
+ * @param keyset - Triple of keys [user, backup, bitgo]
73
+ * @param signer - The signing key
74
+ * @returns The default cosigner key
75
+ */
76
+ export declare function getDefaultCosigner<T>(keyset: Triple<T>, signer: T): T;
@@ -0,0 +1,113 @@
1
+ import * as crypto from "crypto";
2
+ import { BIP32 } from "../bip32.js";
3
+ import { RootWalletKeys } from "../fixedScriptWallet/RootWalletKeys.js";
4
+ /**
5
+ * Generate a deterministic BIP32 key from a seed string.
6
+ * Uses SHA256 hash of the seed to create the key, matching utxo-lib's implementation.
7
+ *
8
+ * @param seed - Seed string for deterministic key generation
9
+ * @returns BIP32 key derived from the seed
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const key = getKey("user");
14
+ * const xpub = key.neutered().toBase58();
15
+ * ```
16
+ */
17
+ export function getKey(seed) {
18
+ return BIP32.fromSeed(crypto.createHash("sha256").update(seed).digest());
19
+ }
20
+ /**
21
+ * Generate a triple of BIP32 keys for a 2-of-3 multisig wallet.
22
+ * Keys are generated deterministically from the seed string with suffixes .0, .1, .2
23
+ * for user, backup, and bitgo keys respectively.
24
+ *
25
+ * @param seed - Base seed string for key generation
26
+ * @returns Triple of BIP32 keys [user, backup, bitgo]
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * const keys = getKeyTriple("default");
31
+ * const [user, backup, bitgo] = keys;
32
+ * ```
33
+ */
34
+ export function getKeyTriple(seed) {
35
+ return [getKey(seed + ".0"), getKey(seed + ".1"), getKey(seed + ".2")];
36
+ }
37
+ /**
38
+ * Create RootWalletKeys from a seed string.
39
+ * Uses standard derivation prefixes ["m/0/0", "m/0/0", "m/0/0"].
40
+ *
41
+ * @param seed - Seed string for key generation
42
+ * @returns RootWalletKeys instance
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * const walletKeys = getWalletKeysForSeed("default");
47
+ * ```
48
+ */
49
+ export function getWalletKeysForSeed(seed) {
50
+ const triple = getKeyTriple(seed);
51
+ return RootWalletKeys.from({
52
+ triple,
53
+ derivationPrefixes: ["m/0/0", "m/0/0", "m/0/0"],
54
+ });
55
+ }
56
+ /**
57
+ * Get the default wallet keys for testing.
58
+ * Equivalent to getWalletKeysForSeed("default").
59
+ *
60
+ * @returns RootWalletKeys instance with default seed
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * const walletKeys = getDefaultWalletKeys();
65
+ * ```
66
+ */
67
+ export function getDefaultWalletKeys() {
68
+ return getWalletKeysForSeed("default");
69
+ }
70
+ /**
71
+ * Get the key name (user, backup, or bitgo) for a given key in a triple.
72
+ *
73
+ * @param triple - Triple of BIP32 keys
74
+ * @param key - Key to find in the triple
75
+ * @returns "user", "backup", "bitgo", or undefined if not found
76
+ */
77
+ export function getKeyName(triple, key) {
78
+ const index = triple.findIndex((k) => {
79
+ const kb58 = k.toBase58();
80
+ const keyb58 = key.toBase58();
81
+ return kb58 === keyb58;
82
+ });
83
+ if (index === 0)
84
+ return "user";
85
+ if (index === 1)
86
+ return "backup";
87
+ if (index === 2)
88
+ return "bitgo";
89
+ return undefined;
90
+ }
91
+ /**
92
+ * Get the default cosigner for a given signer key.
93
+ * - If signer is user, returns bitgo
94
+ * - If signer is backup, returns bitgo
95
+ * - If signer is bitgo, returns user
96
+ *
97
+ * @param keyset - Triple of keys [user, backup, bitgo]
98
+ * @param signer - The signing key
99
+ * @returns The default cosigner key
100
+ */
101
+ export function getDefaultCosigner(keyset, signer) {
102
+ const [user, backup, bitgo] = keyset;
103
+ if (signer === user) {
104
+ return bitgo;
105
+ }
106
+ if (signer === backup) {
107
+ return bitgo;
108
+ }
109
+ if (signer === bitgo) {
110
+ return user;
111
+ }
112
+ throw new Error("signer not in keyset");
113
+ }