@bitgo/wasm-utxo 1.8.0 → 1.9.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/wasm/wasm_utxo.js +6 -6
- package/dist/cjs/js/wasm/wasm_utxo_bg.wasm +0 -0
- package/dist/cjs/js/wasm/wasm_utxo_bg.wasm.d.ts +4 -4
- package/dist/esm/js/wasm/wasm_utxo_bg.js +6 -6
- package/dist/esm/js/wasm/wasm_utxo_bg.wasm +0 -0
- package/dist/esm/js/wasm/wasm_utxo_bg.wasm.d.ts +4 -4
- package/package.json +3 -3
- package/dist/cjs/package.json +0 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +0 -1
- package/dist/esm/test/address/utxolibCompat.d.ts +0 -1
- package/dist/esm/test/address/utxolibCompat.js +0 -107
- package/dist/esm/test/ast/formatNode.d.ts +0 -1
- package/dist/esm/test/ast/formatNode.js +0 -15
- package/dist/esm/test/bip32.d.ts +0 -1
- package/dist/esm/test/bip32.js +0 -242
- package/dist/esm/test/descriptorFixtures.d.ts +0 -25
- package/dist/esm/test/descriptorFixtures.js +0 -605
- package/dist/esm/test/descriptorUtil.d.ts +0 -13
- package/dist/esm/test/descriptorUtil.js +0 -52
- package/dist/esm/test/ecpair.d.ts +0 -1
- package/dist/esm/test/ecpair.js +0 -137
- package/dist/esm/test/fixedScript/address.d.ts +0 -1
- package/dist/esm/test/fixedScript/address.js +0 -66
- package/dist/esm/test/fixedScript/finalizeExtract.d.ts +0 -1
- package/dist/esm/test/fixedScript/finalizeExtract.js +0 -66
- package/dist/esm/test/fixedScript/fixtureUtil.d.ts +0 -103
- package/dist/esm/test/fixedScript/fixtureUtil.js +0 -65
- package/dist/esm/test/fixedScript/musig2Nonces.d.ts +0 -1
- package/dist/esm/test/fixedScript/musig2Nonces.js +0 -77
- package/dist/esm/test/fixedScript/parseTransactionWithWalletKeys.d.ts +0 -1
- package/dist/esm/test/fixedScript/parseTransactionWithWalletKeys.js +0 -168
- package/dist/esm/test/fixedScript/signAndVerifySignature.d.ts +0 -1
- package/dist/esm/test/fixedScript/signAndVerifySignature.js +0 -268
- package/dist/esm/test/fixedScript/walletKeys.util.d.ts +0 -12
- package/dist/esm/test/fixedScript/walletKeys.util.js +0 -17
- package/dist/esm/test/fixedScriptToDescriptor.d.ts +0 -1
- package/dist/esm/test/fixedScriptToDescriptor.js +0 -93
- package/dist/esm/test/fixtures.d.ts +0 -1
- package/dist/esm/test/fixtures.js +0 -16
- package/dist/esm/test/opdrop.d.ts +0 -1
- package/dist/esm/test/opdrop.js +0 -85
- package/dist/esm/test/psbt.util.d.ts +0 -8
- package/dist/esm/test/psbt.util.js +0 -113
- package/dist/esm/test/psbtFixedScriptCompat.d.ts +0 -1
- package/dist/esm/test/psbtFixedScriptCompat.js +0 -116
- package/dist/esm/test/psbtFixedScriptCompatFixtures.d.ts +0 -10
- package/dist/esm/test/psbtFixedScriptCompatFixtures.js +0 -53
- package/dist/esm/test/psbtFromDescriptor.d.ts +0 -1
- package/dist/esm/test/psbtFromDescriptor.js +0 -104
- package/dist/esm/test/psbtFromDescriptor.util.d.ts +0 -63
- package/dist/esm/test/psbtFromDescriptor.util.js +0 -101
- package/dist/esm/test/test.d.ts +0 -1
- package/dist/esm/test/test.js +0 -123
- package/dist/esm/tsconfig.tsbuildinfo +0 -1
package/dist/esm/test/opdrop.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import * as assert from "assert";
|
|
2
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
3
|
-
import { Descriptor } from "../js/index.js";
|
|
4
|
-
import { finalizePsbt, updateInputWithDescriptor } from "./psbt.util.js";
|
|
5
|
-
import { getFixture } from "./fixtures.js";
|
|
6
|
-
const rootWalletKeys = new utxolib.bitgo.RootWalletKeys(utxolib.testutil.getKeyTriple("wasm"));
|
|
7
|
-
function getDescriptorOpDropP2ms(locktime, keys) {
|
|
8
|
-
const xpubs = keys.map((key) => key.toBase58() + "/*");
|
|
9
|
-
// the `r:` prefix is a custom BitGo modification of miniscript to allow OP_DROP
|
|
10
|
-
return `wsh(and_v(r:after(${locktime}),multi(2,${xpubs.join(",")})))`;
|
|
11
|
-
}
|
|
12
|
-
describe("CLV with OP_DROP", function () {
|
|
13
|
-
const locktime = 1024;
|
|
14
|
-
const descriptor = Descriptor.fromString(getDescriptorOpDropP2ms(locktime, rootWalletKeys.triple), "derivable");
|
|
15
|
-
it("has expected AST", () => {
|
|
16
|
-
assert.deepStrictEqual(descriptor.node(), {
|
|
17
|
-
Wsh: {
|
|
18
|
-
Ms: {
|
|
19
|
-
AndV: [
|
|
20
|
-
{
|
|
21
|
-
Drop: {
|
|
22
|
-
After: {
|
|
23
|
-
absLockTime: 1024,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
Multi: [
|
|
29
|
-
2,
|
|
30
|
-
{
|
|
31
|
-
XPub: "xpub661MyMwAqRbcFNusVUbSN3nbanHMtJjLgZGrs1wxH6f77kKQd6Vq4HfkZQNPC1vSbN6RTiBWJJV6FwJtCfBon2SgaT2J3MSkydukstKjwbJ/*",
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
XPub: "xpub661MyMwAqRbcFo3t7PUqvbgvAcEuuoeVib5aapsg52inrG6KGF5aNtR5ey1FNCt1zJpMQiNec5XpofQmLNRhHvQRbhkc8UsWwwMwsXW6ogU/*",
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
XPub: "xpub661MyMwAqRbcGg7f22Kcg2gy1F4jBjWR3xQTECVeJPHmxvhg5gUAZC6EYFtnyi6aMDQir1kV8HzCqC2FzTowGgEZqRh7rinqUCDeNDdmYzH/*",
|
|
38
|
-
},
|
|
39
|
-
],
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
it("has expected asm", () => {
|
|
47
|
-
assert.deepStrictEqual(descriptor.atDerivationIndex(0).toAsmString().split(" "), [
|
|
48
|
-
"OP_PUSHBYTES_2",
|
|
49
|
-
"0004",
|
|
50
|
-
"OP_CLTV",
|
|
51
|
-
"OP_DROP",
|
|
52
|
-
"OP_PUSHNUM_2",
|
|
53
|
-
"OP_PUSHBYTES_33",
|
|
54
|
-
"02ae7c3c0ebc315a33151a1985ebb1fdcae72b3b91c38e3193c40ebabfffe9c343",
|
|
55
|
-
"OP_PUSHBYTES_33",
|
|
56
|
-
"0260ba2407f7c75d525db9f171e9b2f3cf5ba3f0d7fc6067b20d4b91585432f974",
|
|
57
|
-
"OP_PUSHBYTES_33",
|
|
58
|
-
"03eadd6e4300dac62f1d4cf1131a06c5e140911f04245c64934c27510e93dbe843",
|
|
59
|
-
"OP_PUSHNUM_3",
|
|
60
|
-
"OP_CHECKMULTISIG",
|
|
61
|
-
]);
|
|
62
|
-
});
|
|
63
|
-
it("can be signed", async function () {
|
|
64
|
-
const psbt = Object.assign(new utxolib.Psbt({ network: utxolib.networks.bitcoin }), {
|
|
65
|
-
locktime,
|
|
66
|
-
});
|
|
67
|
-
const signers = rootWalletKeys.triple.slice(0, 2);
|
|
68
|
-
const descriptorAt0 = descriptor.atDerivationIndex(0);
|
|
69
|
-
const script = Buffer.from(descriptorAt0.scriptPubkey());
|
|
70
|
-
psbt.addInput({
|
|
71
|
-
hash: Buffer.alloc(32),
|
|
72
|
-
index: 0,
|
|
73
|
-
sequence: 0xfffffffe,
|
|
74
|
-
witnessUtxo: { script, value: BigInt(1e8) },
|
|
75
|
-
});
|
|
76
|
-
psbt.addOutput({ script, value: BigInt(1e8) });
|
|
77
|
-
updateInputWithDescriptor(psbt, 0, descriptorAt0);
|
|
78
|
-
for (const signer of signers) {
|
|
79
|
-
psbt.signAllInputsHD(signer);
|
|
80
|
-
}
|
|
81
|
-
finalizePsbt(psbt);
|
|
82
|
-
const signedTx = psbt.extractTransaction().toBuffer();
|
|
83
|
-
assert.strictEqual(signedTx.toString("hex"), await getFixture("test/fixtures/opdrop.json", signedTx.toString("hex")));
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
2
|
-
import { Descriptor, Psbt } from "../js/index.js";
|
|
3
|
-
export declare function toWrappedPsbt(psbt: utxolib.bitgo.UtxoPsbt | utxolib.Psbt | Buffer | Uint8Array): Psbt;
|
|
4
|
-
export declare function toUtxoPsbt(psbt: Psbt | Buffer | Uint8Array): utxolib.bitgo.UtxoPsbt<utxolib.bitgo.UtxoTransaction<bigint>>;
|
|
5
|
-
export declare function updateInputWithDescriptor(psbt: utxolib.Psbt, inputIndex: number, descriptor: Descriptor): void;
|
|
6
|
-
export declare function updateOutputWithDescriptor(psbt: utxolib.Psbt, outputIndex: number, descriptor: Descriptor): void;
|
|
7
|
-
export declare function finalizePsbt(psbt: utxolib.Psbt): void;
|
|
8
|
-
export declare function assertEqualPsbt(a: utxolib.Psbt, b: utxolib.Psbt): void;
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import * as assert from "node:assert";
|
|
2
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
3
|
-
import { Psbt } from "../js/index.js";
|
|
4
|
-
export function toWrappedPsbt(psbt) {
|
|
5
|
-
if (psbt instanceof utxolib.bitgo.UtxoPsbt || psbt instanceof utxolib.Psbt) {
|
|
6
|
-
psbt = psbt.toBuffer();
|
|
7
|
-
}
|
|
8
|
-
if (psbt instanceof Buffer || psbt instanceof Uint8Array) {
|
|
9
|
-
return Psbt.deserialize(psbt);
|
|
10
|
-
}
|
|
11
|
-
throw new Error("Invalid input");
|
|
12
|
-
}
|
|
13
|
-
export function toUtxoPsbt(psbt) {
|
|
14
|
-
if (psbt instanceof Psbt) {
|
|
15
|
-
psbt = psbt.serialize();
|
|
16
|
-
}
|
|
17
|
-
if (psbt instanceof Buffer || psbt instanceof Uint8Array) {
|
|
18
|
-
return utxolib.bitgo.UtxoPsbt.fromBuffer(Buffer.from(psbt), {
|
|
19
|
-
network: utxolib.networks.bitcoin,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
throw new Error("Invalid input");
|
|
23
|
-
}
|
|
24
|
-
export function updateInputWithDescriptor(psbt, inputIndex, descriptor) {
|
|
25
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
26
|
-
wrappedPsbt.updateInputWithDescriptor(inputIndex, descriptor);
|
|
27
|
-
psbt.data.inputs[inputIndex] = toUtxoPsbt(wrappedPsbt).data.inputs[inputIndex];
|
|
28
|
-
}
|
|
29
|
-
export function updateOutputWithDescriptor(psbt, outputIndex, descriptor) {
|
|
30
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
31
|
-
wrappedPsbt.updateOutputWithDescriptor(outputIndex, descriptor);
|
|
32
|
-
psbt.data.outputs[outputIndex] = toUtxoPsbt(wrappedPsbt).data.outputs[outputIndex];
|
|
33
|
-
}
|
|
34
|
-
export function finalizePsbt(psbt) {
|
|
35
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
36
|
-
wrappedPsbt.finalize();
|
|
37
|
-
const unwrappedPsbt = toUtxoPsbt(wrappedPsbt);
|
|
38
|
-
for (let i = 0; i < psbt.data.inputs.length; i++) {
|
|
39
|
-
psbt.data.inputs[i] = unwrappedPsbt.data.inputs[i];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
function toEntries(k, v, path) {
|
|
43
|
-
if (matchPath(path, ["data", "inputs", any, "sighashType"])) {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
if (matchPath(path.slice(-1), ["unknownKeyVals"])) {
|
|
47
|
-
if (Array.isArray(v) && v.length === 0) {
|
|
48
|
-
return [];
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return [[k, toPlainObject(v, path)]];
|
|
52
|
-
}
|
|
53
|
-
const any = Symbol("any");
|
|
54
|
-
function matchPath(path, pattern) {
|
|
55
|
-
if (path.length !== pattern.length) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
for (let i = 0; i < path.length; i++) {
|
|
59
|
-
if (pattern[i] !== any && path[i] !== pattern[i]) {
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
function normalizeBip32Derivation(v) {
|
|
66
|
-
if (!Array.isArray(v)) {
|
|
67
|
-
throw new Error("Expected bip32Derivation to be an array");
|
|
68
|
-
}
|
|
69
|
-
return v
|
|
70
|
-
.map((e) => {
|
|
71
|
-
let { path } = e;
|
|
72
|
-
if (path.startsWith("m/")) {
|
|
73
|
-
path = path.slice(2);
|
|
74
|
-
}
|
|
75
|
-
return {
|
|
76
|
-
...e,
|
|
77
|
-
path,
|
|
78
|
-
};
|
|
79
|
-
})
|
|
80
|
-
.sort((a, b) => a.masterFingerprint.toString().localeCompare(b.masterFingerprint.toString()));
|
|
81
|
-
}
|
|
82
|
-
function toPlainObject(v, path) {
|
|
83
|
-
// psbts have fun getters and other types of irregular properties that we mash into shape here
|
|
84
|
-
if (v === null || v === undefined) {
|
|
85
|
-
return v;
|
|
86
|
-
}
|
|
87
|
-
if (matchPath(path, ["data", "inputs", any, "bip32Derivation"]) ||
|
|
88
|
-
matchPath(path, ["data", "outputs", any, "bip32Derivation"])) {
|
|
89
|
-
v = normalizeBip32Derivation(v);
|
|
90
|
-
}
|
|
91
|
-
switch (typeof v) {
|
|
92
|
-
case "number":
|
|
93
|
-
case "bigint":
|
|
94
|
-
case "string":
|
|
95
|
-
case "boolean":
|
|
96
|
-
return v;
|
|
97
|
-
case "object":
|
|
98
|
-
if (v instanceof Buffer || v instanceof Uint8Array) {
|
|
99
|
-
return v.toString("hex");
|
|
100
|
-
}
|
|
101
|
-
if (Array.isArray(v)) {
|
|
102
|
-
return v.map((v, i) => toPlainObject(v, [...path, i]));
|
|
103
|
-
}
|
|
104
|
-
return Object.fromEntries(Object.entries(v)
|
|
105
|
-
.flatMap(([k, v]) => toEntries(k, v, [...path, k]))
|
|
106
|
-
.sort(([a], [b]) => a.localeCompare(b)));
|
|
107
|
-
default:
|
|
108
|
-
throw new Error(`Unsupported type: ${typeof v}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
export function assertEqualPsbt(a, b) {
|
|
112
|
-
assert.deepStrictEqual(toPlainObject(a, []), toPlainObject(b, []));
|
|
113
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
2
|
-
import * as assert from "node:assert";
|
|
3
|
-
import { getPsbtFixtures } from "./psbtFixedScriptCompatFixtures.js";
|
|
4
|
-
import { Descriptor } from "../js/index.js";
|
|
5
|
-
import { getDescriptorForScriptType } from "./descriptorUtil.js";
|
|
6
|
-
import { assertEqualPsbt, toUtxoPsbt, toWrappedPsbt, updateInputWithDescriptor, } from "./psbt.util.js";
|
|
7
|
-
import { getKey } from "@bitgo/utxo-lib/dist/src/testutil";
|
|
8
|
-
const rootWalletKeys = new utxolib.bitgo.RootWalletKeys(utxolib.testutil.getKeyTriple("wasm"));
|
|
9
|
-
function assertEqualBuffer(a, b, message) {
|
|
10
|
-
assert.strictEqual(Buffer.from(a).toString("hex"), Buffer.from(b).toString("hex"), message);
|
|
11
|
-
}
|
|
12
|
-
const fixtures = getPsbtFixtures(rootWalletKeys);
|
|
13
|
-
function describeUpdateInputWithDescriptor(psbt, scriptType) {
|
|
14
|
-
function getFixtureAtStage(stage) {
|
|
15
|
-
const f = fixtures.find((f) => f.scriptType === scriptType && f.stage === stage);
|
|
16
|
-
if (!f) {
|
|
17
|
-
throw new Error(`Could not find fixture for scriptType ${scriptType} and stage ${stage}`);
|
|
18
|
-
}
|
|
19
|
-
return f;
|
|
20
|
-
}
|
|
21
|
-
const descriptorStr = getDescriptorForScriptType(rootWalletKeys, scriptType, "internal");
|
|
22
|
-
const index = 0;
|
|
23
|
-
const descriptor = Descriptor.fromString(descriptorStr, "derivable");
|
|
24
|
-
function getWrappedPsbt() {
|
|
25
|
-
return toWrappedPsbt(psbt);
|
|
26
|
-
}
|
|
27
|
-
function getWrappedPsbtWithDescriptorInfo() {
|
|
28
|
-
const wrappedPsbt = getWrappedPsbt();
|
|
29
|
-
const descriptorAtDerivation = descriptor.atDerivationIndex(index);
|
|
30
|
-
wrappedPsbt.updateInputWithDescriptor(0, descriptorAtDerivation);
|
|
31
|
-
wrappedPsbt.updateOutputWithDescriptor(0, descriptorAtDerivation);
|
|
32
|
-
return wrappedPsbt;
|
|
33
|
-
}
|
|
34
|
-
describe("Wrapped PSBT updateInputWithDescriptor", function () {
|
|
35
|
-
it("should update the input with the descriptor", function () {
|
|
36
|
-
const wrappedPsbt = getWrappedPsbtWithDescriptorInfo();
|
|
37
|
-
const updatedPsbt = toUtxoPsbt(wrappedPsbt);
|
|
38
|
-
assertEqualPsbt(updatedPsbt, getFixtureAtStage("unsigned").psbt);
|
|
39
|
-
updatedPsbt.signAllInputsHD(rootWalletKeys.triple[0]);
|
|
40
|
-
updatedPsbt.signAllInputsHD(rootWalletKeys.triple[2]);
|
|
41
|
-
const wrappedSignedPsbt = toWrappedPsbt(updatedPsbt);
|
|
42
|
-
updatedPsbt.finalizeAllInputs();
|
|
43
|
-
wrappedSignedPsbt.finalize();
|
|
44
|
-
assertEqualBuffer(updatedPsbt.toBuffer(), wrappedSignedPsbt.serialize());
|
|
45
|
-
assertEqualBuffer(getFixtureAtStage("fullsigned")
|
|
46
|
-
.psbt.clone()
|
|
47
|
-
.finalizeAllInputs()
|
|
48
|
-
.extractTransaction()
|
|
49
|
-
.toBuffer(), updatedPsbt.extractTransaction().toBuffer());
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
describe("updateInputWithDescriptor util", function () {
|
|
53
|
-
it("should update the input with the descriptor", function () {
|
|
54
|
-
const cloned = psbt.clone();
|
|
55
|
-
updateInputWithDescriptor(cloned, 0, descriptor.atDerivationIndex(index));
|
|
56
|
-
cloned.signAllInputsHD(rootWalletKeys.triple[0]);
|
|
57
|
-
cloned.signAllInputsHD(rootWalletKeys.triple[2]);
|
|
58
|
-
cloned.finalizeAllInputs();
|
|
59
|
-
assertEqualBuffer(getFixtureAtStage("fullsigned")
|
|
60
|
-
.psbt.clone()
|
|
61
|
-
.finalizeAllInputs()
|
|
62
|
-
.extractTransaction()
|
|
63
|
-
.toBuffer(), cloned.extractTransaction().toBuffer());
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe("psbt signWithXprv", function () {
|
|
67
|
-
function signWithKey(keys, { checkFinalized = false } = {}) {
|
|
68
|
-
it(`signs the input with keys ${keys.join(", ")}`, function () {
|
|
69
|
-
const psbt = getWrappedPsbtWithDescriptorInfo();
|
|
70
|
-
keys.forEach((keyName) => {
|
|
71
|
-
const key = keyName === "unrelated" ? getKey(keyName) : rootWalletKeys[keyName];
|
|
72
|
-
const derivationPaths = toUtxoPsbt(psbt).data.inputs[0].bip32Derivation.map((d) => d.path);
|
|
73
|
-
assert.ok(derivationPaths.every((p) => p === derivationPaths[0]));
|
|
74
|
-
const derived = key.derivePath(derivationPaths[0]);
|
|
75
|
-
assert.deepStrictEqual(psbt.signWithXprv(key.toBase58()), {
|
|
76
|
-
// map: input index -> pubkey array
|
|
77
|
-
0: { Ecdsa: keyName === "unrelated" ? [] : [derived.publicKey.toString("hex")] },
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
if (checkFinalized) {
|
|
81
|
-
psbt.finalize();
|
|
82
|
-
assertEqualBuffer(toUtxoPsbt(psbt).extractTransaction().toBuffer(), getFixtureAtStage("fullsigned")
|
|
83
|
-
.psbt.finalizeAllInputs()
|
|
84
|
-
.extractTransaction()
|
|
85
|
-
.toBuffer());
|
|
86
|
-
}
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
signWithKey(["user"]);
|
|
90
|
-
signWithKey(["backup"]);
|
|
91
|
-
signWithKey(["bitgo"]);
|
|
92
|
-
signWithKey(["unrelated"]);
|
|
93
|
-
signWithKey(["user", "bitgo"], { checkFinalized: true });
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
describe("PSBT fixture", function () {
|
|
97
|
-
fixtures.forEach(({ psbt, scriptType, stage }) => {
|
|
98
|
-
describe(`PSBT fixture ${scriptType} ${stage}`, function () {
|
|
99
|
-
let buf;
|
|
100
|
-
let wrappedPsbt;
|
|
101
|
-
before(function () {
|
|
102
|
-
buf = psbt.toBuffer();
|
|
103
|
-
wrappedPsbt = toWrappedPsbt(buf);
|
|
104
|
-
});
|
|
105
|
-
it("should map to same hex", function () {
|
|
106
|
-
assertEqualBuffer(buf, wrappedPsbt.serialize());
|
|
107
|
-
});
|
|
108
|
-
it("should round-trip utxolib -> ms -> utxolib", function () {
|
|
109
|
-
assertEqualBuffer(buf, toUtxoPsbt(wrappedPsbt).toBuffer());
|
|
110
|
-
});
|
|
111
|
-
if (stage === "bare") {
|
|
112
|
-
describeUpdateInputWithDescriptor(psbt, scriptType);
|
|
113
|
-
}
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
2
|
-
import { RootWalletKeys } from "@bitgo/utxo-lib/dist/src/bitgo";
|
|
3
|
-
export type PsbtStage = "bare" | "unsigned" | "halfsigned" | "fullsigned";
|
|
4
|
-
export declare function toPsbtWithPrevOutOnly(psbt: utxolib.bitgo.UtxoPsbt): utxolib.bitgo.UtxoPsbt<utxolib.bitgo.UtxoTransaction<bigint>>;
|
|
5
|
-
export type PsbtFixture = {
|
|
6
|
-
psbt: utxolib.bitgo.UtxoPsbt;
|
|
7
|
-
scriptType: utxolib.bitgo.outputScripts.ScriptType2Of3;
|
|
8
|
-
stage: PsbtStage;
|
|
9
|
-
};
|
|
10
|
-
export declare function getPsbtFixtures(keys: RootWalletKeys): PsbtFixture[];
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
2
|
-
export function toPsbtWithPrevOutOnly(psbt) {
|
|
3
|
-
const psbtCopy = utxolib.bitgo.UtxoPsbt.createPsbt({
|
|
4
|
-
network: utxolib.networks.bitcoin,
|
|
5
|
-
});
|
|
6
|
-
psbtCopy.setVersion(psbt.version);
|
|
7
|
-
psbtCopy.setLocktime(psbt.locktime);
|
|
8
|
-
psbt.txInputs.forEach((input, vin) => {
|
|
9
|
-
const { witnessUtxo, nonWitnessUtxo } = psbt.data.inputs[vin];
|
|
10
|
-
psbtCopy.addInput({
|
|
11
|
-
hash: input.hash,
|
|
12
|
-
index: input.index,
|
|
13
|
-
sequence: input.sequence,
|
|
14
|
-
...(witnessUtxo ? { witnessUtxo } : { nonWitnessUtxo }),
|
|
15
|
-
});
|
|
16
|
-
});
|
|
17
|
-
psbt.txOutputs.forEach((output) => {
|
|
18
|
-
psbtCopy.addOutput(output);
|
|
19
|
-
});
|
|
20
|
-
return psbtCopy;
|
|
21
|
-
}
|
|
22
|
-
function getPsbtWithScriptTypeAndStage(keys, scriptType, stage) {
|
|
23
|
-
if (stage === "bare") {
|
|
24
|
-
const psbt = getPsbtWithScriptTypeAndStage(keys, scriptType, "unsigned");
|
|
25
|
-
return toPsbtWithPrevOutOnly(psbt);
|
|
26
|
-
}
|
|
27
|
-
return utxolib.testutil.constructPsbt([
|
|
28
|
-
{
|
|
29
|
-
scriptType,
|
|
30
|
-
value: BigInt(1e8),
|
|
31
|
-
},
|
|
32
|
-
], [
|
|
33
|
-
{
|
|
34
|
-
value: BigInt(1e8 - 1000),
|
|
35
|
-
scriptType,
|
|
36
|
-
isInternalAddress: true,
|
|
37
|
-
},
|
|
38
|
-
], utxolib.networks.bitcoin, keys, stage);
|
|
39
|
-
}
|
|
40
|
-
export function getPsbtFixtures(keys) {
|
|
41
|
-
const testMatrixScriptTypes = ["p2sh", "p2shP2wsh", "p2wsh"];
|
|
42
|
-
const testMatrixStages = ["bare", "unsigned", "halfsigned", "fullsigned"];
|
|
43
|
-
return testMatrixStages.flatMap((stage) => {
|
|
44
|
-
return testMatrixScriptTypes.map((scriptType) => {
|
|
45
|
-
return {
|
|
46
|
-
psbt: getPsbtWithScriptTypeAndStage(keys, scriptType, stage),
|
|
47
|
-
name: `${scriptType}-${stage}`,
|
|
48
|
-
scriptType,
|
|
49
|
-
stage,
|
|
50
|
-
};
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
|
-
import { ECPair } from "@bitgo/utxo-lib";
|
|
3
|
-
import { getKey } from "@bitgo/utxo-lib/dist/src/testutil";
|
|
4
|
-
import { formatNode } from "../js/ast/index.js";
|
|
5
|
-
import { mockPsbtDefault } from "./psbtFromDescriptor.util.js";
|
|
6
|
-
import { Descriptor } from "../js/index.js";
|
|
7
|
-
import { toWrappedPsbt } from "./psbt.util.js";
|
|
8
|
-
function toKeyWithPath(k, path = "*") {
|
|
9
|
-
return k.neutered().toBase58() + "/" + path;
|
|
10
|
-
}
|
|
11
|
-
function toECPair(k) {
|
|
12
|
-
assert(k.privateKey);
|
|
13
|
-
return ECPair.fromPrivateKey(k.privateKey);
|
|
14
|
-
}
|
|
15
|
-
function toKeyPlainXOnly(k) {
|
|
16
|
-
return k.subarray(1).toString("hex");
|
|
17
|
-
}
|
|
18
|
-
const external = getKey("external");
|
|
19
|
-
const a = getKey("a");
|
|
20
|
-
const b = getKey("b");
|
|
21
|
-
const c = getKey("c");
|
|
22
|
-
const keys = { external, a, b, c };
|
|
23
|
-
function getKeyName(k) {
|
|
24
|
-
const objKeys = Object.keys(keys);
|
|
25
|
-
return objKeys.find((key) => keys[key] === k || toECPair(keys[key]).publicKey.equals(k.publicKey));
|
|
26
|
-
}
|
|
27
|
-
function describeSignDescriptor(name, descriptor, { signBip32 = [], signECPair = [], }) {
|
|
28
|
-
describe(`psbt with descriptor ${name}`, function () {
|
|
29
|
-
const isTaproot = Object.keys(descriptor.node())[0] === "Tr";
|
|
30
|
-
const psbt = mockPsbtDefault({
|
|
31
|
-
descriptorSelf: descriptor,
|
|
32
|
-
descriptorOther: Descriptor.fromString(formatNode({ wpkh: toKeyWithPath(external) }), "derivable"),
|
|
33
|
-
});
|
|
34
|
-
function getSigResult(keys) {
|
|
35
|
-
return {
|
|
36
|
-
[isTaproot ? "Schnorr" : "Ecdsa"]: keys.map((key) => key.publicKey.subarray(isTaproot ? 1 : 0).toString("hex")),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
signBip32.forEach((signSeq) => {
|
|
40
|
-
it(`should sign ${signSeq.map((k) => getKeyName(k)).join(", ")} xprv`, function () {
|
|
41
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
42
|
-
signSeq.forEach((key) => {
|
|
43
|
-
assert.deepStrictEqual(wrappedPsbt.signWithXprv(key.toBase58()), {
|
|
44
|
-
0: getSigResult([key.derive(0)]),
|
|
45
|
-
1: getSigResult([key.derive(1)]),
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
wrappedPsbt.finalize();
|
|
49
|
-
});
|
|
50
|
-
it(`should sign ${signSeq.map((k) => getKeyName(k)).join(", ")} prv buffer`, function () {
|
|
51
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
52
|
-
signSeq.forEach((key) => {
|
|
53
|
-
assert.deepStrictEqual(wrappedPsbt.signWithPrv(key.derive(0).privateKey), {
|
|
54
|
-
// NOTE: signing with a plain derived key does not work for taproot
|
|
55
|
-
// see SingleKeySigner implementation in psbt.rs for details
|
|
56
|
-
0: getSigResult(isTaproot ? [] : [key.derive(0)]),
|
|
57
|
-
1: getSigResult([]),
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
signECPair.forEach((signSeq) => {
|
|
63
|
-
it(`should sign ${signSeq.map((k) => getKeyName(k)).join(", ")} ec pair`, function () {
|
|
64
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
65
|
-
signSeq.forEach((key) => {
|
|
66
|
-
assert(key.privateKey);
|
|
67
|
-
assert.deepStrictEqual(wrappedPsbt.signWithPrv(key.privateKey), {
|
|
68
|
-
0: getSigResult([key]),
|
|
69
|
-
1: getSigResult([key]),
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
wrappedPsbt.finalize();
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function fromNodes(node, type) {
|
|
78
|
-
return Descriptor.fromString(formatNode(node), type);
|
|
79
|
-
}
|
|
80
|
-
describeSignDescriptor("Wsh2Of3", fromNodes({
|
|
81
|
-
wsh: { multi: [2, toKeyWithPath(a), toKeyWithPath(b), toKeyWithPath(c)] },
|
|
82
|
-
}, "derivable"), {
|
|
83
|
-
signBip32: [
|
|
84
|
-
[a, b],
|
|
85
|
-
[b, a],
|
|
86
|
-
],
|
|
87
|
-
});
|
|
88
|
-
describeSignDescriptor("Tr1Of3", fromNodes({
|
|
89
|
-
tr: [toKeyWithPath(a), [{ pk: toKeyWithPath(b) }, { pk: toKeyWithPath(c) }]],
|
|
90
|
-
}, "derivable"), { signBip32: [[a], [b], [c]] });
|
|
91
|
-
describeSignDescriptor("TrWithExternalPlain", fromNodes({
|
|
92
|
-
tr: [
|
|
93
|
-
toKeyPlainXOnly(external.publicKey),
|
|
94
|
-
[
|
|
95
|
-
{ pk: toKeyPlainXOnly(external.publicKey) },
|
|
96
|
-
{
|
|
97
|
-
or_b: [
|
|
98
|
-
{ pk: toKeyPlainXOnly(external.publicKey) },
|
|
99
|
-
{ "s:pk": toKeyPlainXOnly(a.publicKey) },
|
|
100
|
-
],
|
|
101
|
-
},
|
|
102
|
-
],
|
|
103
|
-
],
|
|
104
|
-
}, "definite"), { signECPair: [[toECPair(a)]] });
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
2
|
-
import { Descriptor } from "../js/index.js";
|
|
3
|
-
export declare function createScriptPubKeyFromDescriptor(descriptor: Descriptor, index?: number): Buffer;
|
|
4
|
-
export type Output = {
|
|
5
|
-
script: Buffer;
|
|
6
|
-
value: bigint;
|
|
7
|
-
};
|
|
8
|
-
export type WithDescriptor<T> = T & {
|
|
9
|
-
descriptor: Descriptor;
|
|
10
|
-
};
|
|
11
|
-
export type PrevOutput = {
|
|
12
|
-
hash: string;
|
|
13
|
-
index: number;
|
|
14
|
-
witnessUtxo: Output;
|
|
15
|
-
};
|
|
16
|
-
export type DescriptorWalletOutput = PrevOutput & {
|
|
17
|
-
descriptorName: string;
|
|
18
|
-
descriptorIndex: number;
|
|
19
|
-
};
|
|
20
|
-
export type DerivedDescriptorWalletOutput = WithDescriptor<PrevOutput>;
|
|
21
|
-
export declare function toDerivedDescriptorWalletOutput(output: DescriptorWalletOutput, descriptor: Descriptor): DerivedDescriptorWalletOutput;
|
|
22
|
-
/**
|
|
23
|
-
* Non-Final (Replaceable)
|
|
24
|
-
* Reference: https://github.com/bitcoin/bitcoin/blob/v25.1/src/rpc/rawtransaction_util.cpp#L49
|
|
25
|
-
* */
|
|
26
|
-
export declare const MAX_BIP125_RBF_SEQUENCE: number;
|
|
27
|
-
type WithOptDescriptor<T> = T & {
|
|
28
|
-
descriptor?: Descriptor;
|
|
29
|
-
};
|
|
30
|
-
export declare function createPsbt(params: PsbtParams, inputs: DerivedDescriptorWalletOutput[], outputs: WithOptDescriptor<Output>[]): utxolib.bitgo.UtxoPsbt;
|
|
31
|
-
type MockOutputIdParams = {
|
|
32
|
-
hash?: string;
|
|
33
|
-
vout?: number;
|
|
34
|
-
};
|
|
35
|
-
type BaseMockDescriptorOutputParams = {
|
|
36
|
-
id?: MockOutputIdParams;
|
|
37
|
-
index?: number;
|
|
38
|
-
value?: bigint;
|
|
39
|
-
};
|
|
40
|
-
export declare function mockDerivedDescriptorWalletOutput(descriptor: Descriptor, outputParams?: BaseMockDescriptorOutputParams): DerivedDescriptorWalletOutput;
|
|
41
|
-
type MockInput = BaseMockDescriptorOutputParams & {
|
|
42
|
-
index: number;
|
|
43
|
-
descriptor: Descriptor;
|
|
44
|
-
};
|
|
45
|
-
type MockOutput = {
|
|
46
|
-
descriptor: Descriptor;
|
|
47
|
-
index: number;
|
|
48
|
-
value: bigint;
|
|
49
|
-
external?: boolean;
|
|
50
|
-
};
|
|
51
|
-
export declare function mockPsbt(inputs: MockInput[], outputs: MockOutput[], params?: Partial<PsbtParams>): utxolib.bitgo.UtxoPsbt;
|
|
52
|
-
export type PsbtParams = {
|
|
53
|
-
network: utxolib.Network;
|
|
54
|
-
version?: number;
|
|
55
|
-
locktime?: number;
|
|
56
|
-
sequence?: number;
|
|
57
|
-
};
|
|
58
|
-
export declare function mockPsbtDefault({ descriptorSelf, descriptorOther, params, }: {
|
|
59
|
-
descriptorSelf: Descriptor;
|
|
60
|
-
descriptorOther: Descriptor;
|
|
61
|
-
params?: Partial<PsbtParams>;
|
|
62
|
-
}): utxolib.bitgo.UtxoPsbt;
|
|
63
|
-
export {};
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import * as utxolib from "@bitgo/utxo-lib";
|
|
2
|
-
import { toUtxoPsbt, toWrappedPsbt } from "./psbt.util.js";
|
|
3
|
-
export function createScriptPubKeyFromDescriptor(descriptor, index) {
|
|
4
|
-
if (index === undefined) {
|
|
5
|
-
return Buffer.from(descriptor.scriptPubkey());
|
|
6
|
-
}
|
|
7
|
-
return createScriptPubKeyFromDescriptor(descriptor.atDerivationIndex(index));
|
|
8
|
-
}
|
|
9
|
-
export function toDerivedDescriptorWalletOutput(output, descriptor) {
|
|
10
|
-
const derivedDescriptor = descriptor.atDerivationIndex(output.descriptorIndex);
|
|
11
|
-
const script = createScriptPubKeyFromDescriptor(derivedDescriptor);
|
|
12
|
-
if (!script.equals(output.witnessUtxo.script)) {
|
|
13
|
-
throw new Error(`Script mismatch: descriptor ${output.descriptorName} ${descriptor.toString()} script=${script.toString("hex")}`);
|
|
14
|
-
}
|
|
15
|
-
return {
|
|
16
|
-
hash: output.hash,
|
|
17
|
-
index: output.index,
|
|
18
|
-
witnessUtxo: output.witnessUtxo,
|
|
19
|
-
descriptor: descriptor.atDerivationIndex(output.descriptorIndex),
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Non-Final (Replaceable)
|
|
24
|
-
* Reference: https://github.com/bitcoin/bitcoin/blob/v25.1/src/rpc/rawtransaction_util.cpp#L49
|
|
25
|
-
* */
|
|
26
|
-
export const MAX_BIP125_RBF_SEQUENCE = 0xffffffff - 2;
|
|
27
|
-
function updateInputsWithDescriptors(psbt, descriptors) {
|
|
28
|
-
if (psbt.txInputs.length !== descriptors.length) {
|
|
29
|
-
throw new Error(`Input count mismatch (psbt=${psbt.txInputs.length}, descriptors=${descriptors.length})`);
|
|
30
|
-
}
|
|
31
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
32
|
-
for (const [inputIndex, descriptor] of descriptors.entries()) {
|
|
33
|
-
wrappedPsbt.updateInputWithDescriptor(inputIndex, descriptor);
|
|
34
|
-
}
|
|
35
|
-
const unwrappedPsbt = toUtxoPsbt(wrappedPsbt);
|
|
36
|
-
for (let inputIndex = 0; inputIndex < psbt.txInputs.length; inputIndex++) {
|
|
37
|
-
psbt.data.inputs[inputIndex] = unwrappedPsbt.data.inputs[inputIndex];
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function updateOutputsWithDescriptors(psbt, descriptors) {
|
|
41
|
-
const wrappedPsbt = toWrappedPsbt(psbt);
|
|
42
|
-
for (const [outputIndex, { descriptor }] of descriptors.entries()) {
|
|
43
|
-
if (descriptor) {
|
|
44
|
-
wrappedPsbt.updateOutputWithDescriptor(outputIndex, descriptor);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const unwrappedPsbt = toUtxoPsbt(wrappedPsbt);
|
|
48
|
-
for (let outputIndex = 0; outputIndex < psbt.txOutputs.length; outputIndex++) {
|
|
49
|
-
psbt.data.outputs[outputIndex] = unwrappedPsbt.data.outputs[outputIndex];
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export function createPsbt(params, inputs, outputs) {
|
|
53
|
-
const psbt = utxolib.bitgo.UtxoPsbt.createPsbt({ network: params.network });
|
|
54
|
-
psbt.setVersion(params.version ?? 2);
|
|
55
|
-
psbt.setLocktime(params.locktime ?? 0);
|
|
56
|
-
psbt.addInputs(inputs.map((i) => ({ ...i, sequence: params.sequence ?? MAX_BIP125_RBF_SEQUENCE })));
|
|
57
|
-
psbt.addOutputs(outputs);
|
|
58
|
-
updateInputsWithDescriptors(psbt, inputs.map((i) => i.descriptor));
|
|
59
|
-
updateOutputsWithDescriptors(psbt, outputs);
|
|
60
|
-
return psbt;
|
|
61
|
-
}
|
|
62
|
-
function mockOutputId(id) {
|
|
63
|
-
const hash = id?.hash ?? Buffer.alloc(32, 1).toString("hex");
|
|
64
|
-
const vout = id?.vout ?? 0;
|
|
65
|
-
return { hash, vout };
|
|
66
|
-
}
|
|
67
|
-
export function mockDerivedDescriptorWalletOutput(descriptor, outputParams = {}) {
|
|
68
|
-
const { value = BigInt(1e6) } = outputParams;
|
|
69
|
-
const { hash, vout } = mockOutputId(outputParams.id);
|
|
70
|
-
return {
|
|
71
|
-
hash,
|
|
72
|
-
index: vout,
|
|
73
|
-
witnessUtxo: {
|
|
74
|
-
script: createScriptPubKeyFromDescriptor(descriptor),
|
|
75
|
-
value,
|
|
76
|
-
},
|
|
77
|
-
descriptor,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
function deriveIfWildcard(descriptor, index) {
|
|
81
|
-
return descriptor.hasWildcard() ? descriptor.atDerivationIndex(index) : descriptor;
|
|
82
|
-
}
|
|
83
|
-
export function mockPsbt(inputs, outputs, params = {}) {
|
|
84
|
-
return createPsbt({ ...params, network: params.network ?? utxolib.networks.bitcoin }, inputs.map((i) => mockDerivedDescriptorWalletOutput(deriveIfWildcard(i.descriptor, i.index), i)), outputs.map((o) => {
|
|
85
|
-
const derivedDescriptor = deriveIfWildcard(o.descriptor, o.index);
|
|
86
|
-
return {
|
|
87
|
-
script: createScriptPubKeyFromDescriptor(derivedDescriptor),
|
|
88
|
-
value: o.value,
|
|
89
|
-
descriptor: o.external ? undefined : derivedDescriptor,
|
|
90
|
-
};
|
|
91
|
-
}));
|
|
92
|
-
}
|
|
93
|
-
export function mockPsbtDefault({ descriptorSelf, descriptorOther, params = {}, }) {
|
|
94
|
-
return mockPsbt([
|
|
95
|
-
{ descriptor: descriptorSelf, index: 0 },
|
|
96
|
-
{ descriptor: descriptorSelf, index: 1, id: { vout: 1 } },
|
|
97
|
-
], [
|
|
98
|
-
{ descriptor: descriptorOther, index: 0, value: BigInt(4e5), external: true },
|
|
99
|
-
{ descriptor: descriptorSelf, index: 0, value: BigInt(4e5) },
|
|
100
|
-
], params);
|
|
101
|
-
}
|
package/dist/esm/test/test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|