@chainflip/bitcoin 1.2.7 → 2.1.0-beta.1

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.js DELETED
@@ -1,289 +0,0 @@
1
- import { assert } from '@chainflip/utils/assertion';
2
- import { hexToBytes, bytesToHex } from '@chainflip/utils/bytes';
3
- import * as bitcoin from 'bitcoinjs-lib';
4
- import * as base58 from '@chainflip/utils/base58';
5
- import { assetContractId, assetConstants } from '@chainflip/utils/chainflip';
6
- import { POLKADOT_SS58_PREFIX } from '@chainflip/utils/consts';
7
- import * as ss58 from '@chainflip/utils/ss58';
8
- import BigNumber2 from 'bignumber.js';
9
- import { parseUrlWithBasicAuth } from '@chainflip/utils/url';
10
- import { z } from 'zod';
11
- import { Struct, Bytes, u8, Vector, u16, u128 } from 'scale-ts';
12
-
13
- // src/address.ts
14
-
15
- // src/consts.ts
16
- var networkMap = {
17
- mainnet: "mainnet",
18
- perseverance: "testnet",
19
- sisyphos: "testnet",
20
- testnet: "testnet",
21
- backspin: "regtest",
22
- regtest: "regtest"
23
- };
24
-
25
- // src/address.ts
26
- var p2pkhAddressVersion = {
27
- mainnet: 0,
28
- testnet: 111,
29
- regtest: 111
30
- };
31
- var p2shAddressVersion = {
32
- mainnet: 5,
33
- testnet: 196,
34
- regtest: 196
35
- };
36
- var networkHrp = {
37
- mainnet: "bc",
38
- testnet: "tb",
39
- regtest: "bcrt"
40
- };
41
- var segwitVersions = {
42
- P2WPKH: 0,
43
- P2WSH: 0,
44
- Taproot: 1
45
- };
46
- var byteLikeToUint8Array = (data) => typeof data === "string" ? hexToBytes(data) : new Uint8Array(data);
47
- var encodeAddress = (data, kind, cfOrBtcnetwork) => {
48
- const btcNetwork = networkMap[cfOrBtcnetwork];
49
- assert(btcNetwork, `Invalid network: ${cfOrBtcnetwork}`);
50
- assert(data.length % 2 === 0, "bytes must have an even number of characters");
51
- assert(
52
- typeof data !== "string" || /^(0x)?[0-9a-f]*$/.test(data),
53
- "bytes are not a valid hex string"
54
- );
55
- const bytes = byteLikeToUint8Array(data);
56
- switch (kind) {
57
- case "P2PKH":
58
- case "P2SH": {
59
- const version = (kind === "P2SH" ? p2shAddressVersion : p2pkhAddressVersion)[btcNetwork];
60
- return bitcoin.address.toBase58Check(bytes, version);
61
- }
62
- case "P2WPKH":
63
- case "P2WSH":
64
- case "Taproot":
65
- return bitcoin.address.toBech32(bytes, segwitVersions[kind], networkHrp[btcNetwork]);
66
- default:
67
- throw new Error(`Invalid address type: ${kind}`);
68
- }
69
- };
70
- var decodeAddress = (address2, cfOrBtcNetwork) => {
71
- const network = networkMap[cfOrBtcNetwork];
72
- if (/^[13mn2]/.test(address2)) {
73
- const { hash, version } = bitcoin.address.fromBase58Check(address2);
74
- if (version === p2pkhAddressVersion[network]) {
75
- return { type: "P2PKH", data: hash, version };
76
- }
77
- if (version === p2shAddressVersion[network]) {
78
- return { type: "P2SH", data: hash, version };
79
- }
80
- throw new TypeError(`Invalid version: ${version}`);
81
- }
82
- if (/^(bc|tb|bcrt)1/.test(address2)) {
83
- const { data, prefix, version } = bitcoin.address.fromBech32(address2);
84
- assert(prefix === networkHrp[network], `Invalid prefix: ${prefix}`);
85
- let type;
86
- if (version === 0 && data.length === 20) {
87
- type = "P2WPKH";
88
- } else if (version === 0) {
89
- type = "P2WSH";
90
- } else if (version === 1) {
91
- type = "Taproot";
92
- } else {
93
- throw new TypeError(`Invalid version: ${version}`);
94
- }
95
- return { hrp: prefix, data, type, version };
96
- }
97
- throw new TypeError(`Invalid address "${address2}" for network "${network}"`);
98
- };
99
- var isValidAddressForNetwork = (address2, cfOrBtcNetwork) => {
100
- try {
101
- decodeAddress(address2, cfOrBtcNetwork);
102
- return true;
103
- } catch {
104
- return false;
105
- }
106
- };
107
- var hexString = z.string().regex(/^([0-9a-f]{2})+$/, { message: "expected hex string" });
108
- var vout = z.object({
109
- value: z.number().transform((n) => BigInt(new BigNumber2(n).shiftedBy(8).toFixed(0))),
110
- n: z.number()
111
- });
112
- var nulldataVout = z.object({
113
- scriptPubKey: z.object({
114
- type: z.literal("nulldata"),
115
- // remove OP_RETURN and PUSH_BYTES_XX
116
- hex: hexString.transform((x) => hexToBytes(`0x${x.slice(4)}`))
117
- })
118
- }).and(vout);
119
- var addressVout = z.object({
120
- scriptPubKey: z.object({
121
- type: z.enum([
122
- "witness_v1_taproot",
123
- "witness_v0_scripthash",
124
- "witness_v0_keyhash",
125
- "pubkeyhash",
126
- "scripthash"
127
- ]),
128
- address: z.string()
129
- })
130
- }).and(vout);
131
- var txSchema = z.object({
132
- vout: z.tuple([addressVout, nulldataVout, addressVout]),
133
- blockhash: hexString.nullish()
134
- });
135
- var blockSchema = z.object({
136
- height: z.number()
137
- });
138
- var responseSchemas = {
139
- getrawtransaction: txSchema,
140
- getblock: blockSchema
141
- };
142
- var rpcResponse = z.union([
143
- z.object({ result: z.null(), error: z.object({ code: z.number(), message: z.string() }) }),
144
- z.object({ result: z.unknown(), error: z.null() })
145
- ]);
146
- var makeRequest = async (rpcUrl, method, params) => {
147
- const { url, headers } = parseUrlWithBasicAuth(rpcUrl);
148
- const res = await fetch(url, {
149
- method: "POST",
150
- headers: {
151
- ...headers,
152
- "Content-Type": "application/json"
153
- },
154
- body: JSON.stringify({
155
- jsonrpc: "2.0",
156
- id: 1,
157
- method,
158
- params
159
- })
160
- });
161
- const text = await res.text();
162
- let json;
163
- try {
164
- json = JSON.parse(text);
165
- } catch {
166
- if (res.status !== 200) {
167
- throw new Error(`HTTP error [${res.status}]: ${text || res.statusText}`);
168
- }
169
- throw new Error(`Invalid JSON response: ${text}`);
170
- }
171
- const result = rpcResponse.parse(json);
172
- if (result.error) {
173
- if (result.error.code === -5) return null;
174
- throw new Error(`RPC error [${result.error.code}]: ${result.error.message}`);
175
- }
176
- const parseResult = responseSchemas[method].safeParse(result.result);
177
- if (!parseResult.success) {
178
- if (method === "getrawtransaction") return null;
179
- throw parseResult.error;
180
- }
181
- return parseResult.data;
182
- };
183
- var addressByteLengths = {
184
- Bitcoin: void 0,
185
- Arbitrum: 20,
186
- Ethereum: 20,
187
- Solana: 32,
188
- Polkadot: 32,
189
- Assethub: 32
190
- };
191
- var createSwapDataCodecV0 = (asset) => Struct({
192
- version: u8,
193
- destinationAsset: u8,
194
- destinationAddress: Bytes(addressByteLengths[assetConstants[asset].chain]),
195
- parameters: Struct({
196
- retryDuration: u16,
197
- minOutputAmount: u128,
198
- numberOfChunks: u16,
199
- chunkInterval: u16,
200
- boostFee: u8,
201
- brokerFee: u8,
202
- affiliates: Vector(Struct({ accountIndex: u8, commissionBps: u8 }))
203
- })
204
- });
205
- var createSwapDataCodecV1 = (asset) => Struct({
206
- version: u8,
207
- destinationAsset: u8,
208
- destinationAddress: Bytes(addressByteLengths[assetConstants[asset].chain]),
209
- parameters: Struct({
210
- retryDuration: u16,
211
- minOutputAmount: u128,
212
- maxOraclePriceSlippage: u8,
213
- numberOfChunks: u16,
214
- chunkInterval: u16,
215
- boostFee: u8,
216
- brokerFee: u8,
217
- affiliates: Vector(Struct({ accountIndex: u8, commissionBps: u8 }))
218
- })
219
- });
220
-
221
- // src/deposit.ts
222
- var encodeChainAddress = (data, asset) => {
223
- switch (assetConstants[asset].chain) {
224
- case "Solana":
225
- return base58.encode(data);
226
- case "Assethub":
227
- case "Polkadot":
228
- return ss58.encode({ data, ss58Format: POLKADOT_SS58_PREFIX });
229
- case "Ethereum":
230
- case "Arbitrum":
231
- return bytesToHex(data);
232
- case "Bitcoin":
233
- return new TextDecoder().decode(data);
234
- }
235
- };
236
- var contractIdToInternalAsset = Object.fromEntries(
237
- Object.entries(assetContractId).map(([asset, id]) => [id, asset])
238
- );
239
- var parseVaultSwapData = (data) => {
240
- const version = data[0];
241
- const contractId = data[1];
242
- const outputAsset = contractIdToInternalAsset[contractId];
243
- let destinationAddress;
244
- let parameters;
245
- if (version === 1) {
246
- ({ destinationAddress, parameters } = createSwapDataCodecV1(outputAsset).dec(data));
247
- } else if (version === 0) {
248
- ({ destinationAddress, parameters } = createSwapDataCodecV0(outputAsset).dec(data));
249
- } else {
250
- throw new Error("unsupported version");
251
- }
252
- assert(outputAsset, "unknown asset contract id");
253
- return {
254
- ...parameters,
255
- outputAsset,
256
- destinationAddress: encodeChainAddress(destinationAddress, outputAsset)
257
- };
258
- };
259
- var getX128PriceFromAmounts = (depositAmount, minOutputAmount) => BigInt(
260
- new BigNumber2(minOutputAmount.toString()).div(depositAmount.toString()).multipliedBy(new BigNumber2(2).pow(128)).toFixed(0, BigNumber2.ROUND_FLOOR)
261
- );
262
- var findVaultSwapData = async (url, txId) => {
263
- const tx = await makeRequest(url, "getrawtransaction", [txId, true]);
264
- if (!tx) return null;
265
- const data = parseVaultSwapData(tx.vout[1].scriptPubKey.hex);
266
- const amount = tx.vout[0].value;
267
- const block = tx.blockhash ? await makeRequest(url, "getblock", [tx.blockhash, true]).catch(() => null) : null;
268
- return {
269
- inputAsset: "Btc",
270
- amount,
271
- depositAddress: tx.vout[0].scriptPubKey.address,
272
- refundParams: {
273
- refundAddress: tx.vout[2].scriptPubKey.address,
274
- retryDuration: data.retryDuration,
275
- minPrice: getX128PriceFromAmounts(amount, data.minOutputAmount),
276
- maxOraclePriceSlippage: "maxOraclePriceSlippage" in data ? data.maxOraclePriceSlippage : null
277
- },
278
- destinationAddress: data.destinationAddress,
279
- outputAsset: data.outputAsset,
280
- brokerFee: { account: null, commissionBps: data.brokerFee },
281
- affiliateFees: data.affiliates,
282
- ccmDepositMetadata: null,
283
- maxBoostFee: data.boostFee,
284
- dcaParams: data.numberOfChunks === 1 && data.chunkInterval === 2 ? null : { chunkInterval: data.chunkInterval, numberOfChunks: data.numberOfChunks },
285
- depositChainBlockHeight: block && block.height
286
- };
287
- };
288
-
289
- export { decodeAddress, encodeAddress, findVaultSwapData, isValidAddressForNetwork };