@argonprotocol/bitcoin 1.3.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/lib/bitcoin_bindings_bg-7MW5MTH2.wasm +0 -0
- package/lib/index.d.ts +52 -0
- package/lib/index.js +455 -0
- package/package.json +50 -0
|
Binary file
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BIP32Interface } from 'bip32';
|
|
2
|
+
import { networks, Psbt, Transaction } from 'bitcoinjs-lib';
|
|
3
|
+
import { IBitcoinLock, ArgonPrimitivesBitcoinBitcoinNetwork, IReleaseRequest } from '@argonprotocol/mainchain';
|
|
4
|
+
|
|
5
|
+
declare class CosignScript {
|
|
6
|
+
readonly lock: IBitcoinLock;
|
|
7
|
+
private readonly network;
|
|
8
|
+
constructor(lock: IBitcoinLock, network: networks.Network | ArgonPrimitivesBitcoinBitcoinNetwork);
|
|
9
|
+
getFundingPsbt(): Psbt;
|
|
10
|
+
calculateFee(feeRatePerSatVb: bigint, toScriptPubkey: string): bigint;
|
|
11
|
+
calculateScriptPubkey(): string;
|
|
12
|
+
getCosignPsbt(args: {
|
|
13
|
+
utxoRef: {
|
|
14
|
+
txid: string;
|
|
15
|
+
vout: number;
|
|
16
|
+
};
|
|
17
|
+
releaseRequest: IReleaseRequest;
|
|
18
|
+
}): Psbt;
|
|
19
|
+
psbtFromHex(psbtHex: string): Psbt;
|
|
20
|
+
/**
|
|
21
|
+
* Cosigns the PSBT with the vault xpub.
|
|
22
|
+
* @param psbt - The PSBT to cosign.
|
|
23
|
+
* @param lock - The Bitcoin lock containing the vault information.
|
|
24
|
+
* @param vaultXpriv - The vault's extended private key of which the xpub was used to create the vault.
|
|
25
|
+
*/
|
|
26
|
+
vaultCosignPsbt(psbt: Psbt, lock: IBitcoinLock, vaultXpriv: BIP32Interface): Psbt;
|
|
27
|
+
/**
|
|
28
|
+
* Cosigns the transaction.
|
|
29
|
+
*/
|
|
30
|
+
cosignAndGenerateTx(args: {
|
|
31
|
+
releaseRequest: IReleaseRequest;
|
|
32
|
+
vaultCosignature: Uint8Array;
|
|
33
|
+
utxoRef: {
|
|
34
|
+
txid: string;
|
|
35
|
+
vout: number;
|
|
36
|
+
};
|
|
37
|
+
ownerXpriv: BIP32Interface;
|
|
38
|
+
ownerXprivChildHdPath?: string;
|
|
39
|
+
addTx?: string;
|
|
40
|
+
}): Transaction;
|
|
41
|
+
static getBitcoinJsNetwork(network: ArgonPrimitivesBitcoinBitcoinNetwork): networks.Network;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
declare function getChildXpriv(bip39Seed: Buffer, hdPath: string, network?: networks.Network): BIP32Interface;
|
|
45
|
+
declare function getBip39Seed(mnemonic: string, passphrase?: string): Buffer;
|
|
46
|
+
declare function getXpubFromXpriv(xpriv: BIP32Interface): string;
|
|
47
|
+
declare function getCompressedPubkey(pubkey: string | Buffer): Buffer;
|
|
48
|
+
declare function stripLeadingHexPrefix(hex: string): string;
|
|
49
|
+
declare function addressBytesHex(addressString: string, network: networks.Network): string;
|
|
50
|
+
declare function keyToBuffer(key: string | Buffer): Buffer;
|
|
51
|
+
|
|
52
|
+
export { CosignScript, addressBytesHex, getBip39Seed, getChildXpriv, getCompressedPubkey, getXpubFromXpriv, keyToBuffer, stripLeadingHexPrefix };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// ts/CosignScript.ts
|
|
8
|
+
import { networks as networks2, payments, Psbt, Transaction } from "bitcoinjs-lib";
|
|
9
|
+
|
|
10
|
+
// ts/wasm/bitcoin_bindings_bg.wasm
|
|
11
|
+
var bitcoin_bindings_bg_exports = {};
|
|
12
|
+
__export(bitcoin_bindings_bg_exports, {
|
|
13
|
+
default: () => bitcoin_bindings_bg_default
|
|
14
|
+
});
|
|
15
|
+
var bitcoin_bindings_bg_default = "./bitcoin_bindings_bg-7MW5MTH2.wasm";
|
|
16
|
+
|
|
17
|
+
// ts/wasm/bitcoin_bindings_bg.js
|
|
18
|
+
var wasm;
|
|
19
|
+
function __wbg_set_wasm(val) {
|
|
20
|
+
wasm = val;
|
|
21
|
+
}
|
|
22
|
+
var lTextDecoder = typeof TextDecoder === "undefined" ? (0, module.require)("util").TextDecoder : TextDecoder;
|
|
23
|
+
var cachedTextDecoder = new lTextDecoder("utf-8", { ignoreBOM: true, fatal: true });
|
|
24
|
+
cachedTextDecoder.decode();
|
|
25
|
+
var cachedUint8ArrayMemory0 = null;
|
|
26
|
+
function getUint8ArrayMemory0() {
|
|
27
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
28
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
29
|
+
}
|
|
30
|
+
return cachedUint8ArrayMemory0;
|
|
31
|
+
}
|
|
32
|
+
function getStringFromWasm0(ptr, len) {
|
|
33
|
+
ptr = ptr >>> 0;
|
|
34
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
35
|
+
}
|
|
36
|
+
var WASM_VECTOR_LEN = 0;
|
|
37
|
+
var lTextEncoder = typeof TextEncoder === "undefined" ? (0, module.require)("util").TextEncoder : TextEncoder;
|
|
38
|
+
var cachedTextEncoder = new lTextEncoder("utf-8");
|
|
39
|
+
var encodeString = typeof cachedTextEncoder.encodeInto === "function" ? function(arg, view) {
|
|
40
|
+
return cachedTextEncoder.encodeInto(arg, view);
|
|
41
|
+
} : function(arg, view) {
|
|
42
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
43
|
+
view.set(buf);
|
|
44
|
+
return {
|
|
45
|
+
read: arg.length,
|
|
46
|
+
written: buf.length
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
50
|
+
if (realloc === void 0) {
|
|
51
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
52
|
+
const ptr2 = malloc(buf.length, 1) >>> 0;
|
|
53
|
+
getUint8ArrayMemory0().subarray(ptr2, ptr2 + buf.length).set(buf);
|
|
54
|
+
WASM_VECTOR_LEN = buf.length;
|
|
55
|
+
return ptr2;
|
|
56
|
+
}
|
|
57
|
+
let len = arg.length;
|
|
58
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
59
|
+
const mem = getUint8ArrayMemory0();
|
|
60
|
+
let offset = 0;
|
|
61
|
+
for (; offset < len; offset++) {
|
|
62
|
+
const code = arg.charCodeAt(offset);
|
|
63
|
+
if (code > 127) break;
|
|
64
|
+
mem[ptr + offset] = code;
|
|
65
|
+
}
|
|
66
|
+
if (offset !== len) {
|
|
67
|
+
if (offset !== 0) {
|
|
68
|
+
arg = arg.slice(offset);
|
|
69
|
+
}
|
|
70
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
71
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
72
|
+
const ret = encodeString(arg, view);
|
|
73
|
+
offset += ret.written;
|
|
74
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
75
|
+
}
|
|
76
|
+
WASM_VECTOR_LEN = offset;
|
|
77
|
+
return ptr;
|
|
78
|
+
}
|
|
79
|
+
function takeFromExternrefTable0(idx) {
|
|
80
|
+
const value = wasm.__wbindgen_export_3.get(idx);
|
|
81
|
+
wasm.__externref_table_dealloc(idx);
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
function createCosignPubkey(vault_pubkey_hex, vault_claim_pubkey_hex, owner_pubkey_hex, vault_claim_height, open_claim_height, created_at_height, bitcoin_network) {
|
|
85
|
+
let deferred5_0;
|
|
86
|
+
let deferred5_1;
|
|
87
|
+
try {
|
|
88
|
+
const ptr0 = passStringToWasm0(vault_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
89
|
+
const len0 = WASM_VECTOR_LEN;
|
|
90
|
+
const ptr1 = passStringToWasm0(vault_claim_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
91
|
+
const len1 = WASM_VECTOR_LEN;
|
|
92
|
+
const ptr2 = passStringToWasm0(owner_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
93
|
+
const len2 = WASM_VECTOR_LEN;
|
|
94
|
+
const ret = wasm.createCosignPubkey(ptr0, len0, ptr1, len1, ptr2, len2, vault_claim_height, open_claim_height, created_at_height, bitcoin_network);
|
|
95
|
+
var ptr4 = ret[0];
|
|
96
|
+
var len4 = ret[1];
|
|
97
|
+
if (ret[3]) {
|
|
98
|
+
ptr4 = 0;
|
|
99
|
+
len4 = 0;
|
|
100
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
101
|
+
}
|
|
102
|
+
deferred5_0 = ptr4;
|
|
103
|
+
deferred5_1 = len4;
|
|
104
|
+
return getStringFromWasm0(ptr4, len4);
|
|
105
|
+
} finally {
|
|
106
|
+
wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function calculateFee(vault_pubkey_hex, vault_claim_pubkey_hex, owner_pubkey_hex, vault_claim_height, open_claim_height, created_at_height, bitcoin_network, fee_rate_sats_per_vb, to_script_pubkey) {
|
|
110
|
+
const ptr0 = passStringToWasm0(vault_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
111
|
+
const len0 = WASM_VECTOR_LEN;
|
|
112
|
+
const ptr1 = passStringToWasm0(vault_claim_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
113
|
+
const len1 = WASM_VECTOR_LEN;
|
|
114
|
+
const ptr2 = passStringToWasm0(owner_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
115
|
+
const len2 = WASM_VECTOR_LEN;
|
|
116
|
+
const ptr3 = passStringToWasm0(to_script_pubkey, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
117
|
+
const len3 = WASM_VECTOR_LEN;
|
|
118
|
+
const ret = wasm.calculateFee(ptr0, len0, ptr1, len1, ptr2, len2, vault_claim_height, open_claim_height, created_at_height, bitcoin_network, fee_rate_sats_per_vb, ptr3, len3);
|
|
119
|
+
if (ret[2]) {
|
|
120
|
+
throw takeFromExternrefTable0(ret[1]);
|
|
121
|
+
}
|
|
122
|
+
return BigInt.asUintN(64, ret[0]);
|
|
123
|
+
}
|
|
124
|
+
function signPsbtDerived(psbt_hex, xpriv_b58, xpriv_hd_path, finalize) {
|
|
125
|
+
let deferred5_0;
|
|
126
|
+
let deferred5_1;
|
|
127
|
+
try {
|
|
128
|
+
const ptr0 = passStringToWasm0(psbt_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
129
|
+
const len0 = WASM_VECTOR_LEN;
|
|
130
|
+
const ptr1 = passStringToWasm0(xpriv_b58, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
131
|
+
const len1 = WASM_VECTOR_LEN;
|
|
132
|
+
const ptr2 = passStringToWasm0(xpriv_hd_path, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
133
|
+
const len2 = WASM_VECTOR_LEN;
|
|
134
|
+
const ret = wasm.signPsbtDerived(ptr0, len0, ptr1, len1, ptr2, len2, finalize);
|
|
135
|
+
var ptr4 = ret[0];
|
|
136
|
+
var len4 = ret[1];
|
|
137
|
+
if (ret[3]) {
|
|
138
|
+
ptr4 = 0;
|
|
139
|
+
len4 = 0;
|
|
140
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
141
|
+
}
|
|
142
|
+
deferred5_0 = ptr4;
|
|
143
|
+
deferred5_1 = len4;
|
|
144
|
+
return getStringFromWasm0(ptr4, len4);
|
|
145
|
+
} finally {
|
|
146
|
+
wasm.__wbindgen_free(deferred5_0, deferred5_1, 1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function signPsbt(psbt_hex, bitcoin_network, private_key_hex, finalize) {
|
|
150
|
+
let deferred4_0;
|
|
151
|
+
let deferred4_1;
|
|
152
|
+
try {
|
|
153
|
+
const ptr0 = passStringToWasm0(psbt_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
154
|
+
const len0 = WASM_VECTOR_LEN;
|
|
155
|
+
const ptr1 = passStringToWasm0(private_key_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
156
|
+
const len1 = WASM_VECTOR_LEN;
|
|
157
|
+
const ret = wasm.signPsbt(ptr0, len0, bitcoin_network, ptr1, len1, finalize);
|
|
158
|
+
var ptr3 = ret[0];
|
|
159
|
+
var len3 = ret[1];
|
|
160
|
+
if (ret[3]) {
|
|
161
|
+
ptr3 = 0;
|
|
162
|
+
len3 = 0;
|
|
163
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
164
|
+
}
|
|
165
|
+
deferred4_0 = ptr3;
|
|
166
|
+
deferred4_1 = len3;
|
|
167
|
+
return getStringFromWasm0(ptr3, len3);
|
|
168
|
+
} finally {
|
|
169
|
+
wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function getCosignPsbt(txid, vout, satoshis, vault_pubkey_hex, vault_claim_pubkey_hex, owner_pubkey_hex, vault_claim_height, open_claim_height, created_at_height, bitcoin_network, to_script_pubkey_hex, bitcoin_network_fee) {
|
|
173
|
+
let deferred7_0;
|
|
174
|
+
let deferred7_1;
|
|
175
|
+
try {
|
|
176
|
+
const ptr0 = passStringToWasm0(txid, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
177
|
+
const len0 = WASM_VECTOR_LEN;
|
|
178
|
+
const ptr1 = passStringToWasm0(vault_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
179
|
+
const len1 = WASM_VECTOR_LEN;
|
|
180
|
+
const ptr2 = passStringToWasm0(vault_claim_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
181
|
+
const len2 = WASM_VECTOR_LEN;
|
|
182
|
+
const ptr3 = passStringToWasm0(owner_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
183
|
+
const len3 = WASM_VECTOR_LEN;
|
|
184
|
+
const ptr4 = passStringToWasm0(to_script_pubkey_hex, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
|
185
|
+
const len4 = WASM_VECTOR_LEN;
|
|
186
|
+
const ret = wasm.getCosignPsbt(ptr0, len0, vout, satoshis, ptr1, len1, ptr2, len2, ptr3, len3, vault_claim_height, open_claim_height, created_at_height, bitcoin_network, ptr4, len4, bitcoin_network_fee);
|
|
187
|
+
var ptr6 = ret[0];
|
|
188
|
+
var len6 = ret[1];
|
|
189
|
+
if (ret[3]) {
|
|
190
|
+
ptr6 = 0;
|
|
191
|
+
len6 = 0;
|
|
192
|
+
throw takeFromExternrefTable0(ret[2]);
|
|
193
|
+
}
|
|
194
|
+
deferred7_0 = ptr6;
|
|
195
|
+
deferred7_1 = len6;
|
|
196
|
+
return getStringFromWasm0(ptr6, len6);
|
|
197
|
+
} finally {
|
|
198
|
+
wasm.__wbindgen_free(deferred7_0, deferred7_1, 1);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
var BitcoinNetwork = Object.freeze({
|
|
202
|
+
/**
|
|
203
|
+
* Mainnet Bitcoin.
|
|
204
|
+
*/
|
|
205
|
+
Bitcoin: 0,
|
|
206
|
+
"0": "Bitcoin",
|
|
207
|
+
/**
|
|
208
|
+
* Bitcoin's testnet network.
|
|
209
|
+
*/
|
|
210
|
+
Testnet: 1,
|
|
211
|
+
"1": "Testnet",
|
|
212
|
+
/**
|
|
213
|
+
* Bitcoin's signet network
|
|
214
|
+
*/
|
|
215
|
+
Signet: 2,
|
|
216
|
+
"2": "Signet",
|
|
217
|
+
/**
|
|
218
|
+
* Bitcoin's regtest network.
|
|
219
|
+
*/
|
|
220
|
+
Regtest: 3,
|
|
221
|
+
"3": "Regtest"
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// ts/wasm/bitcoin_bindings.js
|
|
225
|
+
__wbg_set_wasm(bitcoin_bindings_bg_exports);
|
|
226
|
+
(void 0)();
|
|
227
|
+
|
|
228
|
+
// ts/KeysHelper.ts
|
|
229
|
+
import { address } from "bitcoinjs-lib";
|
|
230
|
+
import BIP32Factory from "bip32";
|
|
231
|
+
import * as ecc from "tiny-secp256k1";
|
|
232
|
+
import * as bip39 from "bip39";
|
|
233
|
+
function getChildXpriv(bip39Seed, hdPath, network) {
|
|
234
|
+
const root = BIP32Factory(ecc).fromSeed(bip39Seed, network);
|
|
235
|
+
return root.derivePath(hdPath);
|
|
236
|
+
}
|
|
237
|
+
function getBip39Seed(mnemonic, passphrase) {
|
|
238
|
+
return bip39.mnemonicToSeedSync(mnemonic, passphrase);
|
|
239
|
+
}
|
|
240
|
+
function getXpubFromXpriv(xpriv) {
|
|
241
|
+
return xpriv.neutered().toBase58();
|
|
242
|
+
}
|
|
243
|
+
function getCompressedPubkey(pubkey) {
|
|
244
|
+
const pubkeyBuffer = keyToBuffer(pubkey);
|
|
245
|
+
if (ecc.isPointCompressed(pubkeyBuffer)) {
|
|
246
|
+
return pubkeyBuffer;
|
|
247
|
+
}
|
|
248
|
+
return Buffer.from(ecc.pointCompress(pubkeyBuffer, true));
|
|
249
|
+
}
|
|
250
|
+
function stripLeadingHexPrefix(hex) {
|
|
251
|
+
if (hex.startsWith("0x")) {
|
|
252
|
+
return hex.slice(2);
|
|
253
|
+
}
|
|
254
|
+
return hex;
|
|
255
|
+
}
|
|
256
|
+
function addressBytesHex(addressString, network) {
|
|
257
|
+
if (addressString.startsWith("0x")) {
|
|
258
|
+
return addressString;
|
|
259
|
+
}
|
|
260
|
+
console.log("Converting address to bytes:", addressString, network);
|
|
261
|
+
if (/^[0-9a-fA-F]+$/.test(addressString) && !addressString.startsWith("bc")) {
|
|
262
|
+
return `0x${addressString}`;
|
|
263
|
+
}
|
|
264
|
+
const scriptbuf = address.toOutputScript(addressString, network);
|
|
265
|
+
return `0x${scriptbuf.toString("hex")}`;
|
|
266
|
+
}
|
|
267
|
+
function keyToBuffer(key) {
|
|
268
|
+
if (typeof key === "string") {
|
|
269
|
+
key = stripLeadingHexPrefix(key);
|
|
270
|
+
return Buffer.from(key, "hex");
|
|
271
|
+
}
|
|
272
|
+
return Buffer.from(key);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ts/CosignScript.ts
|
|
276
|
+
var CosignScript = class _CosignScript {
|
|
277
|
+
constructor(lock, network) {
|
|
278
|
+
this.lock = lock;
|
|
279
|
+
if (network === networks2.bitcoin || network === networks2.testnet || network === networks2.regtest) {
|
|
280
|
+
this.network = network;
|
|
281
|
+
} else {
|
|
282
|
+
this.network = _CosignScript.getBitcoinJsNetwork(
|
|
283
|
+
network
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
network;
|
|
288
|
+
getFundingPsbt() {
|
|
289
|
+
const { lock, network } = this;
|
|
290
|
+
return new Psbt({ network }).addOutput({
|
|
291
|
+
script: keyToBuffer(lock.p2wshScriptHashHex),
|
|
292
|
+
value: Number(lock.satoshis)
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
calculateFee(feeRatePerSatVb, toScriptPubkey) {
|
|
296
|
+
toScriptPubkey = addressBytesHex(toScriptPubkey, this.network);
|
|
297
|
+
const { lock, network } = this;
|
|
298
|
+
return calculateFee(
|
|
299
|
+
lock.vaultPubkey,
|
|
300
|
+
lock.vaultClaimPubkey,
|
|
301
|
+
lock.ownerPubkey,
|
|
302
|
+
BigInt(lock.vaultClaimHeight),
|
|
303
|
+
BigInt(lock.openClaimHeight),
|
|
304
|
+
BigInt(lock.createdAtHeight),
|
|
305
|
+
toBitcoinNetwork(network),
|
|
306
|
+
feeRatePerSatVb,
|
|
307
|
+
toScriptPubkey
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
calculateScriptPubkey() {
|
|
311
|
+
const { lock, network } = this;
|
|
312
|
+
return createCosignPubkey(
|
|
313
|
+
lock.vaultPubkey,
|
|
314
|
+
lock.vaultClaimPubkey,
|
|
315
|
+
lock.ownerPubkey,
|
|
316
|
+
BigInt(lock.vaultClaimHeight),
|
|
317
|
+
BigInt(lock.openClaimHeight),
|
|
318
|
+
BigInt(lock.createdAtHeight),
|
|
319
|
+
toBitcoinNetwork(network)
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
getCosignPsbt(args) {
|
|
323
|
+
const { lock, network } = this;
|
|
324
|
+
const { releaseRequest, utxoRef } = args;
|
|
325
|
+
releaseRequest.toScriptPubkey = addressBytesHex(releaseRequest.toScriptPubkey, network);
|
|
326
|
+
const psbtStr = getCosignPsbt(
|
|
327
|
+
utxoRef.txid,
|
|
328
|
+
utxoRef.vout,
|
|
329
|
+
lock.satoshis,
|
|
330
|
+
lock.vaultPubkey,
|
|
331
|
+
lock.vaultClaimPubkey,
|
|
332
|
+
lock.ownerPubkey,
|
|
333
|
+
BigInt(lock.vaultClaimHeight),
|
|
334
|
+
BigInt(lock.openClaimHeight),
|
|
335
|
+
BigInt(lock.createdAtHeight),
|
|
336
|
+
toBitcoinNetwork(network),
|
|
337
|
+
releaseRequest.toScriptPubkey,
|
|
338
|
+
releaseRequest.bitcoinNetworkFee
|
|
339
|
+
);
|
|
340
|
+
return this.psbtFromHex(psbtStr);
|
|
341
|
+
}
|
|
342
|
+
psbtFromHex(psbtHex) {
|
|
343
|
+
const psbt = Psbt.fromHex(psbtHex.replace(/^0x(.+)/, "$1"), { network: this.network });
|
|
344
|
+
if (psbt.data.inputs.length === 0) {
|
|
345
|
+
throw new Error("PSBT has no inputs");
|
|
346
|
+
}
|
|
347
|
+
if (psbt.data.outputs.length === 0) {
|
|
348
|
+
throw new Error("PSBT has no outputs");
|
|
349
|
+
}
|
|
350
|
+
return psbt;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Cosigns the PSBT with the vault xpub.
|
|
354
|
+
* @param psbt - The PSBT to cosign.
|
|
355
|
+
* @param lock - The Bitcoin lock containing the vault information.
|
|
356
|
+
* @param vaultXpriv - The vault's extended private key of which the xpub was used to create the vault.
|
|
357
|
+
*/
|
|
358
|
+
vaultCosignPsbt(psbt, lock, vaultXpriv) {
|
|
359
|
+
const parentFingerprint = Buffer.from(lock.vaultXpubSources.parentFingerprint);
|
|
360
|
+
if (!parentFingerprint.equals(vaultXpriv.fingerprint)) {
|
|
361
|
+
throw new Error(
|
|
362
|
+
`Vault xpub fingerprint ${parentFingerprint.toString("hex")} does not match the vault xpriv fingerprint ${vaultXpriv.fingerprint.toString("hex")}`
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
const childPath = `${lock.vaultXpubSources.cosignHdIndex}`;
|
|
366
|
+
const pubkey = vaultXpriv.derivePath(childPath).publicKey;
|
|
367
|
+
const vaultPubkey = keyToBuffer(lock.vaultPubkey);
|
|
368
|
+
if (!vaultPubkey.equals(pubkey)) {
|
|
369
|
+
throw new Error(
|
|
370
|
+
`Vault pubkey ${vaultPubkey.toString("hex")} does not match the derived pubkey ${pubkey.toString("hex")} using path ${childPath}`
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
const signedPsbt = signPsbtDerived(psbt.toHex(), vaultXpriv.toBase58(), childPath, false);
|
|
374
|
+
psbt = this.psbtFromHex(signedPsbt);
|
|
375
|
+
return psbt;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Cosigns the transaction.
|
|
379
|
+
*/
|
|
380
|
+
cosignAndGenerateTx(args) {
|
|
381
|
+
const { lock } = this;
|
|
382
|
+
const psbt = this.getCosignPsbt(args);
|
|
383
|
+
const { addTx, vaultCosignature, ownerXpriv, ownerXprivChildHdPath } = args;
|
|
384
|
+
psbt.updateInput(0, {
|
|
385
|
+
partialSig: [
|
|
386
|
+
{
|
|
387
|
+
pubkey: keyToBuffer(lock.vaultPubkey),
|
|
388
|
+
signature: Buffer.from(vaultCosignature)
|
|
389
|
+
}
|
|
390
|
+
]
|
|
391
|
+
});
|
|
392
|
+
const derivePubkey = ownerXpriv.publicKey;
|
|
393
|
+
const ownerPubkey = keyToBuffer(lock.ownerPubkey);
|
|
394
|
+
if (!ownerPubkey.equals(derivePubkey)) {
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Owner pubkey ${ownerPubkey.toString("hex")} does not match the derived pubkey ${derivePubkey.toString("hex")}`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (addTx) {
|
|
400
|
+
const tx = Transaction.fromHex(addTx.replace(/^0x(.+)/, "$1"));
|
|
401
|
+
for (let i = 0; i < tx.outs.length; i++) {
|
|
402
|
+
const output = tx.outs[i];
|
|
403
|
+
const scripts = [
|
|
404
|
+
payments.p2wpkh({ pubkey: ownerPubkey }).output,
|
|
405
|
+
payments.p2sh({ redeem: payments.p2wpkh({ pubkey: ownerPubkey }) }).output,
|
|
406
|
+
payments.p2pkh({ pubkey: ownerPubkey }).output
|
|
407
|
+
];
|
|
408
|
+
if (scripts.some((x) => x && output.script.equals(x))) {
|
|
409
|
+
psbt.addInput({
|
|
410
|
+
hash: tx.getId(),
|
|
411
|
+
index: i,
|
|
412
|
+
witnessUtxo: {
|
|
413
|
+
script: output.script,
|
|
414
|
+
value: output.value
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const signedPsbt = ownerXprivChildHdPath ? signPsbtDerived(psbt.toHex(), ownerXpriv.toBase58(), ownerXprivChildHdPath, true) : signPsbt(
|
|
421
|
+
psbt.toHex(),
|
|
422
|
+
toBitcoinNetwork(this.network),
|
|
423
|
+
ownerXpriv.privateKey.toString("hex"),
|
|
424
|
+
true
|
|
425
|
+
);
|
|
426
|
+
const finalPsbt = this.psbtFromHex(signedPsbt);
|
|
427
|
+
return finalPsbt.extractTransaction();
|
|
428
|
+
}
|
|
429
|
+
static getBitcoinJsNetwork(network) {
|
|
430
|
+
if (network.isBitcoin) return networks2.bitcoin;
|
|
431
|
+
if (network.isTestnet || network.isSignet) return networks2.testnet;
|
|
432
|
+
if (network.isRegtest) return networks2.regtest;
|
|
433
|
+
throw new Error("Unsupported network: " + network);
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
function toBitcoinNetwork(network) {
|
|
437
|
+
if (network === networks2.bitcoin) {
|
|
438
|
+
return BitcoinNetwork.Bitcoin;
|
|
439
|
+
} else if (network === networks2.testnet) {
|
|
440
|
+
return BitcoinNetwork.Testnet;
|
|
441
|
+
} else if (network === networks2.regtest) {
|
|
442
|
+
return BitcoinNetwork.Regtest;
|
|
443
|
+
}
|
|
444
|
+
throw new Error("Unsupported network: " + network);
|
|
445
|
+
}
|
|
446
|
+
export {
|
|
447
|
+
CosignScript,
|
|
448
|
+
addressBytesHex,
|
|
449
|
+
getBip39Seed,
|
|
450
|
+
getChildXpriv,
|
|
451
|
+
getCompressedPubkey,
|
|
452
|
+
getXpubFromXpriv,
|
|
453
|
+
keyToBuffer,
|
|
454
|
+
stripLeadingHexPrefix
|
|
455
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@argonprotocol/bitcoin",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "A client for interop with bitcoin in nodejs.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/argonprotocol/mainchain.git"
|
|
8
|
+
},
|
|
9
|
+
"author": "Argon Foundation",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/argonprotocol/mainchain/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/argonprotocol/mainchain#readme",
|
|
15
|
+
"scripts": {
|
|
16
|
+
"wasm-pack": "wasm-pack build --target bundler --release --out-dir ts/wasm --out-name bitcoin_bindings --no-pack --no-opt",
|
|
17
|
+
"prebuild": "yarn workspace @argonprotocol/mainchain run build",
|
|
18
|
+
"build": "yarn wasm-pack && yarn tsc",
|
|
19
|
+
"pretsc": "yarn workspace @argonprotocol/mainchain run tsc",
|
|
20
|
+
"tsc": "yarn pretsc && tsup",
|
|
21
|
+
"test": "yarn build && vitest --run --typecheck --disableConsoleIntercept",
|
|
22
|
+
"test:ci": "yarn tsc && vitest --run --disableConsoleIntercept",
|
|
23
|
+
"tsup": "yarn tsc"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"lib/"
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"bin": "./lib/cli.js",
|
|
30
|
+
"module": "./lib/index.js",
|
|
31
|
+
"types": "./lib/index.d.ts",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@argonprotocol/mainchain": "1.3.0",
|
|
34
|
+
"bignumber.js": "^9.1.2",
|
|
35
|
+
"bip32": "^4.0.0",
|
|
36
|
+
"bip39": "^3.1.0",
|
|
37
|
+
"bitcoinjs-lib": "^6.1.7",
|
|
38
|
+
"tiny-secp256k1": "^2.2.3"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@argonprotocol/testing": "1.3.0",
|
|
42
|
+
"tsup": "^8.4.0",
|
|
43
|
+
"tsx": "^4.19.2",
|
|
44
|
+
"typescript": "^5.8.3",
|
|
45
|
+
"vite-plugin-wasm": "^3.4.1",
|
|
46
|
+
"vitest": "^3.1.1",
|
|
47
|
+
"wasm-pack": "^0.13.1"
|
|
48
|
+
},
|
|
49
|
+
"packageManager": "yarn@4.1.0"
|
|
50
|
+
}
|