@bitgo/wasm-utxo 1.28.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.
- package/dist/cjs/js/fixedScriptWallet/chains.d.ts +5 -0
- package/dist/cjs/js/fixedScriptWallet/chains.js +6 -2
- package/dist/cjs/js/fixedScriptWallet/index.d.ts +19 -2
- package/dist/cjs/js/fixedScriptWallet/index.js +25 -1
- package/dist/cjs/js/fixedScriptWallet/scriptType.d.ts +15 -5
- package/dist/cjs/js/fixedScriptWallet/scriptType.js +28 -0
- package/dist/cjs/js/testutils/AcidTest.d.ts +132 -0
- package/dist/cjs/js/testutils/AcidTest.js +306 -0
- package/dist/cjs/js/testutils/index.d.ts +2 -0
- package/dist/cjs/js/testutils/index.js +18 -0
- package/dist/cjs/js/testutils/keys.d.ts +76 -0
- package/dist/cjs/js/testutils/keys.js +154 -0
- package/dist/cjs/js/wasm/wasm_utxo.d.ts +10 -0
- package/dist/cjs/js/wasm/wasm_utxo.js +31 -0
- package/dist/cjs/js/wasm/wasm_utxo_bg.wasm +0 -0
- package/dist/cjs/js/wasm/wasm_utxo_bg.wasm.d.ts +2 -1
- package/dist/esm/js/fixedScriptWallet/chains.d.ts +5 -0
- package/dist/esm/js/fixedScriptWallet/chains.js +6 -3
- package/dist/esm/js/fixedScriptWallet/index.d.ts +19 -2
- package/dist/esm/js/fixedScriptWallet/index.js +21 -1
- package/dist/esm/js/fixedScriptWallet/scriptType.d.ts +15 -5
- package/dist/esm/js/fixedScriptWallet/scriptType.js +27 -1
- package/dist/esm/js/testutils/AcidTest.d.ts +132 -0
- package/dist/esm/js/testutils/AcidTest.js +302 -0
- package/dist/esm/js/testutils/index.d.ts +2 -0
- package/dist/esm/js/testutils/index.js +2 -0
- package/dist/esm/js/testutils/keys.d.ts +76 -0
- package/dist/esm/js/testutils/keys.js +113 -0
- package/dist/esm/js/wasm/wasm_utxo.d.ts +10 -0
- package/dist/esm/js/wasm/wasm_utxo_bg.js +31 -0
- package/dist/esm/js/wasm/wasm_utxo_bg.wasm +0 -0
- package/dist/esm/js/wasm/wasm_utxo_bg.wasm.d.ts +2 -1
- package/package.json +1 -1
|
@@ -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,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
|
+
}
|
|
@@ -677,6 +677,16 @@ export class FixedScriptWalletNamespace {
|
|
|
677
677
|
* - Dogecoin only supports legacy scripts (p2sh)
|
|
678
678
|
*/
|
|
679
679
|
static supports_script_type(coin: string, script_type: string): boolean;
|
|
680
|
+
/**
|
|
681
|
+
* Create an OP_RETURN output script with optional data
|
|
682
|
+
*
|
|
683
|
+
* # Arguments
|
|
684
|
+
* * `data` - Optional data bytes to include in the OP_RETURN script
|
|
685
|
+
*
|
|
686
|
+
* # Returns
|
|
687
|
+
* The OP_RETURN script as bytes
|
|
688
|
+
*/
|
|
689
|
+
static create_op_return_script(data?: Uint8Array | null): Uint8Array;
|
|
680
690
|
static address_with_network_str(keys: WasmRootWalletKeys, chain: number, index: number, network: string, address_format?: string | null): string;
|
|
681
691
|
static output_script_with_network_str(keys: WasmRootWalletKeys, chain: number, index: number, network: string): Uint8Array;
|
|
682
692
|
static address(keys: WasmRootWalletKeys, chain: number, index: number, network: any, address_format?: string | null): string;
|
|
@@ -1902,6 +1902,37 @@ export class FixedScriptWalletNamespace {
|
|
|
1902
1902
|
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
1903
1903
|
}
|
|
1904
1904
|
}
|
|
1905
|
+
/**
|
|
1906
|
+
* Create an OP_RETURN output script with optional data
|
|
1907
|
+
*
|
|
1908
|
+
* # Arguments
|
|
1909
|
+
* * `data` - Optional data bytes to include in the OP_RETURN script
|
|
1910
|
+
*
|
|
1911
|
+
* # Returns
|
|
1912
|
+
* The OP_RETURN script as bytes
|
|
1913
|
+
* @param {Uint8Array | null} [data]
|
|
1914
|
+
* @returns {Uint8Array}
|
|
1915
|
+
*/
|
|
1916
|
+
static create_op_return_script(data) {
|
|
1917
|
+
try {
|
|
1918
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
1919
|
+
var ptr0 = isLikeNone(data) ? 0 : passArray8ToWasm0(data, wasm.__wbindgen_export);
|
|
1920
|
+
var len0 = WASM_VECTOR_LEN;
|
|
1921
|
+
wasm.fixedscriptwalletnamespace_create_op_return_script(retptr, ptr0, len0);
|
|
1922
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
1923
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
1924
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
1925
|
+
var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
|
|
1926
|
+
if (r3) {
|
|
1927
|
+
throw takeObject(r2);
|
|
1928
|
+
}
|
|
1929
|
+
var v2 = getArrayU8FromWasm0(r0, r1).slice();
|
|
1930
|
+
wasm.__wbindgen_export4(r0, r1 * 1, 1);
|
|
1931
|
+
return v2;
|
|
1932
|
+
} finally {
|
|
1933
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1905
1936
|
/**
|
|
1906
1937
|
* @param {WasmRootWalletKeys} keys
|
|
1907
1938
|
* @param {number} chain
|
|
Binary file
|
|
@@ -100,6 +100,7 @@ export const bitgopsbt_version_group_id: (a: number) => number;
|
|
|
100
100
|
export const fixedscriptwalletnamespace_address: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
|
|
101
101
|
export const fixedscriptwalletnamespace_address_with_network_str: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
|
|
102
102
|
export const fixedscriptwalletnamespace_chain_code_table: () => number;
|
|
103
|
+
export const fixedscriptwalletnamespace_create_op_return_script: (a: number, b: number, c: number) => void;
|
|
103
104
|
export const fixedscriptwalletnamespace_output_script: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
104
105
|
export const fixedscriptwalletnamespace_output_script_with_network_str: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
105
106
|
export const fixedscriptwalletnamespace_supports_script_type: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
@@ -154,8 +155,8 @@ export const wasmrootwalletkeys_new: (a: number, b: number, c: number, d: number
|
|
|
154
155
|
export const wasmrootwalletkeys_user_key: (a: number) => number;
|
|
155
156
|
export const wasmrootwalletkeys_with_derivation_prefixes: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
|
|
156
157
|
export const wasmbip32_from_bip32_properties: (a: number, b: number) => void;
|
|
157
|
-
export const bitgopsbt_sign_all_with_xpriv: (a: number, b: number, c: number) => void;
|
|
158
158
|
export const bitgopsbt_sign_replay_protection_inputs: (a: number, b: number, c: number) => void;
|
|
159
|
+
export const bitgopsbt_sign_all_with_xpriv: (a: number, b: number, c: number) => void;
|
|
159
160
|
export const bitgopsbt_sign_wallet_input: (a: number, b: number, c: number, d: number) => void;
|
|
160
161
|
export const __wbg_wasmdashtransaction_free: (a: number, b: number) => void;
|
|
161
162
|
export const __wbg_wasmreplayprotection_free: (a: number, b: number) => void;
|