@btc-vision/bitcoin 6.4.3 → 6.4.4

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.
@@ -1,170 +1,195 @@
1
- import { bech32m } from 'bech32';
2
- import { Buffer as NBuffer } from 'buffer';
3
- import { fromBech32 } from '../address.js';
4
- import { bitcoin as BITCOIN_NETWORK, Network } from '../networks.js';
5
- import * as bscript from '../script.js';
6
- import { typeforce as typef } from '../types.js';
7
- import * as lazy from './lazy.js';
8
- import { BasePayment, P2OPPayment, PaymentOpts } from './index.js';
9
-
10
- const OPS = bscript.OPS;
11
- const P2OP_WITNESS_VERSION = 0x10;
12
- const MIN_SIZE = 2;
13
- const MAX_SIZE = 40;
14
-
15
- interface P2OPBase extends BasePayment {
16
- name: 'p2op';
17
- }
18
-
19
- interface P2OP_fromOutput extends P2OPBase {
20
- output: Buffer;
21
-
22
- program?: undefined;
23
- deploymentVersion?: undefined;
24
- hash160?: undefined;
25
- }
26
-
27
- interface P2OP_fromProgram extends P2OPBase {
28
- program: Buffer;
29
-
30
- output?: undefined;
31
- deploymentVersion?: never;
32
- hash160?: never;
33
- }
34
-
35
- interface P2OP_fromParts extends P2OPBase {
36
- deploymentVersion: number;
37
- hash160: Buffer;
38
-
39
- output?: undefined;
40
- program?: undefined;
41
- }
42
-
43
- export type P2OPPaymentParams = P2OP_fromOutput | P2OP_fromProgram | P2OP_fromParts;
44
-
45
- /**
46
- * Pay-to-OPNet (P2OP) decoder / encoder.
47
- *
48
- * ▪ witness program = <deploymentVersion:uint8><hash160:20-bytes|...>
49
- * ▪ scriptPubKey = OP_16 <program>
50
- * ▪ address HRP = network.bech32Opnet, encoded with Bech32m
51
- *
52
- * Accepts any combination of { address, output, program } and returns a
53
- * fully lazy payment object, mirroring the style of `p2tr`.
54
- */
55
- export function p2op(a: Omit<P2OPPaymentParams, 'name'>, opts?: PaymentOpts): P2OPPayment {
56
- if (!a.address && !a.output && !a.program) throw new TypeError('Not enough data for p2op');
57
-
58
- opts = Object.assign({ validate: true }, opts || {});
59
-
60
- typef(
61
- {
62
- address: typef.maybe(typef.String),
63
- output: typef.maybe(typef.Buffer),
64
- program: typef.maybe(typef.Buffer),
65
- network: typef.maybe(typef.Object),
66
- deploymentVersion: typef.maybe(typef.Number),
67
- hash160: typef.maybe(typef.BufferN(20)),
68
- },
69
- a,
70
- );
71
-
72
- const _address = lazy.value(() => fromBech32(a.address!));
73
-
74
- const network: Network = a.network || BITCOIN_NETWORK;
75
- const o: P2OPPayment = {
76
- name: 'p2op',
77
- network,
78
- deploymentVersion: 0,
79
- };
80
-
81
- lazy.prop(o, 'program', () => {
82
- if (a.program) return a.program;
83
-
84
- if (a.output) {
85
- if (a.output[0] !== OPS.OP_16) throw new TypeError('Invalid P2OP script');
86
- let pushPos = 1,
87
- progLen: number;
88
- if (a.output[1] < 0x4c) {
89
- progLen = a.output[1];
90
- pushPos = 2;
91
- } else if (a.output[1] === 0x4c) {
92
- progLen = a.output[2];
93
- pushPos = 3;
94
- } else {
95
- throw new TypeError('Unsupported push opcode in P2OP script');
96
- }
97
- return a.output.slice(pushPos, pushPos + progLen);
98
- }
99
-
100
- if (a.address) {
101
- const dec = _address();
102
- return dec.data;
103
- }
104
- });
105
-
106
- lazy.prop(o, 'deploymentVersion', () => {
107
- if (!o.program) return;
108
- return o.program[0];
109
- });
110
-
111
- lazy.prop(o, 'hash160', () => {
112
- if (!o.program) return;
113
- return o.program.slice(1);
114
- });
115
-
116
- lazy.prop(o, 'output', () => {
117
- if (!o.program) return;
118
- return bscript.compile([OPS.OP_16, o.program]);
119
- });
120
-
121
- lazy.prop(o, 'address', () => {
122
- if (!o.program) return;
123
- if (!network.bech32Opnet) {
124
- throw new TypeError('Network does not support opnet');
125
- }
126
-
127
- const words = bech32m.toWords(o.program);
128
- words.unshift(P2OP_WITNESS_VERSION);
129
-
130
- return bech32m.encode(network.bech32Opnet, words);
131
- });
132
-
133
- // extended validation
134
- if (opts.validate) {
135
- let prog: Buffer = NBuffer.alloc(0);
136
-
137
- if (a.address) {
138
- const dec = _address();
139
- if (network.bech32Opnet !== dec.prefix)
140
- throw new TypeError('Invalid prefix or network mismatch');
141
- if (dec.version !== P2OP_WITNESS_VERSION)
142
- throw new TypeError('Invalid witness version for p2op');
143
- if (dec.data.length < MIN_SIZE || dec.data.length > MAX_SIZE)
144
- throw new TypeError('Invalid witness program length');
145
- prog = dec.data;
146
- }
147
-
148
- if (a.program) {
149
- if (prog.length && !prog.equals(a.program)) throw new TypeError('Program mismatch');
150
- prog = a.program;
151
- }
152
-
153
- if (a.output) {
154
- const outProg = o.program!;
155
- if (prog.length && !prog.equals(outProg))
156
- throw new TypeError('Program mismatch (output vs other source)');
157
- prog = outProg;
158
- }
159
-
160
- if (prog.length < MIN_SIZE || prog.length > MAX_SIZE)
161
- throw new TypeError('Witness program must be 2–40 bytes');
162
-
163
- if (a.deploymentVersion !== undefined && a.deploymentVersion !== prog[0])
164
- throw new TypeError('deploymentVersion mismatch');
165
-
166
- if (a.hash160 && !a.hash160.equals(prog.slice(1))) throw new TypeError('hash160 mismatch');
167
- }
168
-
169
- return Object.assign(o, a);
170
- }
1
+ import { bech32m } from 'bech32';
2
+ import { Buffer as NBuffer } from 'buffer';
3
+ import { fromBech32 } from '../address.js';
4
+ import { bitcoin as BITCOIN_NETWORK, Network } from '../networks.js';
5
+ import * as bscript from '../script.js';
6
+ import { typeforce as typef } from '../types.js';
7
+ import * as lazy from './lazy.js';
8
+ import { BasePayment, P2OPPayment, PaymentOpts, PaymentType } from './index.js';
9
+
10
+ const OPS = bscript.OPS;
11
+ const P2OP_WITNESS_VERSION = 0x10;
12
+ const MIN_SIZE = 2;
13
+ const MAX_SIZE = 40;
14
+
15
+ interface P2OPBase extends BasePayment {
16
+ name: PaymentType.P2OP;
17
+ }
18
+
19
+ interface P2OP_fromOutput extends P2OPBase {
20
+ output: Buffer;
21
+
22
+ program?: undefined;
23
+ deploymentVersion?: undefined;
24
+ hash160?: undefined;
25
+ }
26
+
27
+ interface P2OP_fromProgram extends P2OPBase {
28
+ program: Buffer;
29
+
30
+ output?: undefined;
31
+ deploymentVersion?: never;
32
+ hash160?: never;
33
+ }
34
+
35
+ interface P2OP_fromParts extends P2OPBase {
36
+ deploymentVersion: number;
37
+ hash160: Buffer;
38
+
39
+ output?: undefined;
40
+ program?: undefined;
41
+ }
42
+
43
+ export type P2OPPaymentParams = P2OP_fromOutput | P2OP_fromProgram | P2OP_fromParts;
44
+
45
+ /**
46
+ * Pay-to-OPNet (P2OP) decoder / encoder.
47
+ *
48
+ * ▪ witness program = <deploymentVersion:uint8><hash160:20-bytes|...>
49
+ * ▪ scriptPubKey = OP_16 <program>
50
+ * ▪ address HRP = network.bech32Opnet, encoded with Bech32m
51
+ *
52
+ * Accepts any combination of { address, output, program } and returns a
53
+ * fully lazy payment object, mirroring the style of `p2tr`.
54
+ */
55
+ export function p2op(a: Omit<P2OPPaymentParams, 'name'>, opts?: PaymentOpts): P2OPPayment {
56
+ if (
57
+ !a.address &&
58
+ !a.output &&
59
+ !a.program &&
60
+ (typeof a.deploymentVersion === 'undefined' || !a.hash160)
61
+ ) {
62
+ throw new TypeError('At least one of address, output or program must be provided');
63
+ }
64
+
65
+ opts = Object.assign({ validate: true }, opts || {});
66
+
67
+ typef(
68
+ {
69
+ address: typef.maybe(typef.String),
70
+ output: typef.maybe(typef.Buffer),
71
+ program: typef.maybe(typef.Buffer),
72
+ network: typef.maybe(typef.Object),
73
+ deploymentVersion: typef.maybe(typef.Number),
74
+ hash160: typef.maybe(typef.BufferN(20)),
75
+ },
76
+ a,
77
+ );
78
+
79
+ const makeProgramFromParts = (): Buffer | undefined => {
80
+ if (typeof a.deploymentVersion !== 'undefined' && typeof a.hash160 !== 'undefined') {
81
+ if (a.hash160.length !== 20) throw new TypeError('hash160 must be exactly 20 bytes');
82
+ if (a.deploymentVersion < 0 || a.deploymentVersion > 0xff)
83
+ throw new TypeError('deploymentVersion must fit in one byte');
84
+ return Buffer.concat([Buffer.of(a.deploymentVersion), a.hash160]);
85
+ }
86
+ return undefined;
87
+ };
88
+
89
+ const _address = lazy.value(() => fromBech32(a.address!));
90
+
91
+ const network: Network = a.network || BITCOIN_NETWORK;
92
+ const o: P2OPPayment = {
93
+ name: PaymentType.P2OP,
94
+ network,
95
+ deploymentVersion: 0,
96
+ };
97
+
98
+ lazy.prop(o, 'program', () => {
99
+ if (a.program) return a.program;
100
+
101
+ // NEW: build from deploymentVersion+hash160
102
+ const fromParts = makeProgramFromParts();
103
+ if (fromParts) return fromParts;
104
+
105
+ if (a.output) {
106
+ if (a.output[0] !== OPS.OP_16) throw new TypeError('Invalid P2OP script');
107
+ let pushPos = 1,
108
+ progLen: number;
109
+ if (a.output[1] < 0x4c) {
110
+ progLen = a.output[1];
111
+ pushPos = 2;
112
+ } else if (a.output[1] === 0x4c) {
113
+ progLen = a.output[2];
114
+ pushPos = 3;
115
+ } else {
116
+ throw new TypeError('Unsupported push opcode in P2OP script');
117
+ }
118
+ return a.output.slice(pushPos, pushPos + progLen);
119
+ }
120
+
121
+ if (a.address) {
122
+ const dec = _address();
123
+ return dec.data;
124
+ }
125
+ });
126
+
127
+ lazy.prop(o, 'deploymentVersion', () => {
128
+ if (!o.program) return;
129
+ return o.program[0];
130
+ });
131
+
132
+ lazy.prop(o, 'hash160', () => {
133
+ if (!o.program) return;
134
+ return o.program.slice(1);
135
+ });
136
+
137
+ lazy.prop(o, 'output', () => {
138
+ if (!o.program) return;
139
+ return bscript.compile([OPS.OP_16, o.program]);
140
+ });
141
+
142
+ lazy.prop(o, 'address', () => {
143
+ if (!o.program) return;
144
+ if (!network.bech32Opnet) {
145
+ throw new TypeError('Network does not support opnet');
146
+ }
147
+
148
+ const words = bech32m.toWords(o.program);
149
+ words.unshift(P2OP_WITNESS_VERSION);
150
+
151
+ return bech32m.encode(network.bech32Opnet, words);
152
+ });
153
+
154
+ // extended validation
155
+ if (opts.validate) {
156
+ let prog: Buffer = NBuffer.alloc(0);
157
+
158
+ if (a.address) {
159
+ const dec = _address();
160
+ if (network.bech32Opnet !== dec.prefix)
161
+ throw new TypeError('Invalid prefix or network mismatch');
162
+ if (dec.version !== P2OP_WITNESS_VERSION)
163
+ throw new TypeError('Invalid witness version for p2op');
164
+ if (dec.data.length < MIN_SIZE || dec.data.length > MAX_SIZE)
165
+ throw new TypeError('Invalid witness program length');
166
+ prog = dec.data;
167
+ }
168
+
169
+ if (a.program) {
170
+ if (prog.length && !prog.equals(a.program)) throw new TypeError('Program mismatch');
171
+ prog = a.program;
172
+ }
173
+
174
+ if (!prog.length && a.deploymentVersion !== undefined && a.hash160) {
175
+ prog = makeProgramFromParts()!;
176
+ }
177
+
178
+ if (a.output) {
179
+ const outProg = o.program!;
180
+ if (prog.length && !prog.equals(outProg))
181
+ throw new TypeError('Program mismatch (output vs other source)');
182
+ prog = outProg;
183
+ }
184
+
185
+ if (prog.length < MIN_SIZE || prog.length > MAX_SIZE)
186
+ throw new TypeError(`Witness program must be 2–40 bytes. Was ${prog.length} bytes`);
187
+
188
+ if (a.deploymentVersion !== undefined && a.deploymentVersion !== prog[0])
189
+ throw new TypeError('deploymentVersion mismatch');
190
+
191
+ if (a.hash160 && !a.hash160.equals(prog.slice(1))) throw new TypeError('hash160 mismatch');
192
+ }
193
+
194
+ return Object.assign(o, a);
195
+ }
@@ -1,7 +1,7 @@
1
1
  import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
2
2
  import * as bscript from '../script.js';
3
3
  import { isPoint, typeforce as typef } from '../types.js';
4
- import { P2PKPayment, PaymentOpts, StackFunction } from './index.js';
4
+ import { P2PKPayment, PaymentOpts, PaymentType, StackFunction } from './index.js';
5
5
  import * as lazy from './lazy.js';
6
6
 
7
7
  const OPS = bscript.OPS;
@@ -39,7 +39,7 @@ export function p2pk(a: Omit<P2PKPayment, 'name'>, opts?: PaymentOpts): P2PKPaym
39
39
 
40
40
  const network = a.network || BITCOIN_NETWORK;
41
41
  const o: P2PKPayment = {
42
- name: 'p2pk',
42
+ name: PaymentType.P2PK,
43
43
  network,
44
44
  pubkey: undefined,
45
45
  };
@@ -3,7 +3,7 @@ import * as bcrypto from '../crypto.js';
3
3
  import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
4
4
  import * as bscript from '../script.js';
5
5
  import { isPoint, typeforce as typef } from '../types.js';
6
- import { P2PKHPayment, PaymentOpts, StackFunction } from './index.js';
6
+ import { P2PKHPayment, PaymentOpts, PaymentType, StackFunction } from './index.js';
7
7
  import * as lazy from './lazy.js';
8
8
  import { decompressPublicKey } from '../psbt/psbtutils.js';
9
9
 
@@ -53,7 +53,7 @@ export function p2pkh(a: Omit<P2PKHPayment, 'name'>, opts?: PaymentOpts): P2PKHP
53
53
 
54
54
  const network = a.network || BITCOIN_NETWORK;
55
55
  const o: P2PKHPayment = {
56
- name: 'p2pkh',
56
+ name: PaymentType.P2PKH,
57
57
  network,
58
58
  hash: undefined,
59
59
  };
@@ -3,7 +3,7 @@ import * as bcrypto from '../crypto.js';
3
3
  import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
4
4
  import * as bscript from '../script.js';
5
5
  import { stacksEqual, typeforce as typef } from '../types.js';
6
- import { P2SHPayment, Payment, PaymentOpts, ScriptRedeem, Stack, StackFunction } from './index.js';
6
+ import { P2SHPayment, Payment, PaymentOpts, PaymentType, ScriptRedeem, Stack, StackFunction } from './index.js';
7
7
  import * as lazy from './lazy.js';
8
8
 
9
9
  const OPS = bscript.OPS;
@@ -52,8 +52,7 @@ export function p2sh(a: Omit<P2SHPayment, 'name'>, opts?: PaymentOpts): P2SHPaym
52
52
 
53
53
  const o: P2SHPayment = {
54
54
  network,
55
- name: 'p2sh',
56
- hash: undefined,
55
+ name: PaymentType.P2SH
57
56
  };
58
57
 
59
58
  const _address = lazy.value(() => {
@@ -13,7 +13,7 @@ import {
13
13
  toHashTree,
14
14
  tweakKey,
15
15
  } from './bip341.js';
16
- import { P2TRPayment, PaymentOpts } from './index.js';
16
+ import { P2TRPayment, PaymentOpts, PaymentType } from './index.js';
17
17
  import * as lazy from './lazy.js';
18
18
 
19
19
  const OPS = bscript.OPS;
@@ -83,7 +83,7 @@ export function p2tr(a: Omit<P2TRPayment, 'name'>, opts?: PaymentOpts): P2TRPaym
83
83
 
84
84
  const network = a.network || BITCOIN_NETWORK;
85
85
  const o: P2TRPayment = {
86
- name: 'p2tr',
86
+ name: PaymentType.P2TR,
87
87
  network,
88
88
  };
89
89
 
@@ -3,7 +3,7 @@ import * as bcrypto from '../crypto.js';
3
3
  import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
4
4
  import * as bscript from '../script.js';
5
5
  import { isPoint, typeforce as typef } from '../types.js';
6
- import { P2WPKHPayment, PaymentOpts } from './index.js';
6
+ import { P2WPKHPayment, PaymentOpts, PaymentType } from './index.js';
7
7
  import * as lazy from './lazy.js';
8
8
 
9
9
  const OPS = bscript.OPS;
@@ -53,9 +53,8 @@ export function p2wpkh(a: Omit<P2WPKHPayment, 'name'>, opts?: PaymentOpts): P2WP
53
53
 
54
54
  const network = a.network || BITCOIN_NETWORK;
55
55
  const o: P2WPKHPayment = {
56
- name: 'p2wpkh',
57
- network,
58
- hash: undefined,
56
+ name: PaymentType.P2WPKH,
57
+ network
59
58
  };
60
59
 
61
60
  lazy.prop(o, 'address', () => {
@@ -3,7 +3,7 @@ import * as bcrypto from '../crypto.js';
3
3
  import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
4
4
  import * as bscript from '../script.js';
5
5
  import { isPoint, stacksEqual, typeforce as typef } from '../types.js';
6
- import { P2WSHPayment, PaymentOpts, StackElement, StackFunction } from './index.js';
6
+ import { P2WSHPayment, PaymentOpts, PaymentType, StackElement, StackFunction } from './index.js';
7
7
  import * as lazy from './lazy.js';
8
8
 
9
9
  const OPS = bscript.OPS;
@@ -75,8 +75,7 @@ export function p2wsh(a: Omit<P2WSHPayment, 'name'>, opts?: PaymentOpts): P2WSHP
75
75
 
76
76
  const o: P2WSHPayment = {
77
77
  network,
78
- name: 'p2wsh',
79
- hash: undefined,
78
+ name: PaymentType.P2WSH
80
79
  };
81
80
 
82
81
  lazy.prop(o, 'address', () => {
package/src/psbt.ts CHANGED
@@ -20,7 +20,7 @@ import { BIP32Interface } from 'bip32';
20
20
  import { ECPairInterface } from 'ecpair';
21
21
  import { fromOutputScript, toOutputScript } from './address.js';
22
22
  import { cloneBuffer, reverseBuffer } from './bufferutils.js';
23
- import { payments } from './index.js';
23
+ import { P2WSHPayment, payments } from './index.js';
24
24
  import { bitcoin as btcNetwork, Network } from './networks.js';
25
25
  import { tapleafHash } from './payments/bip341.js';
26
26
  import { P2SHPayment, Payment, PaymentOpts } from './payments/index.js';
@@ -1514,8 +1514,8 @@ export function prepareFinalScripts(
1514
1514
 
1515
1515
  // Wow, the payments API is very handy
1516
1516
  const payment: payments.Payment = getPayment(script, scriptType, partialSig);
1517
- const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment });
1518
- const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment });
1517
+ const p2wsh = !isP2WSH ? null : payments.p2wsh({ redeem: payment } as P2WSHPayment);
1518
+ const p2sh = !isP2SH ? null : payments.p2sh({ redeem: p2wsh || payment } as P2SHPayment);
1519
1519
 
1520
1520
  if (isSegwit) {
1521
1521
  if (p2wsh) {
@@ -1771,13 +1771,14 @@ function getPayment(
1771
1771
  ): payments.Payment {
1772
1772
  let payment: payments.Payment;
1773
1773
  switch (scriptType) {
1774
- case 'multisig':
1774
+ case 'multisig': {
1775
1775
  const sigs = getSortedSigs(script, partialSig);
1776
1776
  payment = payments.p2ms({
1777
1777
  output: script,
1778
1778
  signatures: sigs,
1779
1779
  });
1780
1780
  break;
1781
+ }
1781
1782
  case 'pubkey':
1782
1783
  payment = payments.p2pk({
1783
1784
  output: script,