@chainflip/bitcoin 1.0.1 → 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 +45 -179
- package/dist/index.d.cts +24 -4
- package/dist/index.d.ts +24 -4
- package/dist/index.mjs +44 -178
- 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,167 +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([version, ..._bytes.hexToBytes.call(void 0, data)]);
|
|
44
|
-
const checksum = _sha256.sha256.call(void 0, _sha256.sha256.call(void 0, payload)).slice(0, 4);
|
|
45
|
-
const address = base58.encode(Buffer.concat([payload, checksum]));
|
|
46
|
-
return address;
|
|
47
|
-
}
|
|
48
|
-
var BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
49
|
-
function decodeBech32(address) {
|
|
50
|
-
const pos = address.lastIndexOf("1");
|
|
51
|
-
if (pos === -1 || pos === 0 || pos + 7 > address.length) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
const hrp = address.substring(0, pos);
|
|
55
|
-
const data = [];
|
|
56
|
-
for (let i = pos + 1; i < address.length; i++) {
|
|
57
|
-
const charIndex = BECH32_CHARSET.indexOf(address[i]);
|
|
58
|
-
if (charIndex === -1)
|
|
59
|
-
return null;
|
|
60
|
-
data.push(charIndex);
|
|
61
|
-
}
|
|
62
|
-
return { hrp, data };
|
|
63
|
-
}
|
|
64
|
-
function polymod(values) {
|
|
65
|
-
const generators = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
66
|
-
let chk = 1;
|
|
67
|
-
for (const value of values) {
|
|
68
|
-
const top = chk >> 25;
|
|
69
|
-
chk = (chk & 33554431) << 5 ^ value;
|
|
70
|
-
for (let i = 0; i < 5; i++) {
|
|
71
|
-
if (top >> i & 1) {
|
|
72
|
-
chk ^= generators[i];
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return chk;
|
|
77
|
-
}
|
|
78
|
-
function hrpExpand(hrp) {
|
|
79
|
-
const ret = [];
|
|
80
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
81
|
-
ret.push(hrp.charCodeAt(i) >> 5);
|
|
82
|
-
}
|
|
83
|
-
ret.push(0);
|
|
84
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
85
|
-
ret.push(hrp.charCodeAt(i) & 31);
|
|
86
|
-
}
|
|
87
|
-
return ret;
|
|
88
|
-
}
|
|
89
|
-
function computeChecksum(hrp, data) {
|
|
90
|
-
return polymod(hrpExpand(hrp).concat(data));
|
|
91
|
-
}
|
|
92
|
-
var checksums = {
|
|
93
|
-
bech32: 1,
|
|
94
|
-
bech32m: 734539939
|
|
95
|
-
};
|
|
96
|
-
function convert5BitGroupsToBytes(data) {
|
|
97
|
-
let acc = 0;
|
|
98
|
-
let bits = 0;
|
|
99
|
-
const result = [];
|
|
100
|
-
for (let i = 0; i < data.length; i++) {
|
|
101
|
-
acc = acc << 5 | data[i];
|
|
102
|
-
bits += 5;
|
|
103
|
-
if (bits >= 8) {
|
|
104
|
-
result.push(acc >> bits - 8 & 255);
|
|
105
|
-
bits -= 8;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (bits > 0) {
|
|
109
|
-
const remainingByte = acc << 8 - bits & 255;
|
|
110
|
-
if (remainingByte !== 0 || bits > 5) {
|
|
111
|
-
result.push(remainingByte);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return new Uint8Array(result);
|
|
115
|
-
}
|
|
116
|
-
function decodeSegwitAddress(address) {
|
|
117
|
-
const decoded = decodeBech32(address.toLowerCase());
|
|
118
|
-
if (!decoded) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
const { hrp, data: dataWithChecksum } = decoded;
|
|
122
|
-
const checksum = computeChecksum(hrp, dataWithChecksum);
|
|
123
|
-
let type;
|
|
124
|
-
if (checksum === 1) {
|
|
125
|
-
type = "bech32";
|
|
126
|
-
} else if (checksum === 734539939) {
|
|
127
|
-
type = "bech32m";
|
|
128
|
-
} else {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
const data = convert5BitGroupsToBytes(dataWithChecksum.slice(1, -6));
|
|
132
|
-
const [version] = dataWithChecksum;
|
|
133
|
-
_assertion.assert.call(void 0, data.length >= 2 && data.length <= 40, "Invalid address");
|
|
134
|
-
_assertion.assert.call(void 0, version !== 0 || data.length === 20 || data.length === 32, "Invalid address");
|
|
135
|
-
return { hrp, data, type, version };
|
|
136
|
-
}
|
|
137
|
-
function createChecksum(hrp, data, variant) {
|
|
138
|
-
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
|
139
|
-
const polymodValue = polymod(values) ^ checksums[variant];
|
|
140
|
-
const checksum = [];
|
|
141
|
-
for (let i = 0; i < 6; i++) {
|
|
142
|
-
checksum.push(polymodValue >> 5 * (5 - i) & 31);
|
|
143
|
-
}
|
|
144
|
-
return checksum;
|
|
145
|
-
}
|
|
146
|
-
function encodeBech32(hrp, data) {
|
|
147
|
-
return `${hrp}1${data.map((i) => BECH32_CHARSET[i]).join("")}`;
|
|
148
|
-
}
|
|
149
|
-
function convertBytesTo5BitGroups(data) {
|
|
150
|
-
let acc = 0;
|
|
151
|
-
let bits = 0;
|
|
152
|
-
const result = [];
|
|
153
|
-
for (let i = 0; i < data.length; i++) {
|
|
154
|
-
acc = acc << 8 | data[i];
|
|
155
|
-
bits += 8;
|
|
156
|
-
while (bits >= 5) {
|
|
157
|
-
result.push(acc >> bits - 5 & 31);
|
|
158
|
-
bits -= 5;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (bits > 0) {
|
|
162
|
-
result.push(acc << 5 - bits & 31);
|
|
163
|
-
}
|
|
164
|
-
return result;
|
|
165
|
-
}
|
|
166
20
|
var segwitVersions = {
|
|
167
21
|
P2WPKH: 0,
|
|
168
22
|
P2WSH: 0,
|
|
169
23
|
Taproot: 1
|
|
170
24
|
};
|
|
171
|
-
function encodeSegwitAddress(hexData, kind, network) {
|
|
172
|
-
const variant = kind === "Taproot" ? "bech32m" : "bech32";
|
|
173
|
-
const bytes = _bytes.hexToBytes.call(void 0, hexData);
|
|
174
|
-
const version = segwitVersions[kind];
|
|
175
|
-
_assertion.assert.call(void 0, bytes.length >= 2 && bytes.length <= 40, "Invalid address");
|
|
176
|
-
_assertion.assert.call(void 0, version !== 0 || bytes.length === 20 || bytes.length === 32, "Invalid address");
|
|
177
|
-
const data = [segwitVersions[kind]].concat(convertBytesTo5BitGroups(bytes));
|
|
178
|
-
const hrp = networkHrp[network];
|
|
179
|
-
const checksum = createChecksum(hrp, data, variant);
|
|
180
|
-
return encodeBech32(hrp, data.concat(checksum));
|
|
181
|
-
}
|
|
182
25
|
var networkMap = {
|
|
183
26
|
mainnet: "mainnet",
|
|
184
27
|
perseverance: "testnet",
|
|
@@ -187,45 +30,68 @@ var networkMap = {
|
|
|
187
30
|
backspin: "regtest",
|
|
188
31
|
regtest: "regtest"
|
|
189
32
|
};
|
|
33
|
+
var byteLikeToUint8Array = (data) => typeof data === "string" ? _bytes.hexToBytes.call(void 0, data) : new Uint8Array(data);
|
|
190
34
|
var encodeAddress = (data, kind, cfOrBtcnetwork) => {
|
|
191
35
|
const btcNetwork = networkMap[cfOrBtcnetwork];
|
|
192
36
|
_assertion.assert.call(void 0, btcNetwork, `Invalid network: ${cfOrBtcnetwork}`);
|
|
193
37
|
_assertion.assert.call(void 0, data.length % 2 === 0, "bytes must have an even number of characters");
|
|
194
|
-
_assertion.assert.call(void 0,
|
|
38
|
+
_assertion.assert.call(void 0,
|
|
39
|
+
typeof data !== "string" || /^(0x)?[0-9a-f]*$/.test(data),
|
|
40
|
+
"bytes are not a valid hex string"
|
|
41
|
+
);
|
|
42
|
+
const bytes = byteLikeToUint8Array(data);
|
|
195
43
|
switch (kind) {
|
|
196
44
|
case "P2PKH":
|
|
197
|
-
case "P2SH":
|
|
198
|
-
|
|
45
|
+
case "P2SH": {
|
|
46
|
+
const version = (kind === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[btcNetwork];
|
|
47
|
+
return bitcoin.address.toBase58Check(bytes, version);
|
|
48
|
+
}
|
|
199
49
|
case "P2WPKH":
|
|
200
50
|
case "P2WSH":
|
|
201
51
|
case "Taproot":
|
|
202
|
-
return
|
|
52
|
+
return bitcoin.address.toBech32(bytes, segwitVersions[kind], networkHrp[btcNetwork]);
|
|
203
53
|
default:
|
|
204
54
|
throw new Error(`Invalid address type: ${kind}`);
|
|
205
55
|
}
|
|
206
56
|
};
|
|
207
|
-
var
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
return decodeSegwitAddress(address) !== null;
|
|
214
|
-
}
|
|
215
|
-
} else {
|
|
216
|
-
if (/^(m|n|2)/.test(address)) {
|
|
217
|
-
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 };
|
|
218
63
|
}
|
|
219
|
-
if (
|
|
220
|
-
return
|
|
64
|
+
if (version === p2shAddressVersion[network]) {
|
|
65
|
+
return { type: "P2SH", data: hash, version };
|
|
221
66
|
}
|
|
222
|
-
|
|
223
|
-
|
|
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}`);
|
|
224
80
|
}
|
|
81
|
+
return { hrp: prefix, data, type, version };
|
|
225
82
|
}
|
|
226
|
-
|
|
83
|
+
throw new TypeError(`Invalid address: ${address2}`);
|
|
227
84
|
};
|
|
85
|
+
var isValidAddressForNetwork = (address2, cfOrBtcNetwork) => {
|
|
86
|
+
try {
|
|
87
|
+
decodeAddress(address2, cfOrBtcNetwork);
|
|
88
|
+
return true;
|
|
89
|
+
} catch (e) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
228
94
|
|
|
229
95
|
|
|
230
96
|
|
|
231
|
-
exports.encodeAddress = encodeAddress; exports.isValidAddressForNetwork = isValidAddressForNetwork;
|
|
97
|
+
exports.decodeAddress = decodeAddress; exports.encodeAddress = encodeAddress; exports.isValidAddressForNetwork = isValidAddressForNetwork;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
type ChainflipNetwork = 'mainnet' | 'perseverance' | 'sisyphos' | 'backspin';
|
|
2
2
|
type BitcoinNetwork = 'mainnet' | 'testnet' | 'regtest';
|
|
3
|
-
type
|
|
4
|
-
declare const
|
|
5
|
-
|
|
3
|
+
type Bytelike = Uint8Array | number[] | `0x${string}`;
|
|
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;
|
|
6
26
|
|
|
7
|
-
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,7 +1,27 @@
|
|
|
1
1
|
type ChainflipNetwork = 'mainnet' | 'perseverance' | 'sisyphos' | 'backspin';
|
|
2
2
|
type BitcoinNetwork = 'mainnet' | 'testnet' | 'regtest';
|
|
3
|
-
type
|
|
4
|
-
declare const
|
|
5
|
-
|
|
3
|
+
type Bytelike = Uint8Array | number[] | `0x${string}`;
|
|
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;
|
|
6
26
|
|
|
7
|
-
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,167 +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([version, ...hexToBytes(data)]);
|
|
44
|
-
const checksum = sha256(sha256(payload)).slice(0, 4);
|
|
45
|
-
const address = base58.encode(Buffer.concat([payload, checksum]));
|
|
46
|
-
return address;
|
|
47
|
-
}
|
|
48
|
-
var BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
49
|
-
function decodeBech32(address) {
|
|
50
|
-
const pos = address.lastIndexOf("1");
|
|
51
|
-
if (pos === -1 || pos === 0 || pos + 7 > address.length) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
const hrp = address.substring(0, pos);
|
|
55
|
-
const data = [];
|
|
56
|
-
for (let i = pos + 1; i < address.length; i++) {
|
|
57
|
-
const charIndex = BECH32_CHARSET.indexOf(address[i]);
|
|
58
|
-
if (charIndex === -1)
|
|
59
|
-
return null;
|
|
60
|
-
data.push(charIndex);
|
|
61
|
-
}
|
|
62
|
-
return { hrp, data };
|
|
63
|
-
}
|
|
64
|
-
function polymod(values) {
|
|
65
|
-
const generators = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
66
|
-
let chk = 1;
|
|
67
|
-
for (const value of values) {
|
|
68
|
-
const top = chk >> 25;
|
|
69
|
-
chk = (chk & 33554431) << 5 ^ value;
|
|
70
|
-
for (let i = 0; i < 5; i++) {
|
|
71
|
-
if (top >> i & 1) {
|
|
72
|
-
chk ^= generators[i];
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return chk;
|
|
77
|
-
}
|
|
78
|
-
function hrpExpand(hrp) {
|
|
79
|
-
const ret = [];
|
|
80
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
81
|
-
ret.push(hrp.charCodeAt(i) >> 5);
|
|
82
|
-
}
|
|
83
|
-
ret.push(0);
|
|
84
|
-
for (let i = 0; i < hrp.length; i++) {
|
|
85
|
-
ret.push(hrp.charCodeAt(i) & 31);
|
|
86
|
-
}
|
|
87
|
-
return ret;
|
|
88
|
-
}
|
|
89
|
-
function computeChecksum(hrp, data) {
|
|
90
|
-
return polymod(hrpExpand(hrp).concat(data));
|
|
91
|
-
}
|
|
92
|
-
var checksums = {
|
|
93
|
-
bech32: 1,
|
|
94
|
-
bech32m: 734539939
|
|
95
|
-
};
|
|
96
|
-
function convert5BitGroupsToBytes(data) {
|
|
97
|
-
let acc = 0;
|
|
98
|
-
let bits = 0;
|
|
99
|
-
const result = [];
|
|
100
|
-
for (let i = 0; i < data.length; i++) {
|
|
101
|
-
acc = acc << 5 | data[i];
|
|
102
|
-
bits += 5;
|
|
103
|
-
if (bits >= 8) {
|
|
104
|
-
result.push(acc >> bits - 8 & 255);
|
|
105
|
-
bits -= 8;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (bits > 0) {
|
|
109
|
-
const remainingByte = acc << 8 - bits & 255;
|
|
110
|
-
if (remainingByte !== 0 || bits > 5) {
|
|
111
|
-
result.push(remainingByte);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return new Uint8Array(result);
|
|
115
|
-
}
|
|
116
|
-
function decodeSegwitAddress(address) {
|
|
117
|
-
const decoded = decodeBech32(address.toLowerCase());
|
|
118
|
-
if (!decoded) {
|
|
119
|
-
return null;
|
|
120
|
-
}
|
|
121
|
-
const { hrp, data: dataWithChecksum } = decoded;
|
|
122
|
-
const checksum = computeChecksum(hrp, dataWithChecksum);
|
|
123
|
-
let type;
|
|
124
|
-
if (checksum === 1) {
|
|
125
|
-
type = "bech32";
|
|
126
|
-
} else if (checksum === 734539939) {
|
|
127
|
-
type = "bech32m";
|
|
128
|
-
} else {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
const data = convert5BitGroupsToBytes(dataWithChecksum.slice(1, -6));
|
|
132
|
-
const [version] = dataWithChecksum;
|
|
133
|
-
assert(data.length >= 2 && data.length <= 40, "Invalid address");
|
|
134
|
-
assert(version !== 0 || data.length === 20 || data.length === 32, "Invalid address");
|
|
135
|
-
return { hrp, data, type, version };
|
|
136
|
-
}
|
|
137
|
-
function createChecksum(hrp, data, variant) {
|
|
138
|
-
const values = hrpExpand(hrp).concat(data).concat([0, 0, 0, 0, 0, 0]);
|
|
139
|
-
const polymodValue = polymod(values) ^ checksums[variant];
|
|
140
|
-
const checksum = [];
|
|
141
|
-
for (let i = 0; i < 6; i++) {
|
|
142
|
-
checksum.push(polymodValue >> 5 * (5 - i) & 31);
|
|
143
|
-
}
|
|
144
|
-
return checksum;
|
|
145
|
-
}
|
|
146
|
-
function encodeBech32(hrp, data) {
|
|
147
|
-
return `${hrp}1${data.map((i) => BECH32_CHARSET[i]).join("")}`;
|
|
148
|
-
}
|
|
149
|
-
function convertBytesTo5BitGroups(data) {
|
|
150
|
-
let acc = 0;
|
|
151
|
-
let bits = 0;
|
|
152
|
-
const result = [];
|
|
153
|
-
for (let i = 0; i < data.length; i++) {
|
|
154
|
-
acc = acc << 8 | data[i];
|
|
155
|
-
bits += 8;
|
|
156
|
-
while (bits >= 5) {
|
|
157
|
-
result.push(acc >> bits - 5 & 31);
|
|
158
|
-
bits -= 5;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
if (bits > 0) {
|
|
162
|
-
result.push(acc << 5 - bits & 31);
|
|
163
|
-
}
|
|
164
|
-
return result;
|
|
165
|
-
}
|
|
166
20
|
var segwitVersions = {
|
|
167
21
|
P2WPKH: 0,
|
|
168
22
|
P2WSH: 0,
|
|
169
23
|
Taproot: 1
|
|
170
24
|
};
|
|
171
|
-
function encodeSegwitAddress(hexData, kind, network) {
|
|
172
|
-
const variant = kind === "Taproot" ? "bech32m" : "bech32";
|
|
173
|
-
const bytes = hexToBytes(hexData);
|
|
174
|
-
const version = segwitVersions[kind];
|
|
175
|
-
assert(bytes.length >= 2 && bytes.length <= 40, "Invalid address");
|
|
176
|
-
assert(version !== 0 || bytes.length === 20 || bytes.length === 32, "Invalid address");
|
|
177
|
-
const data = [segwitVersions[kind]].concat(convertBytesTo5BitGroups(bytes));
|
|
178
|
-
const hrp = networkHrp[network];
|
|
179
|
-
const checksum = createChecksum(hrp, data, variant);
|
|
180
|
-
return encodeBech32(hrp, data.concat(checksum));
|
|
181
|
-
}
|
|
182
25
|
var networkMap = {
|
|
183
26
|
mainnet: "mainnet",
|
|
184
27
|
perseverance: "testnet",
|
|
@@ -187,45 +30,68 @@ var networkMap = {
|
|
|
187
30
|
backspin: "regtest",
|
|
188
31
|
regtest: "regtest"
|
|
189
32
|
};
|
|
33
|
+
var byteLikeToUint8Array = (data) => typeof data === "string" ? hexToBytes(data) : new Uint8Array(data);
|
|
190
34
|
var encodeAddress = (data, kind, cfOrBtcnetwork) => {
|
|
191
35
|
const btcNetwork = networkMap[cfOrBtcnetwork];
|
|
192
36
|
assert(btcNetwork, `Invalid network: ${cfOrBtcnetwork}`);
|
|
193
37
|
assert(data.length % 2 === 0, "bytes must have an even number of characters");
|
|
194
|
-
assert(
|
|
38
|
+
assert(
|
|
39
|
+
typeof data !== "string" || /^(0x)?[0-9a-f]*$/.test(data),
|
|
40
|
+
"bytes are not a valid hex string"
|
|
41
|
+
);
|
|
42
|
+
const bytes = byteLikeToUint8Array(data);
|
|
195
43
|
switch (kind) {
|
|
196
44
|
case "P2PKH":
|
|
197
|
-
case "P2SH":
|
|
198
|
-
|
|
45
|
+
case "P2SH": {
|
|
46
|
+
const version = (kind === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[btcNetwork];
|
|
47
|
+
return bitcoin.address.toBase58Check(bytes, version);
|
|
48
|
+
}
|
|
199
49
|
case "P2WPKH":
|
|
200
50
|
case "P2WSH":
|
|
201
51
|
case "Taproot":
|
|
202
|
-
return
|
|
52
|
+
return bitcoin.address.toBech32(bytes, segwitVersions[kind], networkHrp[btcNetwork]);
|
|
203
53
|
default:
|
|
204
54
|
throw new Error(`Invalid address type: ${kind}`);
|
|
205
55
|
}
|
|
206
56
|
};
|
|
207
|
-
var
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
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 };
|
|
214
63
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
return parseBase58Address(address, network) !== null;
|
|
64
|
+
if (version === p2shAddressVersion[network]) {
|
|
65
|
+
return { type: "P2SH", data: hash, version };
|
|
218
66
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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}`);
|
|
224
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;
|
|
225
91
|
}
|
|
226
|
-
return false;
|
|
227
92
|
};
|
|
228
93
|
export {
|
|
94
|
+
decodeAddress,
|
|
229
95
|
encodeAddress,
|
|
230
96
|
isValidAddressForNetwork
|
|
231
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",
|