1 | 'use strict';
|
2 | Object.defineProperty(exports, '__esModule', { value: true });
|
3 | exports.p2ms = void 0;
|
4 | const networks_1 = require('../networks');
|
5 | const bscript = require('../script');
|
6 | const types_1 = require('../types');
|
7 | const lazy = require('./lazy');
|
8 | const OPS = bscript.OPS;
|
9 | const OP_INT_BASE = OPS.OP_RESERVED;
|
10 | function stacksEqual(a, b) {
|
11 | if (a.length !== b.length) return false;
|
12 | return a.every((x, i) => {
|
13 | return x.equals(b[i]);
|
14 | });
|
15 | }
|
16 |
|
17 |
|
18 | function p2ms(a, opts) {
|
19 | if (
|
20 | !a.input &&
|
21 | !a.output &&
|
22 | !(a.pubkeys && a.m !== undefined) &&
|
23 | !a.signatures
|
24 | )
|
25 | throw new TypeError('Not enough data');
|
26 | opts = Object.assign({ validate: true }, opts || {});
|
27 | function isAcceptableSignature(x) {
|
28 | return (
|
29 | bscript.isCanonicalScriptSignature(x) ||
|
30 | (opts.allowIncomplete && x === OPS.OP_0) !== undefined
|
31 | );
|
32 | }
|
33 | (0, types_1.typeforce)(
|
34 | {
|
35 | network: types_1.typeforce.maybe(types_1.typeforce.Object),
|
36 | m: types_1.typeforce.maybe(types_1.typeforce.Number),
|
37 | n: types_1.typeforce.maybe(types_1.typeforce.Number),
|
38 | output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
39 | pubkeys: types_1.typeforce.maybe(
|
40 | types_1.typeforce.arrayOf(types_1.isPoint),
|
41 | ),
|
42 | signatures: types_1.typeforce.maybe(
|
43 | types_1.typeforce.arrayOf(isAcceptableSignature),
|
44 | ),
|
45 | input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
|
46 | },
|
47 | a,
|
48 | );
|
49 | const network = a.network || networks_1.bitcoin;
|
50 | const o = { network };
|
51 | let chunks = [];
|
52 | let decoded = false;
|
53 | function decode(output) {
|
54 | if (decoded) return;
|
55 | decoded = true;
|
56 | chunks = bscript.decompile(output);
|
57 | o.m = chunks[0] - OP_INT_BASE;
|
58 | o.n = chunks[chunks.length - 2] - OP_INT_BASE;
|
59 | o.pubkeys = chunks.slice(1, -2);
|
60 | }
|
61 | lazy.prop(o, 'output', () => {
|
62 | if (!a.m) return;
|
63 | if (!o.n) return;
|
64 | if (!a.pubkeys) return;
|
65 | return bscript.compile(
|
66 | [].concat(
|
67 | OP_INT_BASE + a.m,
|
68 | a.pubkeys,
|
69 | OP_INT_BASE + o.n,
|
70 | OPS.OP_CHECKMULTISIG,
|
71 | ),
|
72 | );
|
73 | });
|
74 | lazy.prop(o, 'm', () => {
|
75 | if (!o.output) return;
|
76 | decode(o.output);
|
77 | return o.m;
|
78 | });
|
79 | lazy.prop(o, 'n', () => {
|
80 | if (!o.pubkeys) return;
|
81 | return o.pubkeys.length;
|
82 | });
|
83 | lazy.prop(o, 'pubkeys', () => {
|
84 | if (!a.output) return;
|
85 | decode(a.output);
|
86 | return o.pubkeys;
|
87 | });
|
88 | lazy.prop(o, 'signatures', () => {
|
89 | if (!a.input) return;
|
90 | return bscript.decompile(a.input).slice(1);
|
91 | });
|
92 | lazy.prop(o, 'input', () => {
|
93 | if (!a.signatures) return;
|
94 | return bscript.compile([OPS.OP_0].concat(a.signatures));
|
95 | });
|
96 | lazy.prop(o, 'witness', () => {
|
97 | if (!o.input) return;
|
98 | return [];
|
99 | });
|
100 | lazy.prop(o, 'name', () => {
|
101 | if (!o.m || !o.n) return;
|
102 | return `p2ms(${o.m} of ${o.n})`;
|
103 | });
|
104 |
|
105 | if (opts.validate) {
|
106 | if (a.output) {
|
107 | decode(a.output);
|
108 | if (!types_1.typeforce.Number(chunks[0]))
|
109 | throw new TypeError('Output is invalid');
|
110 | if (!types_1.typeforce.Number(chunks[chunks.length - 2]))
|
111 | throw new TypeError('Output is invalid');
|
112 | if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG)
|
113 | throw new TypeError('Output is invalid');
|
114 | if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3)
|
115 | throw new TypeError('Output is invalid');
|
116 | if (!o.pubkeys.every(x => (0, types_1.isPoint)(x)))
|
117 | throw new TypeError('Output is invalid');
|
118 | if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
|
119 | if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch');
|
120 | if (a.pubkeys && !stacksEqual(a.pubkeys, o.pubkeys))
|
121 | throw new TypeError('Pubkeys mismatch');
|
122 | }
|
123 | if (a.pubkeys) {
|
124 | if (a.n !== undefined && a.n !== a.pubkeys.length)
|
125 | throw new TypeError('Pubkey count mismatch');
|
126 | o.n = a.pubkeys.length;
|
127 | if (o.n < o.m) throw new TypeError('Pubkey count cannot be less than m');
|
128 | }
|
129 | if (a.signatures) {
|
130 | if (a.signatures.length < o.m)
|
131 | throw new TypeError('Not enough signatures provided');
|
132 | if (a.signatures.length > o.m)
|
133 | throw new TypeError('Too many signatures provided');
|
134 | }
|
135 | if (a.input) {
|
136 | if (a.input[0] !== OPS.OP_0) throw new TypeError('Input is invalid');
|
137 | if (
|
138 | o.signatures.length === 0 ||
|
139 | !o.signatures.every(isAcceptableSignature)
|
140 | )
|
141 | throw new TypeError('Input has invalid signature(s)');
|
142 | if (a.signatures && !stacksEqual(a.signatures, o.signatures))
|
143 | throw new TypeError('Signature mismatch');
|
144 | if (a.m !== undefined && a.m !== a.signatures.length)
|
145 | throw new TypeError('Signature count mismatch');
|
146 | }
|
147 | }
|
148 | return Object.assign(o, a);
|
149 | }
|
150 | exports.p2ms = p2ms;
|