@chainflip/bitcoin 1.0.2 → 1.1.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/index.cjs +41 -181
- package/dist/index.d.cts +23 -4
- package/dist/index.d.ts +23 -4
- package/dist/index.mjs +40 -180
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }// src/index.ts
|
|
2
2
|
var _assertion = require('@chainflip/utils/assertion');
|
|
3
|
-
var _base58 = require('@chainflip/utils/base58'); var base58 = _interopRequireWildcard(_base58);
|
|
4
3
|
var _bytes = require('@chainflip/utils/bytes');
|
|
5
|
-
var
|
|
4
|
+
var _bitcoinjslib = require('bitcoinjs-lib'); var bitcoin = _interopRequireWildcard(_bitcoinjslib);
|
|
6
5
|
var p2pkhAddressVersion = {
|
|
7
6
|
mainnet: 0,
|
|
8
7
|
testnet: 111,
|
|
@@ -18,170 +17,11 @@ var networkHrp = {
|
|
|
18
17
|
testnet: "tb",
|
|
19
18
|
regtest: "bcrt"
|
|
20
19
|
};
|
|
21
|
-
function parseBase58Address(address, network) {
|
|
22
|
-
const checksumLength = 4;
|
|
23
|
-
const payloadLength = 21;
|
|
24
|
-
const data = base58.decode(address);
|
|
25
|
-
if (data.length !== payloadLength + checksumLength)
|
|
26
|
-
return null;
|
|
27
|
-
const payload = data.slice(0, payloadLength);
|
|
28
|
-
const checksum = data.slice(-checksumLength);
|
|
29
|
-
const computedChecksum = _sha256.sha256.call(void 0, _sha256.sha256.call(void 0, payload)).slice(0, checksumLength);
|
|
30
|
-
if (!computedChecksum.every((byte, i) => byte === checksum[i]))
|
|
31
|
-
return null;
|
|
32
|
-
const [version, ...hash] = payload;
|
|
33
|
-
if (version === p2pkhAddressVersion[network]) {
|
|
34
|
-
return { type: "p2pkh", hash };
|
|
35
|
-
}
|
|
36
|
-
if (version === p2shAddressVersion[network]) {
|
|
37
|
-
return { type: "p2sh", hash };
|
|
38
|
-
}
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
function encodeBase58Address(data, network, type) {
|
|
42
|
-
const version = (type === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[network];
|
|
43
|
-
const payload = new Uint8Array([
|
|
44
|
-
version,
|
|
45
|
-
...typeof data === "string" ? _bytes.hexToBytes.call(void 0, data) : data
|
|
46
|
-
]);
|
|
47
|
-
const checksum = _sha256.sha256.call(void 0, _sha256.sha256.call(void 0, payload)).slice(0, 4);
|
|
48
|
-
const address = base58.encode(Buffer.concat([payload, checksum]));
|
|
49
|
-
return address;
|
|
50
|
-
}
|
|
51
|
-
var BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
52
|
-
function decodeBech32(address) {
|
|
53
|
-
const pos = address.lastIndexOf("1");
|
|
54
|
-
if (pos === -1 || pos === 0 || pos + 7 > address.length) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
const hrp = address.substring(0, pos);
|
|
58
|
-
const data = [];
|
|
59
|
-
for (let i = pos + 1; i < address.length; i++) {
|
|
60
|
-
const charIndex = BECH32_CHARSET.indexOf(address[i]);
|
|
61
|
-
if (charIndex === -1)
|
|
62
|
-
return null;
|
|
63
|
-
data.push(charIndex);
|
|
64
|
-
}
|
|
65
|
-
return { hrp, data };
|
|
66
|
-
}
|
|
67
|
-
function polymod(values) {
|
|
68
|
-
const generators = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
69
|
-
let chk = 1;
|
|
70
|
-
for (const value of values) {
|
|
71
|
-
const top = chk >> 25;
|
|
72
|
-
chk = (chk & 33554431) << 5 ^ value;
|
|
73
|
-
for (let i = 0; i < 5; i++) {
|
|
74
|
-
if (top >> i & 1) {
|
|
75
|
-
chk ^= generators[i];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return chk;
|
|
80
|
-
}
|
|
81
|
-
function hrpExpand(hrp) {
|
|
82
|
-
const ret = [];
|
|
83
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
84
|
-
ret.push(hrp.charCodeAt(i) >> 5);
|
|
85
|
-
}
|
|
86
|
-
ret.push(0);
|
|
87
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
88
|
-
ret.push(hrp.charCodeAt(i) & 31);
|
|
89
|
-
}
|
|
90
|
-
return ret;
|
|
91
|
-
}
|
|
92
|
-
function computeChecksum(hrp, data) {
|
|
93
|
-
return polymod(hrpExpand(hrp).concat(data));
|
|
94
|
-
}
|
|
95
|
-
var checksums = {
|
|
96
|
-
bech32: 1,
|
|
97
|
-
bech32m: 734539939
|
|
98
|
-
};
|
|
99
|
-
function convert5BitGroupsToBytes(data) {
|
|
100
|
-
let acc = 0;
|
|
101
|
-
let bits = 0;
|
|
102
|
-
const result = [];
|
|
103
|
-
for (let i = 0; i < data.length; i++) {
|
|
104
|
-
acc = acc << 5 | data[i];
|
|
105
|
-
bits += 5;
|
|
106
|
-
if (bits >= 8) {
|
|
107
|
-
result.push(acc >> bits - 8 & 255);
|
|
108
|
-
bits -= 8;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (bits > 0) {
|
|
112
|
-
const remainingByte = acc << 8 - bits & 255;
|
|
113
|
-
if (remainingByte !== 0 || bits > 5) {
|
|
114
|
-
result.push(remainingByte);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return new Uint8Array(result);
|
|
118
|
-
}
|
|
119
|
-
function decodeSegwitAddress(address) {
|
|
120
|
-
const decoded = decodeBech32(address.toLowerCase());
|
|
121
|
-
if (!decoded) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
const { hrp, data: dataWithChecksum } = decoded;
|
|
125
|
-
const checksum = computeChecksum(hrp, dataWithChecksum);
|
|
126
|
-
let type;
|
|
127
|
-
if (checksum === 1) {
|
|
128
|
-
type = "bech32";
|
|
129
|
-
} else if (checksum === 734539939) {
|
|
130
|
-
type = "bech32m";
|
|
131
|
-
} else {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
const data = convert5BitGroupsToBytes(dataWithChecksum.slice(1, -6));
|
|
135
|
-
const [version] = dataWithChecksum;
|
|
136
|
-
_assertion.assert.call(void 0, data.length >= 2 && data.length <= 40, "Invalid address");
|
|
137
|
-
_assertion.assert.call(void 0, version !== 0 || data.length === 20 || data.length === 32, "Invalid address");
|
|
138
|
-
return { hrp, data, type, version };
|
|
139
|
-
}
|
|
140
|
-
function createChecksum(hrp, data, variant) {
|
|
141
|
-
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
|
142
|
-
const polymodValue = polymod(values) ^ checksums[variant];
|
|
143
|
-
const checksum = [];
|
|
144
|
-
for (let i = 0; i < 6; i++) {
|
|
145
|
-
checksum.push(polymodValue >> 5 * (5 - i) & 31);
|
|
146
|
-
}
|
|
147
|
-
return checksum;
|
|
148
|
-
}
|
|
149
|
-
function encodeBech32(hrp, data) {
|
|
150
|
-
return `${hrp}1${data.map((i) => BECH32_CHARSET[i]).join("")}`;
|
|
151
|
-
}
|
|
152
|
-
function convertBytesTo5BitGroups(data) {
|
|
153
|
-
let acc = 0;
|
|
154
|
-
let bits = 0;
|
|
155
|
-
const result = [];
|
|
156
|
-
for (let i = 0; i < data.length; i++) {
|
|
157
|
-
acc = acc << 8 | data[i];
|
|
158
|
-
bits += 8;
|
|
159
|
-
while (bits >= 5) {
|
|
160
|
-
result.push(acc >> bits - 5 & 31);
|
|
161
|
-
bits -= 5;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (bits > 0) {
|
|
165
|
-
result.push(acc << 5 - bits & 31);
|
|
166
|
-
}
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
20
|
var segwitVersions = {
|
|
170
21
|
P2WPKH: 0,
|
|
171
22
|
P2WSH: 0,
|
|
172
23
|
Taproot: 1
|
|
173
24
|
};
|
|
174
|
-
function encodeSegwitAddress(byteData, kind, network) {
|
|
175
|
-
const variant = kind === "Taproot" ? "bech32m" : "bech32";
|
|
176
|
-
const bytes = typeof byteData === "string" ? _bytes.hexToBytes.call(void 0, byteData) : new Uint8Array(byteData);
|
|
177
|
-
const version = segwitVersions[kind];
|
|
178
|
-
_assertion.assert.call(void 0, bytes.length >= 2 && bytes.length <= 40, "Invalid address");
|
|
179
|
-
_assertion.assert.call(void 0, version !== 0 || bytes.length === 20 || bytes.length === 32, "Invalid address");
|
|
180
|
-
const data = [segwitVersions[kind]].concat(convertBytesTo5BitGroups(bytes));
|
|
181
|
-
const hrp = networkHrp[network];
|
|
182
|
-
const checksum = createChecksum(hrp, data, variant);
|
|
183
|
-
return encodeBech32(hrp, data.concat(checksum));
|
|
184
|
-
}
|
|
185
25
|
var networkMap = {
|
|
186
26
|
mainnet: "mainnet",
|
|
187
27
|
perseverance: "testnet",
|
|
@@ -190,6 +30,7 @@ var networkMap = {
|
|
|
190
30
|
backspin: "regtest",
|
|
191
31
|
regtest: "regtest"
|
|
192
32
|
};
|
|
33
|
+
var byteLikeToUint8Array = (data) => typeof data === "string" ? _bytes.hexToBytes.call(void 0, data) : new Uint8Array(data);
|
|
193
34
|
var encodeAddress = (data, kind, cfOrBtcnetwork) => {
|
|
194
35
|
const btcNetwork = networkMap[cfOrBtcnetwork];
|
|
195
36
|
_assertion.assert.call(void 0, btcNetwork, `Invalid network: ${cfOrBtcnetwork}`);
|
|
@@ -198,40 +39,59 @@ var encodeAddress = (data, kind, cfOrBtcnetwork) => {
|
|
|
198
39
|
typeof data !== "string" || /^(0x)?[0-9a-f]*$/.test(data),
|
|
199
40
|
"bytes are not a valid hex string"
|
|
200
41
|
);
|
|
42
|
+
const bytes = byteLikeToUint8Array(data);
|
|
201
43
|
switch (kind) {
|
|
202
44
|
case "P2PKH":
|
|
203
|
-
case "P2SH":
|
|
204
|
-
|
|
45
|
+
case "P2SH": {
|
|
46
|
+
const version = (kind === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[btcNetwork];
|
|
47
|
+
return bitcoin.address.toBase58Check(bytes, version);
|
|
48
|
+
}
|
|
205
49
|
case "P2WPKH":
|
|
206
50
|
case "P2WSH":
|
|
207
51
|
case "Taproot":
|
|
208
|
-
return
|
|
52
|
+
return bitcoin.address.toBech32(bytes, segwitVersions[kind], networkHrp[btcNetwork]);
|
|
209
53
|
default:
|
|
210
54
|
throw new Error(`Invalid address type: ${kind}`);
|
|
211
55
|
}
|
|
212
56
|
};
|
|
213
|
-
var
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return decodeSegwitAddress(address) !== null;
|
|
220
|
-
}
|
|
221
|
-
} else {
|
|
222
|
-
if (/^(m|n|2)/.test(address)) {
|
|
223
|
-
return parseBase58Address(address, network) !== null;
|
|
57
|
+
var decodeAddress = (address2, cfOrBtcNetwork) => {
|
|
58
|
+
if (/^[13mn2]/.test(address2)) {
|
|
59
|
+
const network = networkMap[cfOrBtcNetwork];
|
|
60
|
+
const { hash, version } = bitcoin.address.fromBase58Check(address2);
|
|
61
|
+
if (version === p2pkhAddressVersion[network]) {
|
|
62
|
+
return { type: "P2PKH", data: hash, version };
|
|
224
63
|
}
|
|
225
|
-
if (
|
|
226
|
-
return
|
|
64
|
+
if (version === p2shAddressVersion[network]) {
|
|
65
|
+
return { type: "P2SH", data: hash, version };
|
|
227
66
|
}
|
|
228
|
-
|
|
229
|
-
|
|
67
|
+
throw new TypeError(`Invalid version: ${version}`);
|
|
68
|
+
}
|
|
69
|
+
if (/^(bc|tb|bcrt)1/.test(address2)) {
|
|
70
|
+
const { data, prefix, version } = bitcoin.address.fromBech32(address2);
|
|
71
|
+
let type;
|
|
72
|
+
if (version === 0 && data.length === 20) {
|
|
73
|
+
type = "P2WPKH";
|
|
74
|
+
} else if (version === 0) {
|
|
75
|
+
type = "P2WSH";
|
|
76
|
+
} else if (version === 1) {
|
|
77
|
+
type = "Taproot";
|
|
78
|
+
} else {
|
|
79
|
+
throw new TypeError(`Invalid version: ${version}`);
|
|
230
80
|
}
|
|
81
|
+
return { hrp: prefix, data, type, version };
|
|
231
82
|
}
|
|
232
|
-
|
|
83
|
+
throw new TypeError(`Invalid address: ${address2}`);
|
|
233
84
|
};
|
|
85
|
+
var isValidAddressForNetwork = (address2, cfOrBtcNetwork) => {
|
|
86
|
+
try {
|
|
87
|
+
decodeAddress(address2, cfOrBtcNetwork);
|
|
88
|
+
return true;
|
|
89
|
+
} catch (e) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
234
94
|
|
|
235
95
|
|
|
236
96
|
|
|
237
|
-
exports.encodeAddress = encodeAddress; exports.isValidAddressForNetwork = isValidAddressForNetwork;
|
|
97
|
+
exports.decodeAddress = decodeAddress; exports.encodeAddress = encodeAddress; exports.isValidAddressForNetwork = isValidAddressForNetwork;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
type ChainflipNetwork = 'mainnet' | 'perseverance' | 'sisyphos' | 'backspin';
|
|
2
2
|
type BitcoinNetwork = 'mainnet' | 'testnet' | 'regtest';
|
|
3
3
|
type Bytelike = Uint8Array | number[] | `0x${string}`;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
declare const networkHrp: {
|
|
5
|
+
readonly mainnet: "bc";
|
|
6
|
+
readonly testnet: "tb";
|
|
7
|
+
readonly regtest: "bcrt";
|
|
8
|
+
};
|
|
9
|
+
type HRP = (typeof networkHrp)[keyof typeof networkHrp];
|
|
10
|
+
type Base58AddressType = 'P2SH' | 'P2PKH';
|
|
11
|
+
type DecodedBase58Address = {
|
|
12
|
+
type: Base58AddressType;
|
|
13
|
+
data: Uint8Array;
|
|
14
|
+
version: number;
|
|
15
|
+
};
|
|
16
|
+
type DecodedSegwitAddress = {
|
|
17
|
+
hrp: HRP;
|
|
18
|
+
data: Uint8Array;
|
|
19
|
+
type: SegwitAddressType;
|
|
20
|
+
version: number;
|
|
21
|
+
};
|
|
22
|
+
type SegwitAddressType = 'P2WPKH' | 'P2WSH' | 'Taproot';
|
|
23
|
+
declare const encodeAddress: (data: Bytelike, kind: Base58AddressType | SegwitAddressType, cfOrBtcnetwork: BitcoinNetwork | ChainflipNetwork) => string;
|
|
24
|
+
declare const decodeAddress: (address: string, cfOrBtcNetwork: BitcoinNetwork | ChainflipNetwork) => DecodedBase58Address | DecodedSegwitAddress;
|
|
25
|
+
declare const isValidAddressForNetwork: (address: string, cfOrBtcNetwork: BitcoinNetwork | ChainflipNetwork) => boolean;
|
|
7
26
|
|
|
8
|
-
export { encodeAddress, isValidAddressForNetwork };
|
|
27
|
+
export { type Base58AddressType, type BitcoinNetwork, type Bytelike, type ChainflipNetwork, type DecodedBase58Address, type DecodedSegwitAddress, type HRP, type SegwitAddressType, decodeAddress, encodeAddress, isValidAddressForNetwork };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
type ChainflipNetwork = 'mainnet' | 'perseverance' | 'sisyphos' | 'backspin';
|
|
2
2
|
type BitcoinNetwork = 'mainnet' | 'testnet' | 'regtest';
|
|
3
3
|
type Bytelike = Uint8Array | number[] | `0x${string}`;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
declare const networkHrp: {
|
|
5
|
+
readonly mainnet: "bc";
|
|
6
|
+
readonly testnet: "tb";
|
|
7
|
+
readonly regtest: "bcrt";
|
|
8
|
+
};
|
|
9
|
+
type HRP = (typeof networkHrp)[keyof typeof networkHrp];
|
|
10
|
+
type Base58AddressType = 'P2SH' | 'P2PKH';
|
|
11
|
+
type DecodedBase58Address = {
|
|
12
|
+
type: Base58AddressType;
|
|
13
|
+
data: Uint8Array;
|
|
14
|
+
version: number;
|
|
15
|
+
};
|
|
16
|
+
type DecodedSegwitAddress = {
|
|
17
|
+
hrp: HRP;
|
|
18
|
+
data: Uint8Array;
|
|
19
|
+
type: SegwitAddressType;
|
|
20
|
+
version: number;
|
|
21
|
+
};
|
|
22
|
+
type SegwitAddressType = 'P2WPKH' | 'P2WSH' | 'Taproot';
|
|
23
|
+
declare const encodeAddress: (data: Bytelike, kind: Base58AddressType | SegwitAddressType, cfOrBtcnetwork: BitcoinNetwork | ChainflipNetwork) => string;
|
|
24
|
+
declare const decodeAddress: (address: string, cfOrBtcNetwork: BitcoinNetwork | ChainflipNetwork) => DecodedBase58Address | DecodedSegwitAddress;
|
|
25
|
+
declare const isValidAddressForNetwork: (address: string, cfOrBtcNetwork: BitcoinNetwork | ChainflipNetwork) => boolean;
|
|
7
26
|
|
|
8
|
-
export { encodeAddress, isValidAddressForNetwork };
|
|
27
|
+
export { type Base58AddressType, type BitcoinNetwork, type Bytelike, type ChainflipNetwork, type DecodedBase58Address, type DecodedSegwitAddress, type HRP, type SegwitAddressType, decodeAddress, encodeAddress, isValidAddressForNetwork };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { assert } from "@chainflip/utils/assertion";
|
|
3
|
-
import * as base58 from "@chainflip/utils/base58";
|
|
4
3
|
import { hexToBytes } from "@chainflip/utils/bytes";
|
|
5
|
-
import
|
|
4
|
+
import * as bitcoin from "bitcoinjs-lib";
|
|
6
5
|
var p2pkhAddressVersion = {
|
|
7
6
|
mainnet: 0,
|
|
8
7
|
testnet: 111,
|
|
@@ -18,170 +17,11 @@ var networkHrp = {
|
|
|
18
17
|
testnet: "tb",
|
|
19
18
|
regtest: "bcrt"
|
|
20
19
|
};
|
|
21
|
-
function parseBase58Address(address, network) {
|
|
22
|
-
const checksumLength = 4;
|
|
23
|
-
const payloadLength = 21;
|
|
24
|
-
const data = base58.decode(address);
|
|
25
|
-
if (data.length !== payloadLength + checksumLength)
|
|
26
|
-
return null;
|
|
27
|
-
const payload = data.slice(0, payloadLength);
|
|
28
|
-
const checksum = data.slice(-checksumLength);
|
|
29
|
-
const computedChecksum = sha256(sha256(payload)).slice(0, checksumLength);
|
|
30
|
-
if (!computedChecksum.every((byte, i) => byte === checksum[i]))
|
|
31
|
-
return null;
|
|
32
|
-
const [version, ...hash] = payload;
|
|
33
|
-
if (version === p2pkhAddressVersion[network]) {
|
|
34
|
-
return { type: "p2pkh", hash };
|
|
35
|
-
}
|
|
36
|
-
if (version === p2shAddressVersion[network]) {
|
|
37
|
-
return { type: "p2sh", hash };
|
|
38
|
-
}
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
function encodeBase58Address(data, network, type) {
|
|
42
|
-
const version = (type === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[network];
|
|
43
|
-
const payload = new Uint8Array([
|
|
44
|
-
version,
|
|
45
|
-
...typeof data === "string" ? hexToBytes(data) : data
|
|
46
|
-
]);
|
|
47
|
-
const checksum = sha256(sha256(payload)).slice(0, 4);
|
|
48
|
-
const address = base58.encode(Buffer.concat([payload, checksum]));
|
|
49
|
-
return address;
|
|
50
|
-
}
|
|
51
|
-
var BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
52
|
-
function decodeBech32(address) {
|
|
53
|
-
const pos = address.lastIndexOf("1");
|
|
54
|
-
if (pos === -1 || pos === 0 || pos + 7 > address.length) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
const hrp = address.substring(0, pos);
|
|
58
|
-
const data = [];
|
|
59
|
-
for (let i = pos + 1; i < address.length; i++) {
|
|
60
|
-
const charIndex = BECH32_CHARSET.indexOf(address[i]);
|
|
61
|
-
if (charIndex === -1)
|
|
62
|
-
return null;
|
|
63
|
-
data.push(charIndex);
|
|
64
|
-
}
|
|
65
|
-
return { hrp, data };
|
|
66
|
-
}
|
|
67
|
-
function polymod(values) {
|
|
68
|
-
const generators = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
69
|
-
let chk = 1;
|
|
70
|
-
for (const value of values) {
|
|
71
|
-
const top = chk >> 25;
|
|
72
|
-
chk = (chk & 33554431) << 5 ^ value;
|
|
73
|
-
for (let i = 0; i < 5; i++) {
|
|
74
|
-
if (top >> i & 1) {
|
|
75
|
-
chk ^= generators[i];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return chk;
|
|
80
|
-
}
|
|
81
|
-
function hrpExpand(hrp) {
|
|
82
|
-
const ret = [];
|
|
83
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
84
|
-
ret.push(hrp.charCodeAt(i) >> 5);
|
|
85
|
-
}
|
|
86
|
-
ret.push(0);
|
|
87
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
88
|
-
ret.push(hrp.charCodeAt(i) & 31);
|
|
89
|
-
}
|
|
90
|
-
return ret;
|
|
91
|
-
}
|
|
92
|
-
function computeChecksum(hrp, data) {
|
|
93
|
-
return polymod(hrpExpand(hrp).concat(data));
|
|
94
|
-
}
|
|
95
|
-
var checksums = {
|
|
96
|
-
bech32: 1,
|
|
97
|
-
bech32m: 734539939
|
|
98
|
-
};
|
|
99
|
-
function convert5BitGroupsToBytes(data) {
|
|
100
|
-
let acc = 0;
|
|
101
|
-
let bits = 0;
|
|
102
|
-
const result = [];
|
|
103
|
-
for (let i = 0; i < data.length; i++) {
|
|
104
|
-
acc = acc << 5 | data[i];
|
|
105
|
-
bits += 5;
|
|
106
|
-
if (bits >= 8) {
|
|
107
|
-
result.push(acc >> bits - 8 & 255);
|
|
108
|
-
bits -= 8;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (bits > 0) {
|
|
112
|
-
const remainingByte = acc << 8 - bits & 255;
|
|
113
|
-
if (remainingByte !== 0 || bits > 5) {
|
|
114
|
-
result.push(remainingByte);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
return new Uint8Array(result);
|
|
118
|
-
}
|
|
119
|
-
function decodeSegwitAddress(address) {
|
|
120
|
-
const decoded = decodeBech32(address.toLowerCase());
|
|
121
|
-
if (!decoded) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
const { hrp, data: dataWithChecksum } = decoded;
|
|
125
|
-
const checksum = computeChecksum(hrp, dataWithChecksum);
|
|
126
|
-
let type;
|
|
127
|
-
if (checksum === 1) {
|
|
128
|
-
type = "bech32";
|
|
129
|
-
} else if (checksum === 734539939) {
|
|
130
|
-
type = "bech32m";
|
|
131
|
-
} else {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
const data = convert5BitGroupsToBytes(dataWithChecksum.slice(1, -6));
|
|
135
|
-
const [version] = dataWithChecksum;
|
|
136
|
-
assert(data.length >= 2 && data.length <= 40, "Invalid address");
|
|
137
|
-
assert(version !== 0 || data.length === 20 || data.length === 32, "Invalid address");
|
|
138
|
-
return { hrp, data, type, version };
|
|
139
|
-
}
|
|
140
|
-
function createChecksum(hrp, data, variant) {
|
|
141
|
-
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
|
142
|
-
const polymodValue = polymod(values) ^ checksums[variant];
|
|
143
|
-
const checksum = [];
|
|
144
|
-
for (let i = 0; i < 6; i++) {
|
|
145
|
-
checksum.push(polymodValue >> 5 * (5 - i) & 31);
|
|
146
|
-
}
|
|
147
|
-
return checksum;
|
|
148
|
-
}
|
|
149
|
-
function encodeBech32(hrp, data) {
|
|
150
|
-
return `${hrp}1${data.map((i) => BECH32_CHARSET[i]).join("")}`;
|
|
151
|
-
}
|
|
152
|
-
function convertBytesTo5BitGroups(data) {
|
|
153
|
-
let acc = 0;
|
|
154
|
-
let bits = 0;
|
|
155
|
-
const result = [];
|
|
156
|
-
for (let i = 0; i < data.length; i++) {
|
|
157
|
-
acc = acc << 8 | data[i];
|
|
158
|
-
bits += 8;
|
|
159
|
-
while (bits >= 5) {
|
|
160
|
-
result.push(acc >> bits - 5 & 31);
|
|
161
|
-
bits -= 5;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
if (bits > 0) {
|
|
165
|
-
result.push(acc << 5 - bits & 31);
|
|
166
|
-
}
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
20
|
var segwitVersions = {
|
|
170
21
|
P2WPKH: 0,
|
|
171
22
|
P2WSH: 0,
|
|
172
23
|
Taproot: 1
|
|
173
24
|
};
|
|
174
|
-
function encodeSegwitAddress(byteData, kind, network) {
|
|
175
|
-
const variant = kind === "Taproot" ? "bech32m" : "bech32";
|
|
176
|
-
const bytes = typeof byteData === "string" ? hexToBytes(byteData) : new Uint8Array(byteData);
|
|
177
|
-
const version = segwitVersions[kind];
|
|
178
|
-
assert(bytes.length >= 2 && bytes.length <= 40, "Invalid address");
|
|
179
|
-
assert(version !== 0 || bytes.length === 20 || bytes.length === 32, "Invalid address");
|
|
180
|
-
const data = [segwitVersions[kind]].concat(convertBytesTo5BitGroups(bytes));
|
|
181
|
-
const hrp = networkHrp[network];
|
|
182
|
-
const checksum = createChecksum(hrp, data, variant);
|
|
183
|
-
return encodeBech32(hrp, data.concat(checksum));
|
|
184
|
-
}
|
|
185
25
|
var networkMap = {
|
|
186
26
|
mainnet: "mainnet",
|
|
187
27
|
perseverance: "testnet",
|
|
@@ -190,6 +30,7 @@ var networkMap = {
|
|
|
190
30
|
backspin: "regtest",
|
|
191
31
|
regtest: "regtest"
|
|
192
32
|
};
|
|
33
|
+
var byteLikeToUint8Array = (data) => typeof data === "string" ? hexToBytes(data) : new Uint8Array(data);
|
|
193
34
|
var encodeAddress = (data, kind, cfOrBtcnetwork) => {
|
|
194
35
|
const btcNetwork = networkMap[cfOrBtcnetwork];
|
|
195
36
|
assert(btcNetwork, `Invalid network: ${cfOrBtcnetwork}`);
|
|
@@ -198,40 +39,59 @@ var encodeAddress = (data, kind, cfOrBtcnetwork) => {
|
|
|
198
39
|
typeof data !== "string" || /^(0x)?[0-9a-f]*$/.test(data),
|
|
199
40
|
"bytes are not a valid hex string"
|
|
200
41
|
);
|
|
42
|
+
const bytes = byteLikeToUint8Array(data);
|
|
201
43
|
switch (kind) {
|
|
202
44
|
case "P2PKH":
|
|
203
|
-
case "P2SH":
|
|
204
|
-
|
|
45
|
+
case "P2SH": {
|
|
46
|
+
const version = (kind === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[btcNetwork];
|
|
47
|
+
return bitcoin.address.toBase58Check(bytes, version);
|
|
48
|
+
}
|
|
205
49
|
case "P2WPKH":
|
|
206
50
|
case "P2WSH":
|
|
207
51
|
case "Taproot":
|
|
208
|
-
return
|
|
52
|
+
return bitcoin.address.toBech32(bytes, segwitVersions[kind], networkHrp[btcNetwork]);
|
|
209
53
|
default:
|
|
210
54
|
throw new Error(`Invalid address type: ${kind}`);
|
|
211
55
|
}
|
|
212
56
|
};
|
|
213
|
-
var
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
return decodeSegwitAddress(address) !== null;
|
|
57
|
+
var decodeAddress = (address2, cfOrBtcNetwork) => {
|
|
58
|
+
if (/^[13mn2]/.test(address2)) {
|
|
59
|
+
const network = networkMap[cfOrBtcNetwork];
|
|
60
|
+
const { hash, version } = bitcoin.address.fromBase58Check(address2);
|
|
61
|
+
if (version === p2pkhAddressVersion[network]) {
|
|
62
|
+
return { type: "P2PKH", data: hash, version };
|
|
220
63
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return parseBase58Address(address, network) !== null;
|
|
64
|
+
if (version === p2shAddressVersion[network]) {
|
|
65
|
+
return { type: "P2SH", data: hash, version };
|
|
224
66
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
67
|
+
throw new TypeError(`Invalid version: ${version}`);
|
|
68
|
+
}
|
|
69
|
+
if (/^(bc|tb|bcrt)1/.test(address2)) {
|
|
70
|
+
const { data, prefix, version } = bitcoin.address.fromBech32(address2);
|
|
71
|
+
let type;
|
|
72
|
+
if (version === 0 && data.length === 20) {
|
|
73
|
+
type = "P2WPKH";
|
|
74
|
+
} else if (version === 0) {
|
|
75
|
+
type = "P2WSH";
|
|
76
|
+
} else if (version === 1) {
|
|
77
|
+
type = "Taproot";
|
|
78
|
+
} else {
|
|
79
|
+
throw new TypeError(`Invalid version: ${version}`);
|
|
230
80
|
}
|
|
81
|
+
return { hrp: prefix, data, type, version };
|
|
82
|
+
}
|
|
83
|
+
throw new TypeError(`Invalid address: ${address2}`);
|
|
84
|
+
};
|
|
85
|
+
var isValidAddressForNetwork = (address2, cfOrBtcNetwork) => {
|
|
86
|
+
try {
|
|
87
|
+
decodeAddress(address2, cfOrBtcNetwork);
|
|
88
|
+
return true;
|
|
89
|
+
} catch {
|
|
90
|
+
return false;
|
|
231
91
|
}
|
|
232
|
-
return false;
|
|
233
92
|
};
|
|
234
93
|
export {
|
|
94
|
+
decodeAddress,
|
|
235
95
|
encodeAddress,
|
|
236
96
|
isValidAddressForNetwork
|
|
237
97
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chainflip/bitcoin",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": "https://github.com/chainflip-io/chainflip-product-toolkit.git",
|
|
6
6
|
"publishConfig": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"module": "dist/index.mjs",
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@chainflip/utils": "^0.4.0",
|
|
18
|
-
"
|
|
18
|
+
"bitcoinjs-lib": "^7.0.0-rc.0"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"prepublish": "pnpm build && pnpm test run",
|