@btc-vision/bitcoin 6.3.5 → 6.4.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/.mocharc.json +13 -0
- package/browser/address.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/index.js.LICENSE.txt +3 -3
- package/browser/networks.d.ts +1 -0
- package/browser/psbt/psbtutils.d.ts +1 -1
- package/build/address.d.ts +1 -1
- package/build/address.js +12 -5
- package/build/block.js +2 -2
- package/build/bufferutils.js +5 -5
- package/build/networks.d.ts +1 -0
- package/build/networks.js +11 -0
- package/build/psbt/psbtutils.js +2 -2
- package/build/psbt.js +3 -7
- package/package.json +26 -26
- package/src/address.ts +20 -6
- package/src/block.ts +233 -233
- package/src/bufferutils.ts +188 -180
- package/src/index.ts +86 -86
- package/src/networks.ts +12 -0
- package/src/psbt/bip371.ts +441 -441
- package/src/psbt/psbtutils.ts +4 -3
- package/src/psbt.ts +2187 -2187
- package/test/address.spec.ts +155 -177
- package/test/bitcoin.core.spec.ts +212 -234
- package/test/block.spec.ts +171 -194
- package/test/bufferutils.spec.ts +450 -513
- package/test/crypto.spec.ts +49 -55
- package/test/fixtures/address.json +3 -3
- package/test/integration/addresses.spec.ts +142 -154
- package/test/integration/bip32.spec.ts +130 -151
- package/test/integration/blocks.spec.ts +28 -28
- package/test/integration/cltv.spec.ts +241 -283
- package/test/integration/csv.spec.ts +452 -527
- package/test/integration/payments.spec.ts +110 -135
- package/test/integration/taproot.spec.ts +663 -707
- package/test/integration/transactions.spec.ts +668 -769
- package/test/payments.spec.ts +114 -125
- package/test/payments.utils.ts +165 -208
- package/test/psbt.spec.ts +1285 -1414
- package/test/script.spec.ts +186 -210
- package/test/script_number.spec.ts +26 -29
- package/test/script_signature.spec.ts +66 -66
- package/test/transaction.spec.ts +337 -387
- package/test/ts-node-register.js +7 -5
- package/test/tsconfig.json +4 -1
- package/test/types.spec.ts +53 -58
- package/.nyc_output/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +0 -1
- package/.nyc_output/processinfo/6368a5b2-daa5-4821-8ed0-b742d6fc7eab.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/test/address.spec.js +0 -124
- package/test/bitcoin.core.spec.js +0 -170
- package/test/block.spec.js +0 -141
- package/test/bufferutils.spec.js +0 -427
- package/test/crypto.spec.js +0 -41
- package/test/integration/_regtest.js +0 -7
- package/test/integration/addresses.spec.js +0 -116
- package/test/integration/bip32.spec.js +0 -85
- package/test/integration/blocks.spec.js +0 -26
- package/test/integration/cltv.spec.js +0 -199
- package/test/integration/csv.spec.js +0 -362
- package/test/integration/payments.spec.js +0 -98
- package/test/integration/taproot.spec.js +0 -532
- package/test/integration/transactions.spec.js +0 -561
- package/test/payments.spec.js +0 -97
- package/test/payments.utils.js +0 -190
- package/test/psbt.spec.js +0 -1044
- package/test/script.spec.js +0 -151
- package/test/script_number.spec.js +0 -24
- package/test/script_signature.spec.js +0 -52
- package/test/transaction.spec.js +0 -269
- package/test/types.spec.js +0 -46
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const assert = require("assert");
|
|
4
|
-
const mocha_1 = require("mocha");
|
|
5
|
-
const bitcoin = require("../..");
|
|
6
|
-
(0, mocha_1.describe)('bitcoinjs-lib (blocks)', () => {
|
|
7
|
-
(0, mocha_1.it)('can extract a height from a CoinBase transaction', () => {
|
|
8
|
-
// from 00000000000000000097669cdca131f24d40c4cc7d80eaa65967a2d09acf6ce6
|
|
9
|
-
const txHex = '010000000001010000000000000000000000000000000000000000000000000000000' +
|
|
10
|
-
'000000000ffffffff50037f9a07174d696e656420627920416e74506f6f6c685b205a' +
|
|
11
|
-
'2b1f7bfabe6d6d36afe1910eca9405b66f97750940a656e38e2c0312958190ff8e98f' +
|
|
12
|
-
'd16761d220400000000000000aa340000d49f0000ffffffff02b07fc3660000000019' +
|
|
13
|
-
'76a9148349212dc27ce3ab4c5b29b85c4dec643d764b1788ac0000000000000000266' +
|
|
14
|
-
'a24aa21a9ed72d9432948505e3d3062f1307a3f027a5dea846ff85e47159680919c12' +
|
|
15
|
-
'bf1e40012000000000000000000000000000000000000000000000000000000000000' +
|
|
16
|
-
'0000000000000';
|
|
17
|
-
const tx = bitcoin.Transaction.fromHex(txHex);
|
|
18
|
-
assert.strictEqual(tx.ins.length, 1);
|
|
19
|
-
const script = tx.ins[0].script;
|
|
20
|
-
// bitcoin.script.decompile(script) // returns [] :(
|
|
21
|
-
assert.strictEqual(script[0], 0x03);
|
|
22
|
-
const heightBuffer = script.slice(1, 4);
|
|
23
|
-
const height = bitcoin.script.number.decode(heightBuffer);
|
|
24
|
-
assert.strictEqual(height, 498303);
|
|
25
|
-
});
|
|
26
|
-
});
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const assert = require("assert");
|
|
4
|
-
const ecpair_1 = require("ecpair");
|
|
5
|
-
const ecc = require("tiny-secp256k1");
|
|
6
|
-
const mocha_1 = require("mocha");
|
|
7
|
-
const bitcoin = require("../..");
|
|
8
|
-
const _regtest_1 = require("./_regtest");
|
|
9
|
-
const ECPair = (0, ecpair_1.default)(ecc);
|
|
10
|
-
const regtest = _regtest_1.regtestUtils.network;
|
|
11
|
-
const bip65 = require('bip65');
|
|
12
|
-
function toOutputScript(address) {
|
|
13
|
-
return bitcoin.address.toOutputScript(address, regtest);
|
|
14
|
-
}
|
|
15
|
-
function idToHash(txid) {
|
|
16
|
-
return Buffer.from(txid, 'hex').reverse();
|
|
17
|
-
}
|
|
18
|
-
const alice = ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest);
|
|
19
|
-
const bob = ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest);
|
|
20
|
-
(0, mocha_1.describe)('bitcoinjs-lib (transactions w/ CLTV)', () => {
|
|
21
|
-
// force update MTP
|
|
22
|
-
(0, mocha_1.before)(async () => {
|
|
23
|
-
await _regtest_1.regtestUtils.mine(11);
|
|
24
|
-
});
|
|
25
|
-
const hashType = bitcoin.Transaction.SIGHASH_ALL;
|
|
26
|
-
function cltvCheckSigOutput(aQ, bQ, lockTime) {
|
|
27
|
-
return bitcoin.script.fromASM(`
|
|
28
|
-
OP_IF
|
|
29
|
-
${bitcoin.script.number.encode(lockTime).toString('hex')}
|
|
30
|
-
OP_CHECKLOCKTIMEVERIFY
|
|
31
|
-
OP_DROP
|
|
32
|
-
OP_ELSE
|
|
33
|
-
${bQ.publicKey.toString('hex')}
|
|
34
|
-
OP_CHECKSIGVERIFY
|
|
35
|
-
OP_ENDIF
|
|
36
|
-
${aQ.publicKey.toString('hex')}
|
|
37
|
-
OP_CHECKSIG
|
|
38
|
-
`
|
|
39
|
-
.trim()
|
|
40
|
-
.replace(/\s+/g, ' '));
|
|
41
|
-
}
|
|
42
|
-
function utcNow() {
|
|
43
|
-
return Math.floor(Date.now() / 1000);
|
|
44
|
-
}
|
|
45
|
-
// expiry past, {Alice's signature} OP_TRUE
|
|
46
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Alice can redeem ' +
|
|
47
|
-
'the output after the expiry (in the past)', async () => {
|
|
48
|
-
// 3 hours ago
|
|
49
|
-
const lockTime = bip65.encode({ utc: utcNow() - 3600 * 3 });
|
|
50
|
-
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
|
|
51
|
-
const { address } = bitcoin.payments.p2sh({
|
|
52
|
-
redeem: { output: redeemScript, network: regtest },
|
|
53
|
-
network: regtest,
|
|
54
|
-
});
|
|
55
|
-
// fund the P2SH(CLTV) address
|
|
56
|
-
const unspent = await _regtest_1.regtestUtils.faucet(address, 1e5);
|
|
57
|
-
const tx = new bitcoin.Transaction();
|
|
58
|
-
tx.locktime = lockTime;
|
|
59
|
-
// Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail.
|
|
60
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
|
|
61
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 7e4);
|
|
62
|
-
// {Alice's signature} OP_TRUE
|
|
63
|
-
const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
|
|
64
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
65
|
-
redeem: {
|
|
66
|
-
input: bitcoin.script.compile([
|
|
67
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
68
|
-
bitcoin.opcodes.OP_TRUE,
|
|
69
|
-
]),
|
|
70
|
-
output: redeemScript,
|
|
71
|
-
},
|
|
72
|
-
}).input;
|
|
73
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
74
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
75
|
-
await _regtest_1.regtestUtils.verify({
|
|
76
|
-
txId: tx.getId(),
|
|
77
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
78
|
-
vout: 0,
|
|
79
|
-
value: 7e4,
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
// expiry will pass, {Alice's signature} OP_TRUE
|
|
83
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Alice can redeem ' +
|
|
84
|
-
'the output after the expiry (in the future)', async () => {
|
|
85
|
-
const height = await _regtest_1.regtestUtils.height();
|
|
86
|
-
// 5 blocks from now
|
|
87
|
-
const lockTime = bip65.encode({ blocks: height + 5 });
|
|
88
|
-
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
|
|
89
|
-
const { address } = bitcoin.payments.p2sh({
|
|
90
|
-
redeem: { output: redeemScript, network: regtest },
|
|
91
|
-
network: regtest,
|
|
92
|
-
});
|
|
93
|
-
// fund the P2SH(CLTV) address
|
|
94
|
-
const unspent = await _regtest_1.regtestUtils.faucet(address, 1e5);
|
|
95
|
-
const tx = new bitcoin.Transaction();
|
|
96
|
-
tx.locktime = lockTime;
|
|
97
|
-
// Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail.
|
|
98
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
|
|
99
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 7e4);
|
|
100
|
-
// {Alice's signature} OP_TRUE
|
|
101
|
-
const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
|
|
102
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
103
|
-
redeem: {
|
|
104
|
-
input: bitcoin.script.compile([
|
|
105
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
106
|
-
bitcoin.opcodes.OP_TRUE,
|
|
107
|
-
]),
|
|
108
|
-
output: redeemScript,
|
|
109
|
-
},
|
|
110
|
-
}).input;
|
|
111
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
112
|
-
// TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
|
|
113
|
-
// ...
|
|
114
|
-
// into the future!
|
|
115
|
-
await _regtest_1.regtestUtils.mine(5);
|
|
116
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
117
|
-
await _regtest_1.regtestUtils.verify({
|
|
118
|
-
txId: tx.getId(),
|
|
119
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
120
|
-
vout: 0,
|
|
121
|
-
value: 7e4,
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
// expiry ignored, {Bob's signature} {Alice's signature} OP_FALSE
|
|
125
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Alice and Bob can ' +
|
|
126
|
-
'redeem the output at any time', async () => {
|
|
127
|
-
// two hours ago
|
|
128
|
-
const lockTime = bip65.encode({ utc: utcNow() - 3600 * 2 });
|
|
129
|
-
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
|
|
130
|
-
const { address } = bitcoin.payments.p2sh({
|
|
131
|
-
redeem: { output: redeemScript, network: regtest },
|
|
132
|
-
network: regtest,
|
|
133
|
-
});
|
|
134
|
-
// fund the P2SH(CLTV) address
|
|
135
|
-
const unspent = await _regtest_1.regtestUtils.faucet(address, 2e5);
|
|
136
|
-
const tx = new bitcoin.Transaction();
|
|
137
|
-
tx.locktime = lockTime;
|
|
138
|
-
// Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail.
|
|
139
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
|
|
140
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 8e4);
|
|
141
|
-
// {Alice's signature} {Bob's signature} OP_FALSE
|
|
142
|
-
const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
|
|
143
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
144
|
-
redeem: {
|
|
145
|
-
input: bitcoin.script.compile([
|
|
146
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
147
|
-
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
|
148
|
-
bitcoin.opcodes.OP_FALSE,
|
|
149
|
-
]),
|
|
150
|
-
output: redeemScript,
|
|
151
|
-
},
|
|
152
|
-
}).input;
|
|
153
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
154
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
155
|
-
await _regtest_1.regtestUtils.verify({
|
|
156
|
-
txId: tx.getId(),
|
|
157
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
158
|
-
vout: 0,
|
|
159
|
-
value: 8e4,
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
// expiry in the future, {Alice's signature} OP_TRUE
|
|
163
|
-
(0, mocha_1.it)('can create (but fail to broadcast via 3PBP) a Transaction where Alice ' +
|
|
164
|
-
'attempts to redeem before the expiry', async () => {
|
|
165
|
-
// two hours from now
|
|
166
|
-
const lockTime = bip65.encode({ utc: utcNow() + 3600 * 2 });
|
|
167
|
-
const redeemScript = cltvCheckSigOutput(alice, bob, lockTime);
|
|
168
|
-
const { address } = bitcoin.payments.p2sh({
|
|
169
|
-
redeem: { output: redeemScript, network: regtest },
|
|
170
|
-
network: regtest,
|
|
171
|
-
});
|
|
172
|
-
// fund the P2SH(CLTV) address
|
|
173
|
-
const unspent = await _regtest_1.regtestUtils.faucet(address, 2e4);
|
|
174
|
-
const tx = new bitcoin.Transaction();
|
|
175
|
-
tx.locktime = lockTime;
|
|
176
|
-
// Note: nSequence MUST be <= 0xfffffffe otherwise OP_CHECKLOCKTIMEVERIFY will fail.
|
|
177
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, 0xfffffffe);
|
|
178
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 1e4);
|
|
179
|
-
// {Alice's signature} OP_TRUE
|
|
180
|
-
const signatureHash = tx.hashForSignature(0, redeemScript, hashType);
|
|
181
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
182
|
-
redeem: {
|
|
183
|
-
input: bitcoin.script.compile([
|
|
184
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
185
|
-
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
|
186
|
-
bitcoin.opcodes.OP_TRUE,
|
|
187
|
-
]),
|
|
188
|
-
output: redeemScript,
|
|
189
|
-
},
|
|
190
|
-
}).input;
|
|
191
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
192
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex()).catch(err => {
|
|
193
|
-
assert.throws(() => {
|
|
194
|
-
if (err)
|
|
195
|
-
throw err;
|
|
196
|
-
}, /Error: non-final/);
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
});
|
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const assert = require("assert");
|
|
4
|
-
const ecpair_1 = require("ecpair");
|
|
5
|
-
const ecc = require("tiny-secp256k1");
|
|
6
|
-
const mocha_1 = require("mocha");
|
|
7
|
-
const bitcoin = require("../..");
|
|
8
|
-
const _regtest_1 = require("./_regtest");
|
|
9
|
-
const ECPair = (0, ecpair_1.default)(ecc);
|
|
10
|
-
const regtest = _regtest_1.regtestUtils.network;
|
|
11
|
-
const bip68 = require('bip68');
|
|
12
|
-
const varuint = require('varuint-bitcoin');
|
|
13
|
-
function toOutputScript(address) {
|
|
14
|
-
return bitcoin.address.toOutputScript(address, regtest);
|
|
15
|
-
}
|
|
16
|
-
function idToHash(txid) {
|
|
17
|
-
return Buffer.from(txid, 'hex').reverse();
|
|
18
|
-
}
|
|
19
|
-
const alice = ECPair.fromWIF('cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe', regtest);
|
|
20
|
-
const bob = ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x', regtest);
|
|
21
|
-
const charles = ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsMSb4Ubnf', regtest);
|
|
22
|
-
const dave = ECPair.fromWIF('cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsMwS4pqnx', regtest);
|
|
23
|
-
(0, mocha_1.describe)('bitcoinjs-lib (transactions w/ CSV)', () => {
|
|
24
|
-
// force update MTP
|
|
25
|
-
(0, mocha_1.before)(async () => {
|
|
26
|
-
await _regtest_1.regtestUtils.mine(11);
|
|
27
|
-
});
|
|
28
|
-
const hashType = bitcoin.Transaction.SIGHASH_ALL;
|
|
29
|
-
// IF MTP (from when confirmed) > seconds, _alice can redeem
|
|
30
|
-
function csvCheckSigOutput(_alice, _bob, sequence) {
|
|
31
|
-
return bitcoin.script.fromASM(`
|
|
32
|
-
OP_IF
|
|
33
|
-
${bitcoin.script.number.encode(sequence).toString('hex')}
|
|
34
|
-
OP_CHECKSEQUENCEVERIFY
|
|
35
|
-
OP_DROP
|
|
36
|
-
OP_ELSE
|
|
37
|
-
${_bob.publicKey.toString('hex')}
|
|
38
|
-
OP_CHECKSIGVERIFY
|
|
39
|
-
OP_ENDIF
|
|
40
|
-
${_alice.publicKey.toString('hex')}
|
|
41
|
-
OP_CHECKSIG
|
|
42
|
-
`
|
|
43
|
-
.trim()
|
|
44
|
-
.replace(/\s+/g, ' '));
|
|
45
|
-
}
|
|
46
|
-
// 2 of 3 multisig of _bob, _charles, _dave,
|
|
47
|
-
// but after sequence1 time, _alice can allow the multisig to become 1 of 3.
|
|
48
|
-
// but after sequence2 time, _alice can sign for the output all by themself.
|
|
49
|
-
// Ref: https://github.com/bitcoinbook/bitcoinbook/blob/f8b883dcd4e3d1b9adf40fed59b7e898fbd9241f/ch07.asciidoc#complex-script-example
|
|
50
|
-
// Note: bitcoinjs-lib will not offer specific support for problems with
|
|
51
|
-
// advanced script usages such as below. Use at your own risk.
|
|
52
|
-
function complexCsvOutput(_alice, _bob, _charles, _dave, sequence1, sequence2) {
|
|
53
|
-
return bitcoin.script.fromASM(`
|
|
54
|
-
OP_IF
|
|
55
|
-
OP_IF
|
|
56
|
-
OP_2
|
|
57
|
-
OP_ELSE
|
|
58
|
-
${bitcoin.script.number.encode(sequence1).toString('hex')}
|
|
59
|
-
OP_CHECKSEQUENCEVERIFY
|
|
60
|
-
OP_DROP
|
|
61
|
-
${_alice.publicKey.toString('hex')}
|
|
62
|
-
OP_CHECKSIGVERIFY
|
|
63
|
-
OP_1
|
|
64
|
-
OP_ENDIF
|
|
65
|
-
${_bob.publicKey.toString('hex')}
|
|
66
|
-
${_charles.publicKey.toString('hex')}
|
|
67
|
-
${_dave.publicKey.toString('hex')}
|
|
68
|
-
OP_3
|
|
69
|
-
OP_CHECKMULTISIG
|
|
70
|
-
OP_ELSE
|
|
71
|
-
${bitcoin.script.number.encode(sequence2).toString('hex')}
|
|
72
|
-
OP_CHECKSEQUENCEVERIFY
|
|
73
|
-
OP_DROP
|
|
74
|
-
${_alice.publicKey.toString('hex')}
|
|
75
|
-
OP_CHECKSIG
|
|
76
|
-
OP_ENDIF
|
|
77
|
-
`
|
|
78
|
-
.trim()
|
|
79
|
-
.replace(/\s+/g, ' '));
|
|
80
|
-
}
|
|
81
|
-
// expiry will pass, {Alice's signature} OP_TRUE
|
|
82
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Alice can redeem ' +
|
|
83
|
-
'the output after the expiry (in the future) (simple CHECKSEQUENCEVERIFY)', async () => {
|
|
84
|
-
// 5 blocks from now
|
|
85
|
-
const sequence = bip68.encode({ blocks: 5 });
|
|
86
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
87
|
-
redeem: {
|
|
88
|
-
output: csvCheckSigOutput(alice, bob, sequence),
|
|
89
|
-
},
|
|
90
|
-
network: regtest,
|
|
91
|
-
});
|
|
92
|
-
// fund the P2SH(CSV) address
|
|
93
|
-
const unspent = await _regtest_1.regtestUtils.faucet(p2sh.address, 1e5);
|
|
94
|
-
const utx = await _regtest_1.regtestUtils.fetch(unspent.txId);
|
|
95
|
-
// for non segwit inputs, you must pass the full transaction buffer
|
|
96
|
-
const nonWitnessUtxo = Buffer.from(utx.txHex, 'hex');
|
|
97
|
-
// This is an example of using the finalizeInput second parameter to
|
|
98
|
-
// define how you finalize the inputs, allowing for any type of script.
|
|
99
|
-
const tx = new bitcoin.Psbt({ network: regtest })
|
|
100
|
-
.setVersion(2)
|
|
101
|
-
.addInput({
|
|
102
|
-
hash: unspent.txId,
|
|
103
|
-
index: unspent.vout,
|
|
104
|
-
sequence,
|
|
105
|
-
redeemScript: p2sh.redeem.output,
|
|
106
|
-
nonWitnessUtxo,
|
|
107
|
-
})
|
|
108
|
-
.addOutput({
|
|
109
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
110
|
-
value: 7e4,
|
|
111
|
-
})
|
|
112
|
-
.signInput(0, alice)
|
|
113
|
-
.finalizeInput(0, csvGetFinalScripts) // See csvGetFinalScripts below
|
|
114
|
-
.extractTransaction();
|
|
115
|
-
// TODO: test that it failures _prior_ to expiry, unfortunately, race conditions when run concurrently
|
|
116
|
-
// ...
|
|
117
|
-
// into the future!
|
|
118
|
-
await _regtest_1.regtestUtils.mine(10);
|
|
119
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
120
|
-
await _regtest_1.regtestUtils.verify({
|
|
121
|
-
txId: tx.getId(),
|
|
122
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
123
|
-
vout: 0,
|
|
124
|
-
value: 7e4,
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
// expiry in the future, {Alice's signature} OP_TRUE
|
|
128
|
-
(0, mocha_1.it)('can create (but fail to broadcast via 3PBP) a Transaction where Alice ' +
|
|
129
|
-
'attempts to redeem before the expiry (simple CHECKSEQUENCEVERIFY)', async () => {
|
|
130
|
-
// two hours after confirmation
|
|
131
|
-
const sequence = bip68.encode({ seconds: 7168 });
|
|
132
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
133
|
-
network: regtest,
|
|
134
|
-
redeem: {
|
|
135
|
-
output: csvCheckSigOutput(alice, bob, sequence),
|
|
136
|
-
},
|
|
137
|
-
});
|
|
138
|
-
// fund the P2SH(CSV) address
|
|
139
|
-
const unspent = await _regtest_1.regtestUtils.faucet(p2sh.address, 2e4);
|
|
140
|
-
const tx = new bitcoin.Transaction();
|
|
141
|
-
tx.version = 2;
|
|
142
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, sequence);
|
|
143
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 1e4);
|
|
144
|
-
// {Alice's signature} OP_TRUE
|
|
145
|
-
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType);
|
|
146
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
147
|
-
network: regtest,
|
|
148
|
-
redeem: {
|
|
149
|
-
network: regtest,
|
|
150
|
-
output: p2sh.redeem.output,
|
|
151
|
-
input: bitcoin.script.compile([
|
|
152
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
153
|
-
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
|
154
|
-
bitcoin.opcodes.OP_TRUE,
|
|
155
|
-
]),
|
|
156
|
-
},
|
|
157
|
-
}).input;
|
|
158
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
159
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex()).catch(err => {
|
|
160
|
-
assert.throws(() => {
|
|
161
|
-
if (err)
|
|
162
|
-
throw err;
|
|
163
|
-
}, /Error: non-BIP68-final/);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
// Check first combination of complex CSV, 2 of 3
|
|
167
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Bob and Charles ' +
|
|
168
|
-
'can send (complex CHECKSEQUENCEVERIFY)', async () => {
|
|
169
|
-
// 2 blocks from now
|
|
170
|
-
const sequence1 = bip68.encode({ blocks: 2 });
|
|
171
|
-
// 5 blocks from now
|
|
172
|
-
const sequence2 = bip68.encode({ blocks: 5 });
|
|
173
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
174
|
-
redeem: {
|
|
175
|
-
output: complexCsvOutput(alice, bob, charles, dave, sequence1, sequence2),
|
|
176
|
-
},
|
|
177
|
-
network: regtest,
|
|
178
|
-
});
|
|
179
|
-
// fund the P2SH(CCSV) address
|
|
180
|
-
const unspent = await _regtest_1.regtestUtils.faucet(p2sh.address, 1e5);
|
|
181
|
-
const tx = new bitcoin.Transaction();
|
|
182
|
-
tx.version = 2;
|
|
183
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout);
|
|
184
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 7e4);
|
|
185
|
-
// OP_0 {Bob sig} {Charles sig} OP_TRUE OP_TRUE
|
|
186
|
-
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType);
|
|
187
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
188
|
-
network: regtest,
|
|
189
|
-
redeem: {
|
|
190
|
-
network: regtest,
|
|
191
|
-
output: p2sh.redeem.output,
|
|
192
|
-
input: bitcoin.script.compile([
|
|
193
|
-
bitcoin.opcodes.OP_0,
|
|
194
|
-
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
|
195
|
-
bitcoin.script.signature.encode(charles.sign(signatureHash), hashType),
|
|
196
|
-
bitcoin.opcodes.OP_TRUE,
|
|
197
|
-
bitcoin.opcodes.OP_TRUE,
|
|
198
|
-
]),
|
|
199
|
-
},
|
|
200
|
-
}).input;
|
|
201
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
202
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
203
|
-
await _regtest_1.regtestUtils.verify({
|
|
204
|
-
txId: tx.getId(),
|
|
205
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
206
|
-
vout: 0,
|
|
207
|
-
value: 7e4,
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
// Check first combination of complex CSV, mediator + 1 of 3 after 2 blocks
|
|
211
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Alice (mediator) ' +
|
|
212
|
-
'and Bob can send after 2 blocks (complex CHECKSEQUENCEVERIFY)', async () => {
|
|
213
|
-
// 2 blocks from now
|
|
214
|
-
const sequence1 = bip68.encode({ blocks: 2 });
|
|
215
|
-
// 5 blocks from now
|
|
216
|
-
const sequence2 = bip68.encode({ blocks: 5 });
|
|
217
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
218
|
-
redeem: {
|
|
219
|
-
output: complexCsvOutput(alice, bob, charles, dave, sequence1, sequence2),
|
|
220
|
-
},
|
|
221
|
-
network: regtest,
|
|
222
|
-
});
|
|
223
|
-
// fund the P2SH(CCSV) address
|
|
224
|
-
const unspent = await _regtest_1.regtestUtils.faucet(p2sh.address, 1e5);
|
|
225
|
-
const tx = new bitcoin.Transaction();
|
|
226
|
-
tx.version = 2;
|
|
227
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, sequence1); // Set sequence1 for input
|
|
228
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 7e4);
|
|
229
|
-
// OP_0 {Bob sig} {Alice mediator sig} OP_FALSE OP_TRUE
|
|
230
|
-
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType);
|
|
231
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
232
|
-
network: regtest,
|
|
233
|
-
redeem: {
|
|
234
|
-
network: regtest,
|
|
235
|
-
output: p2sh.redeem.output,
|
|
236
|
-
input: bitcoin.script.compile([
|
|
237
|
-
bitcoin.opcodes.OP_0,
|
|
238
|
-
bitcoin.script.signature.encode(bob.sign(signatureHash), hashType),
|
|
239
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
240
|
-
bitcoin.opcodes.OP_0,
|
|
241
|
-
bitcoin.opcodes.OP_TRUE,
|
|
242
|
-
]),
|
|
243
|
-
},
|
|
244
|
-
}).input;
|
|
245
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
246
|
-
// Wait 2 blocks
|
|
247
|
-
await _regtest_1.regtestUtils.mine(2);
|
|
248
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
249
|
-
await _regtest_1.regtestUtils.verify({
|
|
250
|
-
txId: tx.getId(),
|
|
251
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
252
|
-
vout: 0,
|
|
253
|
-
value: 7e4,
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
// Check first combination of complex CSV, mediator after 5 blocks
|
|
257
|
-
(0, mocha_1.it)('can create (and broadcast via 3PBP) a Transaction where Alice (mediator) ' +
|
|
258
|
-
'can send after 5 blocks (complex CHECKSEQUENCEVERIFY)', async () => {
|
|
259
|
-
// 2 blocks from now
|
|
260
|
-
const sequence1 = bip68.encode({ blocks: 2 });
|
|
261
|
-
// 5 blocks from now
|
|
262
|
-
const sequence2 = bip68.encode({ blocks: 5 });
|
|
263
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
264
|
-
redeem: {
|
|
265
|
-
output: complexCsvOutput(alice, bob, charles, dave, sequence1, sequence2),
|
|
266
|
-
},
|
|
267
|
-
network: regtest,
|
|
268
|
-
});
|
|
269
|
-
// fund the P2SH(CCSV) address
|
|
270
|
-
const unspent = await _regtest_1.regtestUtils.faucet(p2sh.address, 1e5);
|
|
271
|
-
const tx = new bitcoin.Transaction();
|
|
272
|
-
tx.version = 2;
|
|
273
|
-
tx.addInput(idToHash(unspent.txId), unspent.vout, sequence2); // Set sequence2 for input
|
|
274
|
-
tx.addOutput(toOutputScript(_regtest_1.regtestUtils.RANDOM_ADDRESS), 7e4);
|
|
275
|
-
// {Alice mediator sig} OP_FALSE
|
|
276
|
-
const signatureHash = tx.hashForSignature(0, p2sh.redeem.output, hashType);
|
|
277
|
-
const redeemScriptSig = bitcoin.payments.p2sh({
|
|
278
|
-
network: regtest,
|
|
279
|
-
redeem: {
|
|
280
|
-
network: regtest,
|
|
281
|
-
output: p2sh.redeem.output,
|
|
282
|
-
input: bitcoin.script.compile([
|
|
283
|
-
bitcoin.script.signature.encode(alice.sign(signatureHash), hashType),
|
|
284
|
-
bitcoin.opcodes.OP_0,
|
|
285
|
-
]),
|
|
286
|
-
},
|
|
287
|
-
}).input;
|
|
288
|
-
tx.setInputScript(0, redeemScriptSig);
|
|
289
|
-
// Wait 5 blocks
|
|
290
|
-
await _regtest_1.regtestUtils.mine(5);
|
|
291
|
-
await _regtest_1.regtestUtils.broadcast(tx.toHex());
|
|
292
|
-
await _regtest_1.regtestUtils.verify({
|
|
293
|
-
txId: tx.getId(),
|
|
294
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
295
|
-
vout: 0,
|
|
296
|
-
value: 7e4,
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
});
|
|
300
|
-
// This function is used to finalize a CSV transaction using PSBT.
|
|
301
|
-
// See first test above.
|
|
302
|
-
function csvGetFinalScripts(inputIndex, input, script, isSegwit, isP2SH, isP2WSH) {
|
|
303
|
-
// Step 1: Check to make sure the meaningful script matches what you expect.
|
|
304
|
-
const decompiled = bitcoin.script.decompile(script);
|
|
305
|
-
// Checking if first OP is OP_IF... should do better check in production!
|
|
306
|
-
// You may even want to check the public keys in the script against a
|
|
307
|
-
// whitelist depending on the circumstances!!!
|
|
308
|
-
// You also want to check the contents of the input to see if you have enough
|
|
309
|
-
// info to actually construct the scriptSig and Witnesses.
|
|
310
|
-
if (!decompiled || decompiled[0] !== bitcoin.opcodes.OP_IF) {
|
|
311
|
-
throw new Error(`Can not finalize input #${inputIndex}`);
|
|
312
|
-
}
|
|
313
|
-
// Step 2: Create final scripts
|
|
314
|
-
let payment = {
|
|
315
|
-
network: regtest,
|
|
316
|
-
output: script,
|
|
317
|
-
// This logic should be more strict and make sure the pubkeys in the
|
|
318
|
-
// meaningful script are the ones signing in the PSBT etc.
|
|
319
|
-
input: bitcoin.script.compile([
|
|
320
|
-
input.partialSig[0].signature,
|
|
321
|
-
bitcoin.opcodes.OP_TRUE,
|
|
322
|
-
]),
|
|
323
|
-
};
|
|
324
|
-
if (isP2WSH && isSegwit)
|
|
325
|
-
payment = bitcoin.payments.p2wsh({
|
|
326
|
-
network: regtest,
|
|
327
|
-
redeem: payment,
|
|
328
|
-
});
|
|
329
|
-
if (isP2SH)
|
|
330
|
-
payment = bitcoin.payments.p2sh({
|
|
331
|
-
network: regtest,
|
|
332
|
-
redeem: payment,
|
|
333
|
-
});
|
|
334
|
-
function witnessStackToScriptWitness(witness) {
|
|
335
|
-
let buffer = Buffer.allocUnsafe(0);
|
|
336
|
-
function writeSlice(slice) {
|
|
337
|
-
buffer = Buffer.concat([buffer, Buffer.from(slice)]);
|
|
338
|
-
}
|
|
339
|
-
function writeVarInt(i) {
|
|
340
|
-
const currentLen = buffer.length;
|
|
341
|
-
const varintLen = varuint.encodingLength(i);
|
|
342
|
-
buffer = Buffer.concat([buffer, Buffer.allocUnsafe(varintLen)]);
|
|
343
|
-
varuint.encode(i, buffer, currentLen);
|
|
344
|
-
}
|
|
345
|
-
function writeVarSlice(slice) {
|
|
346
|
-
writeVarInt(slice.length);
|
|
347
|
-
writeSlice(slice);
|
|
348
|
-
}
|
|
349
|
-
function writeVector(vector) {
|
|
350
|
-
writeVarInt(vector.length);
|
|
351
|
-
vector.forEach(writeVarSlice);
|
|
352
|
-
}
|
|
353
|
-
writeVector(witness);
|
|
354
|
-
return buffer;
|
|
355
|
-
}
|
|
356
|
-
return {
|
|
357
|
-
finalScriptSig: payment.input,
|
|
358
|
-
finalScriptWitness: payment.witness && payment.witness.length > 0
|
|
359
|
-
? witnessStackToScriptWitness(payment.witness)
|
|
360
|
-
: undefined,
|
|
361
|
-
};
|
|
362
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const ecpair_1 = require("ecpair");
|
|
4
|
-
const ecc = require("tiny-secp256k1");
|
|
5
|
-
const mocha_1 = require("mocha");
|
|
6
|
-
const bitcoin = require("../..");
|
|
7
|
-
const _regtest_1 = require("./_regtest");
|
|
8
|
-
const ECPair = (0, ecpair_1.default)(ecc);
|
|
9
|
-
const NETWORK = _regtest_1.regtestUtils.network;
|
|
10
|
-
const keyPairs = [
|
|
11
|
-
ECPair.makeRandom({ network: NETWORK }),
|
|
12
|
-
ECPair.makeRandom({ network: NETWORK }),
|
|
13
|
-
];
|
|
14
|
-
async function buildAndSign(depends, prevOutput, redeemScript, witnessScript) {
|
|
15
|
-
const unspent = await _regtest_1.regtestUtils.faucetComplex(prevOutput, 5e4);
|
|
16
|
-
const utx = await _regtest_1.regtestUtils.fetch(unspent.txId);
|
|
17
|
-
const psbt = new bitcoin.Psbt({ network: NETWORK })
|
|
18
|
-
.addInput({
|
|
19
|
-
hash: unspent.txId,
|
|
20
|
-
index: unspent.vout,
|
|
21
|
-
nonWitnessUtxo: Buffer.from(utx.txHex, 'hex'),
|
|
22
|
-
...(redeemScript ? { redeemScript } : {}),
|
|
23
|
-
...(witnessScript ? { witnessScript } : {}),
|
|
24
|
-
})
|
|
25
|
-
.addOutput({
|
|
26
|
-
address: _regtest_1.regtestUtils.RANDOM_ADDRESS,
|
|
27
|
-
value: 2e4,
|
|
28
|
-
});
|
|
29
|
-
if (depends.signatures) {
|
|
30
|
-
keyPairs.forEach(keyPair => {
|
|
31
|
-
psbt.signInput(0, keyPair);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
else if (depends.signature) {
|
|
35
|
-
psbt.signInput(0, keyPairs[0]);
|
|
36
|
-
}
|
|
37
|
-
return _regtest_1.regtestUtils.broadcast(psbt.finalizeAllInputs().extractTransaction().toHex());
|
|
38
|
-
}
|
|
39
|
-
['p2ms', 'p2pk', 'p2pkh', 'p2wpkh'].forEach(k => {
|
|
40
|
-
const fixtures = require('../fixtures/' + k);
|
|
41
|
-
const { depends } = fixtures.dynamic;
|
|
42
|
-
const fn = bitcoin.payments[k];
|
|
43
|
-
const base = {};
|
|
44
|
-
if (depends.pubkey)
|
|
45
|
-
base.pubkey = keyPairs[0].publicKey;
|
|
46
|
-
if (depends.pubkeys)
|
|
47
|
-
base.pubkeys = keyPairs.map(x => x.publicKey);
|
|
48
|
-
if (depends.m)
|
|
49
|
-
base.m = base.pubkeys.length;
|
|
50
|
-
const { output } = fn(base);
|
|
51
|
-
if (!output)
|
|
52
|
-
throw new TypeError('Missing output');
|
|
53
|
-
(0, mocha_1.describe)('bitcoinjs-lib (payments - ' + k + ')', () => {
|
|
54
|
-
(0, mocha_1.it)('can broadcast as an output, and be spent as an input', async () => {
|
|
55
|
-
Object.assign(depends, { prevOutScriptType: k });
|
|
56
|
-
await buildAndSign(depends, output, undefined, undefined);
|
|
57
|
-
});
|
|
58
|
-
(0, mocha_1.it)('can (as P2SH(' +
|
|
59
|
-
k +
|
|
60
|
-
')) broadcast as an output, and be spent as an input', async () => {
|
|
61
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
62
|
-
redeem: { output },
|
|
63
|
-
network: NETWORK,
|
|
64
|
-
});
|
|
65
|
-
Object.assign(depends, { prevOutScriptType: 'p2sh-' + k });
|
|
66
|
-
await buildAndSign(depends, p2sh.output, p2sh.redeem.output, undefined);
|
|
67
|
-
});
|
|
68
|
-
// NOTE: P2WPKH cannot be wrapped in P2WSH, consensus fail
|
|
69
|
-
if (k === 'p2wpkh')
|
|
70
|
-
return;
|
|
71
|
-
(0, mocha_1.it)('can (as P2WSH(' +
|
|
72
|
-
k +
|
|
73
|
-
')) broadcast as an output, and be spent as an input', async () => {
|
|
74
|
-
const p2wsh = bitcoin.payments.p2wsh({
|
|
75
|
-
redeem: { output },
|
|
76
|
-
network: NETWORK,
|
|
77
|
-
});
|
|
78
|
-
Object.assign(depends, { prevOutScriptType: 'p2wsh-' + k });
|
|
79
|
-
await buildAndSign(depends, p2wsh.output, undefined, p2wsh.redeem.output);
|
|
80
|
-
});
|
|
81
|
-
(0, mocha_1.it)('can (as P2SH(P2WSH(' +
|
|
82
|
-
k +
|
|
83
|
-
'))) broadcast as an output, and be spent as an input', async () => {
|
|
84
|
-
const p2wsh = bitcoin.payments.p2wsh({
|
|
85
|
-
redeem: { output },
|
|
86
|
-
network: NETWORK,
|
|
87
|
-
});
|
|
88
|
-
const p2sh = bitcoin.payments.p2sh({
|
|
89
|
-
redeem: { output: p2wsh.output },
|
|
90
|
-
network: NETWORK,
|
|
91
|
-
});
|
|
92
|
-
Object.assign(depends, {
|
|
93
|
-
prevOutScriptType: 'p2sh-p2wsh-' + k,
|
|
94
|
-
});
|
|
95
|
-
await buildAndSign(depends, p2sh.output, p2sh.redeem.output, p2wsh.redeem.output);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|