@btc-vision/bitcoin 6.4.1 → 6.4.3
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/browser/address.d.ts +1 -0
- package/browser/index.js +1 -1
- package/browser/payments/embed.d.ts +2 -2
- package/browser/payments/index.d.ts +61 -12
- package/browser/payments/lazy.d.ts +1 -1
- package/browser/payments/p2ms.d.ts +2 -2
- package/browser/payments/p2op.d.ts +25 -0
- package/browser/payments/p2pk.d.ts +2 -2
- package/browser/payments/p2pkh.d.ts +2 -2
- package/browser/payments/p2sh.d.ts +2 -2
- package/browser/payments/p2tr.d.ts +2 -2
- package/browser/payments/p2wpkh.d.ts +2 -2
- package/browser/payments/p2wsh.d.ts +2 -2
- package/browser/psbt/psbtutils.d.ts +1 -0
- package/build/address.js +4 -5
- package/build/payments/embed.d.ts +2 -2
- package/build/payments/embed.js +6 -2
- package/build/payments/index.d.ts +61 -12
- package/build/payments/index.js +1 -0
- package/build/payments/lazy.d.ts +1 -1
- package/build/payments/p2ms.d.ts +2 -2
- package/build/payments/p2ms.js +8 -2
- package/build/payments/p2op.d.ts +25 -0
- package/build/payments/p2op.js +112 -0
- package/build/payments/p2pk.d.ts +2 -2
- package/build/payments/p2pk.js +5 -1
- package/build/payments/p2pkh.d.ts +2 -2
- package/build/payments/p2pkh.js +5 -1
- package/build/payments/p2sh.d.ts +2 -2
- package/build/payments/p2sh.js +5 -1
- package/build/payments/p2tr.d.ts +2 -2
- package/build/payments/p2tr.js +5 -2
- package/build/payments/p2wpkh.d.ts +2 -2
- package/build/payments/p2wpkh.js +5 -1
- package/build/payments/p2wsh.d.ts +2 -2
- package/build/payments/p2wsh.js +5 -1
- package/build/psbt/psbtutils.d.ts +1 -0
- package/build/psbt/psbtutils.js +2 -0
- package/build/psbt.js +3 -1
- package/package.json +1 -1
- package/src/address.ts +283 -287
- package/src/payments/embed.ts +61 -55
- package/src/payments/index.ts +110 -13
- package/src/payments/lazy.ts +28 -28
- package/src/payments/p2ms.ts +11 -5
- package/src/payments/p2op.ts +170 -0
- package/src/payments/p2pk.ts +93 -85
- package/src/payments/p2pkh.ts +214 -210
- package/src/payments/p2sh.ts +211 -206
- package/src/payments/p2tr.ts +9 -4
- package/src/payments/p2wpkh.ts +7 -3
- package/src/payments/p2wsh.ts +7 -3
- package/src/psbt/psbtutils.ts +322 -320
- package/src/psbt.ts +5 -3
- package/test/payments.spec.ts +2 -2
package/src/payments/embed.ts
CHANGED
|
@@ -1,55 +1,61 @@
|
|
|
1
|
-
import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
|
|
2
|
-
import * as bscript from '../script.js';
|
|
3
|
-
import { stacksEqual, typeforce as typef } from '../types.js';
|
|
4
|
-
import {
|
|
5
|
-
import * as lazy from './lazy.js';
|
|
6
|
-
|
|
7
|
-
const OPS = bscript.OPS;
|
|
8
|
-
|
|
9
|
-
// output: OP_RETURN ...
|
|
10
|
-
/**
|
|
11
|
-
* Embeds data in a Bitcoin payment.
|
|
12
|
-
* @param a - The payment object.
|
|
13
|
-
* @param opts - Optional payment options.
|
|
14
|
-
* @returns The modified payment object.
|
|
15
|
-
* @throws {TypeError} If there is not enough data or if the output is invalid.
|
|
16
|
-
*/
|
|
17
|
-
export function p2data(a:
|
|
18
|
-
if (!a.data && !a.output) throw new TypeError('Not enough data');
|
|
19
|
-
opts = Object.assign({ validate: true }, opts || {});
|
|
20
|
-
|
|
21
|
-
typef(
|
|
22
|
-
{
|
|
23
|
-
network: typef.maybe(typef.Object),
|
|
24
|
-
output: typef.maybe(typef.Buffer),
|
|
25
|
-
data: typef.maybe(typef.arrayOf(typef.Buffer)),
|
|
26
|
-
},
|
|
27
|
-
a,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const network = a.network || BITCOIN_NETWORK;
|
|
31
|
-
const o = { name: 'embed', network
|
|
32
|
-
|
|
33
|
-
lazy.prop(o, 'output', () => {
|
|
34
|
-
if (!a.data) return;
|
|
35
|
-
return bscript.compile(([OPS.OP_RETURN] as Stack).concat(a.data));
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
import { bitcoin as BITCOIN_NETWORK } from '../networks.js';
|
|
2
|
+
import * as bscript from '../script.js';
|
|
3
|
+
import { stacksEqual, typeforce as typef } from '../types.js';
|
|
4
|
+
import { EmbedPayment, PaymentOpts, Stack } from './index.js';
|
|
5
|
+
import * as lazy from './lazy.js';
|
|
6
|
+
|
|
7
|
+
const OPS = bscript.OPS;
|
|
8
|
+
|
|
9
|
+
// output: OP_RETURN ...
|
|
10
|
+
/**
|
|
11
|
+
* Embeds data in a Bitcoin payment.
|
|
12
|
+
* @param a - The payment object.
|
|
13
|
+
* @param opts - Optional payment options.
|
|
14
|
+
* @returns The modified payment object.
|
|
15
|
+
* @throws {TypeError} If there is not enough data or if the output is invalid.
|
|
16
|
+
*/
|
|
17
|
+
export function p2data(a: Omit<EmbedPayment, 'name'>, opts?: PaymentOpts): EmbedPayment {
|
|
18
|
+
if (!a.data && !a.output) throw new TypeError('Not enough data');
|
|
19
|
+
opts = Object.assign({ validate: true }, opts || {});
|
|
20
|
+
|
|
21
|
+
typef(
|
|
22
|
+
{
|
|
23
|
+
network: typef.maybe(typef.Object),
|
|
24
|
+
output: typef.maybe(typef.Buffer),
|
|
25
|
+
data: typef.maybe(typef.arrayOf(typef.Buffer)),
|
|
26
|
+
},
|
|
27
|
+
a,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const network = a.network || BITCOIN_NETWORK;
|
|
31
|
+
const o: EmbedPayment = { name: 'embed', network, data: [] };
|
|
32
|
+
|
|
33
|
+
lazy.prop(o, 'output', () => {
|
|
34
|
+
if (!a.data) return;
|
|
35
|
+
return bscript.compile(([OPS.OP_RETURN] as Stack).concat(a.data));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
lazy.prop(o, 'data', () => {
|
|
39
|
+
if (!a.output) return;
|
|
40
|
+
const script = bscript.decompile(a.output);
|
|
41
|
+
if (script === null || script === undefined) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return script.slice(1) as Buffer[];
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// extended validation
|
|
49
|
+
if (opts.validate) {
|
|
50
|
+
if (a.output) {
|
|
51
|
+
const chunks = bscript.decompile(a.output);
|
|
52
|
+
if (chunks![0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid');
|
|
53
|
+
if (!chunks!.slice(1).every(typef.Buffer)) throw new TypeError('Output is invalid');
|
|
54
|
+
|
|
55
|
+
if (a.data && !stacksEqual(a.data, o.data as Buffer[]))
|
|
56
|
+
throw new TypeError('Data mismatch');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return Object.assign(o, a);
|
|
61
|
+
}
|
package/src/payments/index.ts
CHANGED
|
@@ -19,35 +19,132 @@ export * from './p2sh.js';
|
|
|
19
19
|
export * from './p2tr.js';
|
|
20
20
|
export * from './p2wpkh.js';
|
|
21
21
|
export * from './p2wsh.js';
|
|
22
|
+
export * from './p2op.js';
|
|
22
23
|
|
|
23
|
-
export interface
|
|
24
|
+
export interface BasePayment {
|
|
25
|
+
/** Convenience label, also the discriminant for the union. */
|
|
24
26
|
name?: string;
|
|
27
|
+
/** Network parameters (mainnet if omitted). */
|
|
25
28
|
network?: Network;
|
|
29
|
+
/** Fully-assembled scriptPubKey (if already known). */
|
|
26
30
|
output?: Buffer;
|
|
27
|
-
|
|
31
|
+
/** Raw scriptSig (legacy script types only). */
|
|
32
|
+
input?: Buffer;
|
|
33
|
+
/** Human-readable address (if already known). */
|
|
34
|
+
address?: string;
|
|
35
|
+
/** Segwit stack (empty for legacy). */
|
|
36
|
+
witness?: Buffer[];
|
|
37
|
+
|
|
38
|
+
/** Script template for P2SH, P2WSH, P2TR, etc. */
|
|
39
|
+
redeem?: ScriptRedeem;
|
|
40
|
+
|
|
41
|
+
/** Non-standard options used by some wallets. */
|
|
42
|
+
useHybrid?: boolean;
|
|
43
|
+
useUncompressed?: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Helper used by redeeming script-template outputs (P2SH, P2WSH). */
|
|
47
|
+
export interface ScriptRedeem extends BasePayment {
|
|
48
|
+
output?: Buffer; // script template
|
|
49
|
+
redeemVersion?: number; // tapscript leaves etc.
|
|
50
|
+
network?: Network; // network parameters (mainnet if omitted)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface P2PKPayment extends BasePayment {
|
|
54
|
+
name: 'p2pk';
|
|
55
|
+
pubkey?: Buffer;
|
|
56
|
+
/** DER-encoded sig – empty until signed. */
|
|
57
|
+
signature?: Buffer;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface P2PKHPayment extends BasePayment {
|
|
61
|
+
name: 'p2pkh';
|
|
62
|
+
/** RIPEMD-160(SHA-256(pubkey)) – 20 bytes. */
|
|
63
|
+
hash?: Buffer;
|
|
64
|
+
pubkey?: Buffer;
|
|
65
|
+
signature?: Buffer;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface P2SHPayment extends BasePayment {
|
|
69
|
+
name: 'p2sh';
|
|
70
|
+
/** Hash160 of a redeem script. */
|
|
71
|
+
hash?: Buffer;
|
|
72
|
+
|
|
73
|
+
/** The entire signature stack when spending a P2SH (non-segwit). */
|
|
74
|
+
signatures?: Buffer[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface P2MSPayment extends BasePayment {
|
|
78
|
+
name: 'p2ms';
|
|
79
|
+
/** M-of-N parameters. */
|
|
28
80
|
m?: number;
|
|
29
81
|
n?: number;
|
|
30
82
|
pubkeys?: Buffer[];
|
|
31
|
-
input?: Buffer;
|
|
32
83
|
signatures?: Buffer[];
|
|
33
|
-
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface P2WPKHPayment extends BasePayment {
|
|
87
|
+
name: 'p2wpkh';
|
|
88
|
+
/** 20-byte witness program. */
|
|
89
|
+
hash?: Buffer;
|
|
34
90
|
pubkey?: Buffer;
|
|
35
91
|
signature?: Buffer;
|
|
36
|
-
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface P2WSHPayment extends BasePayment {
|
|
95
|
+
name: 'p2wsh';
|
|
96
|
+
/** 32-byte witness program. */
|
|
37
97
|
hash?: Buffer;
|
|
38
|
-
redeem?:
|
|
39
|
-
|
|
98
|
+
redeem?: ScriptRedeem;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface P2TRPayment extends BasePayment {
|
|
102
|
+
name: 'p2tr';
|
|
103
|
+
/** x-only pubkey that commits to the tree. */
|
|
104
|
+
pubkey?: Buffer;
|
|
105
|
+
/** Internal (untweaked) x-only pubkey. */
|
|
106
|
+
internalPubkey?: Buffer;
|
|
107
|
+
/** Merkle-root tweak, present when a script path exists. */
|
|
108
|
+
hash?: Buffer;
|
|
109
|
+
/** Full taptree description (optional, dev-side). */
|
|
40
110
|
scriptTree?: Taptree;
|
|
41
|
-
|
|
111
|
+
/** Key-path sig or leading stack elem. */
|
|
112
|
+
signature?: Buffer;
|
|
42
113
|
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
114
|
+
redeemVersion?: number; // tapscript leaves etc.
|
|
115
|
+
redeem?: ScriptRedeem;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface P2OPPayment extends BasePayment {
|
|
119
|
+
name: 'p2op';
|
|
120
|
+
/** <deploymentVersion || HASH160(payload)> (2–40 bytes). */
|
|
121
|
+
program?: Buffer;
|
|
122
|
+
deploymentVersion: number | undefined;
|
|
123
|
+
/** Convenience slice of `program` (20 bytes for current spec). */
|
|
124
|
+
hash160?: Buffer;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** OP_RETURN data-carrying output */
|
|
128
|
+
export interface EmbedPayment extends BasePayment {
|
|
129
|
+
name: 'embed';
|
|
130
|
+
/** Raw pushed chunks after OP_RETURN. */
|
|
131
|
+
data: Buffer[];
|
|
132
|
+
// `output` is automatically derived from `data` (or vice-versa)
|
|
46
133
|
}
|
|
47
134
|
|
|
48
|
-
export type
|
|
135
|
+
export type Payment =
|
|
136
|
+
| P2PKPayment
|
|
137
|
+
| P2PKHPayment
|
|
138
|
+
| P2SHPayment
|
|
139
|
+
| P2MSPayment
|
|
140
|
+
| P2WPKHPayment
|
|
141
|
+
| P2WSHPayment
|
|
142
|
+
| P2TRPayment
|
|
143
|
+
| P2OPPayment
|
|
144
|
+
| EmbedPayment
|
|
145
|
+
| ScriptRedeem;
|
|
49
146
|
|
|
50
|
-
export type
|
|
147
|
+
export type PaymentCreator = <T extends BasePayment>(a: T, opts?: PaymentOpts) => T;
|
|
51
148
|
|
|
52
149
|
export interface PaymentOpts {
|
|
53
150
|
validate?: boolean;
|
package/src/payments/lazy.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
export function prop(object:
|
|
2
|
-
Object.defineProperty(object, name, {
|
|
3
|
-
configurable: true,
|
|
4
|
-
enumerable: true,
|
|
5
|
-
get():
|
|
6
|
-
const _value = f.call(this);
|
|
7
|
-
this[name] = _value;
|
|
8
|
-
return _value;
|
|
9
|
-
},
|
|
10
|
-
set(_value:
|
|
11
|
-
Object.defineProperty(this, name, {
|
|
12
|
-
configurable: true,
|
|
13
|
-
enumerable: true,
|
|
14
|
-
value: _value,
|
|
15
|
-
writable: true,
|
|
16
|
-
});
|
|
17
|
-
},
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function value<T>(f: () => T): () => T {
|
|
22
|
-
let _value: T;
|
|
23
|
-
return (): T => {
|
|
24
|
-
if (_value !== undefined) return _value;
|
|
25
|
-
_value = f();
|
|
26
|
-
return _value;
|
|
27
|
-
};
|
|
28
|
-
}
|
|
1
|
+
export function prop<T extends {}>(object: T, name: string, f: () => T[keyof T]): void {
|
|
2
|
+
Object.defineProperty(object, name, {
|
|
3
|
+
configurable: true,
|
|
4
|
+
enumerable: true,
|
|
5
|
+
get(): unknown {
|
|
6
|
+
const _value = f.call(this);
|
|
7
|
+
this[name] = _value;
|
|
8
|
+
return _value;
|
|
9
|
+
},
|
|
10
|
+
set(_value: unknown): void {
|
|
11
|
+
Object.defineProperty(this, name, {
|
|
12
|
+
configurable: true,
|
|
13
|
+
enumerable: true,
|
|
14
|
+
value: _value,
|
|
15
|
+
writable: true,
|
|
16
|
+
});
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function value<T>(f: () => T): () => T {
|
|
22
|
+
let _value: T;
|
|
23
|
+
return (): T => {
|
|
24
|
+
if (_value !== undefined) return _value;
|
|
25
|
+
_value = f();
|
|
26
|
+
return _value;
|
|
27
|
+
};
|
|
28
|
+
}
|
package/src/payments/p2ms.ts
CHANGED
|
@@ -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, stacksEqual, typeforce as typef } from '../types.js';
|
|
4
|
-
import {
|
|
4
|
+
import { P2MSPayment, PaymentOpts, Stack } from './index.js';
|
|
5
5
|
import * as lazy from './lazy.js';
|
|
6
6
|
|
|
7
7
|
const OPS = bscript.OPS;
|
|
@@ -17,7 +17,7 @@ const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
|
|
|
17
17
|
* @returns The created payment object.
|
|
18
18
|
* @throws {TypeError} If the provided data is not valid.
|
|
19
19
|
*/
|
|
20
|
-
export function p2ms(a:
|
|
20
|
+
export function p2ms(a: Omit<P2MSPayment, 'name'>, opts?: PaymentOpts): P2MSPayment {
|
|
21
21
|
if (!a.input && !a.output && !(a.pubkeys && a.m !== undefined) && !a.signatures)
|
|
22
22
|
throw new TypeError('Not enough data');
|
|
23
23
|
opts = Object.assign({ validate: true }, opts || {});
|
|
@@ -44,7 +44,10 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment {
|
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
const network = a.network || BITCOIN_NETWORK;
|
|
47
|
-
const o:
|
|
47
|
+
const o: P2MSPayment = {
|
|
48
|
+
network,
|
|
49
|
+
name: 'p2ms',
|
|
50
|
+
};
|
|
48
51
|
|
|
49
52
|
let chunks: Stack = [];
|
|
50
53
|
let decoded = false;
|
|
@@ -85,9 +88,12 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment {
|
|
|
85
88
|
decode(a.output);
|
|
86
89
|
return o.pubkeys;
|
|
87
90
|
});
|
|
88
|
-
lazy.prop(o, 'signatures', () => {
|
|
91
|
+
lazy.prop<P2MSPayment>(o, 'signatures', () => {
|
|
89
92
|
if (!a.input) return;
|
|
90
|
-
|
|
93
|
+
const decompiled = bscript.decompile(a.input);
|
|
94
|
+
if (decompiled === null || decompiled === undefined) return;
|
|
95
|
+
|
|
96
|
+
return decompiled.slice(1) as Buffer[];
|
|
91
97
|
});
|
|
92
98
|
lazy.prop(o, 'input', () => {
|
|
93
99
|
if (!a.signatures) return;
|
|
@@ -0,0 +1,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 } 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
|
+
}
|