@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 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 _sha256 = require('@noble/hashes/sha256');
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, /^(0x)?[0-9a-f]*$/.test(data), "bytes must be hex-encoded with a 0x prefix");
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
- return encodeBase58Address(data, btcNetwork, kind);
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 encodeSegwitAddress(data, kind, btcNetwork);
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 isValidAddressForNetwork = (address, network) => {
208
- if (network === "mainnet") {
209
- if (/^(1|3)/.test(address)) {
210
- return parseBase58Address(address, network) !== null;
211
- }
212
- if (/^bc1/.test(address)) {
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 (network === "regtest" && /^bcrt1/.test(address)) {
220
- return decodeSegwitAddress(address) !== null;
64
+ if (version === p2shAddressVersion[network]) {
65
+ return { type: "P2SH", data: hash, version };
221
66
  }
222
- if (network === "testnet" && /^tb1/.test(address)) {
223
- return decodeSegwitAddress(address) !== null;
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
- return false;
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 AddressType = 'P2WPKH' | 'P2SH' | 'P2PKH' | 'P2WSH' | 'Taproot';
4
- declare const encodeAddress: (data: `0x${string}`, kind: AddressType, cfOrBtcnetwork: BitcoinNetwork | ChainflipNetwork) => string;
5
- declare const isValidAddressForNetwork: (address: string, network: BitcoinNetwork) => boolean;
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 AddressType = 'P2WPKH' | 'P2SH' | 'P2PKH' | 'P2WSH' | 'Taproot';
4
- declare const encodeAddress: (data: `0x${string}`, kind: AddressType, cfOrBtcnetwork: BitcoinNetwork | ChainflipNetwork) => string;
5
- declare const isValidAddressForNetwork: (address: string, network: BitcoinNetwork) => boolean;
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 { sha256 } from "@noble/hashes/sha256";
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(/^(0x)?[0-9a-f]*$/.test(data), "bytes must be hex-encoded with a 0x prefix");
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
- return encodeBase58Address(data, btcNetwork, kind);
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 encodeSegwitAddress(data, kind, btcNetwork);
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 isValidAddressForNetwork = (address, network) => {
208
- if (network === "mainnet") {
209
- if (/^(1|3)/.test(address)) {
210
- return parseBase58Address(address, network) !== null;
211
- }
212
- if (/^bc1/.test(address)) {
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
- } else {
216
- if (/^(m|n|2)/.test(address)) {
217
- return parseBase58Address(address, network) !== null;
64
+ if (version === p2shAddressVersion[network]) {
65
+ return { type: "P2SH", data: hash, version };
218
66
  }
219
- if (network === "regtest" && /^bcrt1/.test(address)) {
220
- return decodeSegwitAddress(address) !== null;
221
- }
222
- if (network === "testnet" && /^tb1/.test(address)) {
223
- return decodeSegwitAddress(address) !== null;
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.1",
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
- "@noble/hashes": "^1.4.0"
18
+ "bitcoinjs-lib": "^7.0.0-rc.0"
19
19
  },
20
20
  "scripts": {
21
21
  "prepublish": "pnpm build && pnpm test run",