@swapkit/toolboxes 1.0.0-beta.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.
Files changed (89) hide show
  1. package/dist/chunk-fazw0jvt.js +3 -0
  2. package/dist/chunk-fazw0jvt.js.map +9 -0
  3. package/dist/chunk-tvrdndbw.js +4 -0
  4. package/dist/chunk-tvrdndbw.js.map +9 -0
  5. package/dist/cosmos/index.cjs +3 -0
  6. package/dist/cosmos/index.cjs.map +19 -0
  7. package/dist/cosmos/index.js +3 -0
  8. package/dist/cosmos/index.js.map +19 -0
  9. package/dist/evm/index.cjs +3 -0
  10. package/dist/evm/index.cjs.map +24 -0
  11. package/dist/evm/index.js +3 -0
  12. package/dist/evm/index.js.map +24 -0
  13. package/dist/index.cjs +3 -0
  14. package/dist/index.cjs.map +9 -0
  15. package/dist/index.js +3 -0
  16. package/dist/index.js.map +9 -0
  17. package/dist/radix/index.cjs +3 -0
  18. package/dist/radix/index.cjs.map +10 -0
  19. package/dist/radix/index.js +3 -0
  20. package/dist/radix/index.js.map +10 -0
  21. package/dist/solana/index.cjs +3 -0
  22. package/dist/solana/index.cjs.map +10 -0
  23. package/dist/solana/index.js +3 -0
  24. package/dist/solana/index.js.map +10 -0
  25. package/dist/substrate/index.cjs +3 -0
  26. package/dist/substrate/index.cjs.map +12 -0
  27. package/dist/substrate/index.js +3 -0
  28. package/dist/substrate/index.js.map +12 -0
  29. package/dist/utxo/index.cjs +3 -0
  30. package/dist/utxo/index.cjs.map +18 -0
  31. package/dist/utxo/index.js +3 -0
  32. package/dist/utxo/index.js.map +18 -0
  33. package/package.json +105 -0
  34. package/src/cosmos/index.ts +11 -0
  35. package/src/cosmos/thorchainUtils/addressFormat.ts +24 -0
  36. package/src/cosmos/thorchainUtils/index.ts +4 -0
  37. package/src/cosmos/thorchainUtils/messages.ts +244 -0
  38. package/src/cosmos/thorchainUtils/registry.ts +47 -0
  39. package/src/cosmos/thorchainUtils/types/client-types.ts +80 -0
  40. package/src/cosmos/thorchainUtils/types/index.ts +1 -0
  41. package/src/cosmos/thorchainUtils/types/proto/MsgCompiled.js +2806 -0
  42. package/src/cosmos/thorchainUtils/types/proto/MsgCompiled.ts +2802 -0
  43. package/src/cosmos/thorchainUtils/util.ts +46 -0
  44. package/src/cosmos/toolbox/BaseCosmosToolbox.ts +254 -0
  45. package/src/cosmos/toolbox/gaia.ts +39 -0
  46. package/src/cosmos/toolbox/getToolboxByChain.ts +29 -0
  47. package/src/cosmos/toolbox/kujira.ts +61 -0
  48. package/src/cosmos/toolbox/thorchain.ts +321 -0
  49. package/src/cosmos/types.ts +31 -0
  50. package/src/cosmos/util.ts +230 -0
  51. package/src/evm/__tests__/ethereum.test.ts +147 -0
  52. package/src/evm/api.ts +157 -0
  53. package/src/evm/contracts/eth/multicall.ts +165 -0
  54. package/src/evm/contracts/op/gasOracle.ts +151 -0
  55. package/src/evm/helpers.ts +145 -0
  56. package/src/evm/index.ts +20 -0
  57. package/src/evm/provider.ts +6 -0
  58. package/src/evm/toolbox/EVMToolbox.ts +662 -0
  59. package/src/evm/toolbox/arb.ts +61 -0
  60. package/src/evm/toolbox/avax.ts +36 -0
  61. package/src/evm/toolbox/base.ts +42 -0
  62. package/src/evm/toolbox/bsc.ts +34 -0
  63. package/src/evm/toolbox/eth.ts +44 -0
  64. package/src/evm/toolbox/getToolboxByChain.ts +42 -0
  65. package/src/evm/toolbox/matic.ts +42 -0
  66. package/src/evm/toolbox/op.ts +163 -0
  67. package/src/evm/types.ts +118 -0
  68. package/src/index.ts +0 -0
  69. package/src/radix/index.ts +151 -0
  70. package/src/radix/toolbox.ts +693 -0
  71. package/src/solana/index.ts +49 -0
  72. package/src/solana/toolbox.ts +272 -0
  73. package/src/substrate/index.ts +3 -0
  74. package/src/substrate/toolbox/baseSubstrateToolbox.ts +286 -0
  75. package/src/substrate/toolbox/index.ts +40 -0
  76. package/src/substrate/types/index.ts +2 -0
  77. package/src/substrate/types/network.ts +42 -0
  78. package/src/substrate/types/wallet.ts +78 -0
  79. package/src/utxo/helpers/api.ts +431 -0
  80. package/src/utxo/helpers/bchaddrjs.ts +177 -0
  81. package/src/utxo/helpers/coinselect.ts +96 -0
  82. package/src/utxo/helpers/index.ts +5 -0
  83. package/src/utxo/helpers/txSize.ts +104 -0
  84. package/src/utxo/helpers/utils.ts +45 -0
  85. package/src/utxo/index.ts +9 -0
  86. package/src/utxo/toolbox/bitcoinCash.ts +281 -0
  87. package/src/utxo/toolbox/index.ts +37 -0
  88. package/src/utxo/toolbox/utxo.ts +360 -0
  89. package/src/utxo/types.ts +70 -0
@@ -0,0 +1,360 @@
1
+ import * as secp256k1 from "@bitcoinerlab/secp256k1";
2
+ import { HDKey } from "@scure/bip32";
3
+ import { mnemonicToSeedSync } from "@scure/bip39";
4
+ import {
5
+ AssetValue,
6
+ BaseDecimal,
7
+ Chain,
8
+ FeeOption,
9
+ SwapKitNumber,
10
+ type UTXOChain,
11
+ } from "@swapkit/helpers";
12
+ import { Psbt, address as btcLibAddress, initEccLib, payments } from "bitcoinjs-lib";
13
+ import type { ECPairInterface } from "ecpair";
14
+
15
+ import {
16
+ UTXOScriptType,
17
+ accumulative,
18
+ calculateTxSize,
19
+ compileMemo,
20
+ getDustThreshold,
21
+ getInputSize,
22
+ getNetwork,
23
+ getUtxoApi,
24
+ standardFeeRates,
25
+ } from "../helpers";
26
+ import type { TargetOutput, UTXOBuildTxParams, UTXOType, UTXOWalletTransferParams } from "../types";
27
+ import { validateAddress as validateBCHAddress } from "./bitcoinCash";
28
+ import type { BCHToolbox, BTCToolbox, DASHToolbox, DOGEToolbox, LTCToolbox } from "./index";
29
+
30
+ export const nonSegwitChains = [Chain.Dash, Chain.Dogecoin];
31
+
32
+ async function createKeysForPath({
33
+ phrase,
34
+ wif,
35
+ derivationPath,
36
+ chain,
37
+ }: { phrase?: string; wif?: string; derivationPath: string; chain: Chain }) {
38
+ const { ECPairFactory } = await import("ecpair");
39
+ if (!(wif || phrase)) throw new Error("Either phrase or wif must be provided");
40
+
41
+ const factory = ECPairFactory(secp256k1);
42
+ const network = getNetwork(chain);
43
+
44
+ if (wif) return factory.fromWIF(wif, network);
45
+
46
+ const seed = mnemonicToSeedSync(phrase as string);
47
+ const master = HDKey.fromMasterSeed(seed, network).derive(derivationPath);
48
+ if (!master.privateKey) throw new Error("Could not get private key from phrase");
49
+
50
+ return factory.fromPrivateKey(Buffer.from(master.privateKey), { network });
51
+ }
52
+
53
+ function validateAddress({ address, chain }: { address: string; chain: UTXOChain }) {
54
+ try {
55
+ initEccLib(secp256k1);
56
+ btcLibAddress.toOutputScript(address, getNetwork(chain));
57
+ return true;
58
+ } catch (_error) {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ function getAddressFromKeys({ keys, chain }: { chain: UTXOChain; keys: ECPairInterface }) {
64
+ if (!keys) throw new Error("Keys must be provided");
65
+
66
+ const method = nonSegwitChains.includes(chain) ? payments.p2pkh : payments.p2wpkh;
67
+ const { address } = method({ pubkey: keys.publicKey, network: getNetwork(chain) });
68
+ if (!address) throw new Error("Address not defined");
69
+
70
+ return address;
71
+ }
72
+
73
+ function transfer(chain: UTXOChain) {
74
+ return async function transfer({
75
+ signTransaction,
76
+ from,
77
+ memo,
78
+ recipient,
79
+ feeOptionKey,
80
+ broadcastTx,
81
+ feeRate,
82
+ assetValue,
83
+ }: UTXOWalletTransferParams<Psbt, Psbt>) {
84
+ if (!from) throw new Error("From address must be provided");
85
+ if (!recipient) throw new Error("Recipient address must be provided");
86
+ if (!signTransaction) throw new Error("Sign transaction must be provided");
87
+ const txFeeRate = feeRate || (await getFeeRates(chain))[feeOptionKey || FeeOption.Fast];
88
+
89
+ const { psbt } = await buildTx(chain)({
90
+ recipient,
91
+ feeRate: txFeeRate,
92
+ sender: from,
93
+ fetchTxHex: nonSegwitChains.includes(chain),
94
+ assetValue,
95
+ memo,
96
+ });
97
+ const signedPsbt = await signTransaction(psbt);
98
+ signedPsbt.finalizeAllInputs(); // Finalise inputs
99
+ // TX extracted and formatted to hex
100
+ return broadcastTx(signedPsbt.extractTransaction().toHex());
101
+ };
102
+ }
103
+
104
+ const getBalance = async ({ address, chain }: { address: string; chain: UTXOChain }) => {
105
+ const baseBalance = await getUtxoApi(chain).getBalance(address);
106
+ const balance = SwapKitNumber.fromBigInt(BigInt(baseBalance), BaseDecimal[chain]).getValue(
107
+ "string",
108
+ );
109
+ const asset = AssetValue.from({ asset: `${chain}.${chain}`, value: balance });
110
+
111
+ return [asset];
112
+ };
113
+
114
+ async function getFeeRates(chain: UTXOChain) {
115
+ const suggestedFeeRate = await getUtxoApi(chain).getSuggestedTxFee();
116
+
117
+ return standardFeeRates(suggestedFeeRate);
118
+ }
119
+
120
+ function getInputsAndTargetOutputs(chain: UTXOChain) {
121
+ return async function getInputsAndTargetOutputs({
122
+ assetValue,
123
+ recipient,
124
+ memo,
125
+ sender,
126
+ fetchTxHex = false,
127
+ }: {
128
+ assetValue: AssetValue;
129
+ recipient: string;
130
+ memo?: string;
131
+ sender: string;
132
+ fetchTxHex?: boolean;
133
+ }) {
134
+ const inputs = await getUtxoApi(chain).scanUTXOs({ address: sender, fetchTxHex });
135
+
136
+ //1. add output amount and recipient to targets
137
+ //2. add output memo to targets (optional)
138
+
139
+ return {
140
+ inputs,
141
+ outputs: [
142
+ { address: recipient, value: Number(assetValue.bigIntValue) },
143
+ ...(memo ? [{ address: "", script: compileMemo(memo), value: 0 }] : []),
144
+ ],
145
+ };
146
+ };
147
+ }
148
+
149
+ export function buildTx(chain: UTXOChain) {
150
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: TODO: refactor
151
+ return async function buildTx({
152
+ assetValue,
153
+ recipient,
154
+ memo,
155
+ feeRate,
156
+ sender,
157
+ fetchTxHex = false,
158
+ }: UTXOBuildTxParams): Promise<{
159
+ psbt: Psbt;
160
+ utxos: UTXOType[];
161
+ inputs: UTXOType[];
162
+ }> {
163
+ const compiledMemo = memo ? compileMemo(memo) : null;
164
+ const getInputsAndOutputs = getInputsAndTargetOutputs(chain);
165
+
166
+ const inputsAndOutputs = await getInputsAndOutputs({
167
+ assetValue,
168
+ recipient,
169
+ memo,
170
+ sender,
171
+ fetchTxHex,
172
+ });
173
+
174
+ const { inputs, outputs } = accumulative({ ...inputsAndOutputs, feeRate, chain });
175
+
176
+ // .inputs and .outputs will be undefined if no solution was found
177
+ if (!(inputs && outputs)) throw new Error("Insufficient Balance for transaction");
178
+ const psbt = new Psbt({ network: getNetwork(chain) });
179
+
180
+ if (chain === Chain.Dogecoin) psbt.setMaximumFeeRate(650000000);
181
+
182
+ for (const utxo of inputs) {
183
+ psbt.addInput({
184
+ hash: utxo.hash,
185
+ index: utxo.index,
186
+ ...(!!utxo.witnessUtxo &&
187
+ !nonSegwitChains.includes(chain) && { witnessUtxo: utxo.witnessUtxo }),
188
+ ...(nonSegwitChains.includes(chain) && {
189
+ nonWitnessUtxo: utxo.txHex ? Buffer.from(utxo.txHex, "hex") : undefined,
190
+ }),
191
+ });
192
+ }
193
+
194
+ for (const output of outputs) {
195
+ const address = "address" in output && output.address ? output.address : sender;
196
+ const params = output.script
197
+ ? compiledMemo
198
+ ? { script: compiledMemo, value: 0 }
199
+ : undefined
200
+ : { address, value: output.value };
201
+
202
+ if (params) {
203
+ initEccLib(secp256k1);
204
+ psbt.addOutput(params);
205
+ }
206
+ }
207
+
208
+ return { psbt, utxos: inputsAndOutputs.inputs, inputs };
209
+ };
210
+ }
211
+
212
+ function getInputsOutputsFee(chain: UTXOChain) {
213
+ return async function getInputsOutputsFee({
214
+ assetValue,
215
+ feeOptionKey = FeeOption.Fast,
216
+ feeRate,
217
+ fetchTxHex = false,
218
+ memo,
219
+ recipient,
220
+ from,
221
+ }: {
222
+ assetValue: AssetValue;
223
+ recipient: string;
224
+ memo?: string;
225
+ from: string;
226
+ feeOptionKey?: FeeOption;
227
+ feeRate?: number;
228
+ fetchTxHex?: boolean;
229
+ }) {
230
+ const getInputsAndOutputs = getInputsAndTargetOutputs(chain);
231
+ const inputsAndOutputs = await getInputsAndOutputs({
232
+ assetValue,
233
+ recipient,
234
+ memo,
235
+ sender: from,
236
+ fetchTxHex,
237
+ });
238
+
239
+ const feeRateWhole = feeRate ? Math.floor(feeRate) : (await getFeeRates(chain))[feeOptionKey];
240
+
241
+ return accumulative({ ...inputsAndOutputs, feeRate: feeRateWhole, chain });
242
+ };
243
+ }
244
+
245
+ function estimateMaxSendableAmount(chain: UTXOChain) {
246
+ return async function estimateMaxSendableAmount({
247
+ from,
248
+ memo,
249
+ feeRate,
250
+ feeOptionKey = FeeOption.Fast,
251
+ recipients = 1,
252
+ }: {
253
+ from: string;
254
+ memo?: string;
255
+ feeRate?: number;
256
+ feeOptionKey?: FeeOption;
257
+ recipients?: number | TargetOutput[];
258
+ }) {
259
+ const addressData = await getUtxoApi(chain).getAddressData(from);
260
+ const feeRateWhole = feeRate ? Math.ceil(feeRate) : (await getFeeRates(chain))[feeOptionKey];
261
+
262
+ const inputs = addressData?.utxo
263
+ .map((utxo) => ({
264
+ ...utxo,
265
+ // type: utxo.witnessUtxo ? UTXOScriptType.P2WPKH : UTXOScriptType.P2PKH,
266
+ type: UTXOScriptType.P2PKH,
267
+ hash: "",
268
+ }))
269
+ .filter(
270
+ (utxo) => utxo.value > Math.max(getDustThreshold(chain), getInputSize(utxo) * feeRateWhole),
271
+ );
272
+
273
+ if (!inputs?.length) return AssetValue.from({ chain });
274
+
275
+ const balance = AssetValue.from({
276
+ chain,
277
+ value: inputs.reduce((sum, utxo) => sum + utxo.value, 0),
278
+ });
279
+
280
+ const outputs =
281
+ typeof recipients === "number"
282
+ ? (Array.from({ length: recipients }, () => ({
283
+ address: from,
284
+ value: 0,
285
+ })) as TargetOutput[])
286
+ : recipients;
287
+
288
+ if (memo) {
289
+ const compiledMemo = compileMemo(memo);
290
+ outputs.push({ address: from, script: compiledMemo, value: 0 });
291
+ }
292
+
293
+ const txSize = calculateTxSize({ inputs, outputs, feeRate: feeRateWhole });
294
+
295
+ const fee = txSize * feeRateWhole;
296
+
297
+ return balance.sub(fee);
298
+ };
299
+ }
300
+
301
+ export const BaseUTXOToolbox = (chain: UTXOChain) => ({
302
+ accumulative,
303
+ calculateTxSize,
304
+ getFeeRates: () => getFeeRates(chain),
305
+ buildTx: buildTx(chain),
306
+ transfer: transfer(chain),
307
+ getInputsOutputsFee: getInputsOutputsFee(chain),
308
+
309
+ broadcastTx: (txHash: string) => getUtxoApi(chain).broadcastTx(txHash),
310
+ getAddressFromKeys: (keys: ECPairInterface) => getAddressFromKeys({ keys, chain }),
311
+ validateAddress: (address: string) => validateAddress({ address, chain }),
312
+ createKeysForPath: (params: any) => createKeysForPath({ ...params, chain }),
313
+
314
+ getPrivateKeyFromMnemonic: async (params: {
315
+ phrase: string;
316
+ derivationPath: string;
317
+ }) => {
318
+ const keys = await createKeysForPath({ ...params, chain });
319
+ return keys.toWIF();
320
+ },
321
+
322
+ getBalance: async (address: string, _potentialScamFilter?: boolean) =>
323
+ getBalance({ address, chain }),
324
+
325
+ estimateTransactionFee: async (params: {
326
+ assetValue: AssetValue;
327
+ recipient: string;
328
+ from: string;
329
+ memo?: string;
330
+ feeOptionKey?: FeeOption;
331
+ feeRate?: number;
332
+ fetchTxHex?: boolean;
333
+ }) => {
334
+ const getInputsFee = getInputsOutputsFee(chain);
335
+ const inputFees = await getInputsFee(params);
336
+
337
+ return AssetValue.from({
338
+ chain,
339
+ value: SwapKitNumber.fromBigInt(BigInt(inputFees.fee), 8).getValue("string"),
340
+ });
341
+ },
342
+
343
+ estimateMaxSendableAmount: async (params: any) => estimateMaxSendableAmount({ ...params, chain }),
344
+ });
345
+
346
+ export function utxoValidateAddress({ chain, address }: { chain: UTXOChain; address: string }) {
347
+ return chain === Chain.BitcoinCash
348
+ ? validateBCHAddress(address)
349
+ : validateAddress({ address, chain });
350
+ }
351
+
352
+ export type BaseUTXOWallet = ReturnType<typeof BaseUTXOToolbox>;
353
+ type UTXOWalletType = {
354
+ [Chain.Bitcoin]: ReturnType<typeof BTCToolbox>;
355
+ [Chain.BitcoinCash]: ReturnType<typeof BCHToolbox>;
356
+ [Chain.Dogecoin]: ReturnType<typeof DOGEToolbox>;
357
+ [Chain.Litecoin]: ReturnType<typeof LTCToolbox>;
358
+ [Chain.Dash]: ReturnType<typeof DASHToolbox>;
359
+ };
360
+ export type UTXOWallets = { [chain in UTXOChain]: BaseUTXOWallet & UTXOWalletType[chain] };
@@ -0,0 +1,70 @@
1
+ import type { AssetValue, FeeOption, UTXOChain, Witness } from "@swapkit/helpers";
2
+
3
+ import type { UTXOScriptType } from "./helpers";
4
+ import type { BCHToolbox, BTCToolbox, DOGEToolbox, LTCToolbox } from "./index";
5
+
6
+ export type TransactionType = {
7
+ toHex(): string;
8
+ };
9
+
10
+ export type TargetOutput =
11
+ | { address: string; script?: Buffer; value: number }
12
+ | { script: Buffer; value: number };
13
+
14
+ export type TransactionBuilderType = {
15
+ inputs: any[];
16
+ sign(
17
+ vin: number,
18
+ keyPair: { getAddress: (index?: number) => string },
19
+ redeemScript?: Buffer,
20
+ hashType?: number,
21
+ witnessValue?: number,
22
+ witnessScript?: Buffer,
23
+ signatureAlgorithm?: string,
24
+ ): void;
25
+ build(): TransactionType;
26
+ };
27
+
28
+ export type UTXOToolbox = ReturnType<
29
+ typeof BTCToolbox | typeof BCHToolbox | typeof DOGEToolbox | typeof LTCToolbox
30
+ >;
31
+
32
+ export type UTXOType = {
33
+ hash: string;
34
+ index: number;
35
+ value: number;
36
+ txHex?: string;
37
+ witnessUtxo?: Witness;
38
+ };
39
+
40
+ export type UTXOInputWithScriptType = UTXOType & { type: UTXOScriptType; address: string };
41
+
42
+ export type UTXOCalculateTxSizeParams = {
43
+ inputs: (UTXOInputWithScriptType | UTXOType)[];
44
+ outputs?: TargetOutput[];
45
+ feeRate: number;
46
+ };
47
+
48
+ export type UTXOBuildTxParams = {
49
+ assetValue: AssetValue;
50
+ recipient: string;
51
+ memo?: string;
52
+ feeRate: number;
53
+ sender: string;
54
+ fetchTxHex?: boolean;
55
+ };
56
+
57
+ export type UTXOTransferParams = {
58
+ broadcastTx: (txHex: string) => Promise<string>;
59
+ chain: UTXOChain;
60
+ feeOptionKey?: FeeOption;
61
+ feeRate?: number;
62
+ from: string;
63
+ recipient: string;
64
+ assetValue: AssetValue;
65
+ memo?: string;
66
+ };
67
+
68
+ export type UTXOWalletTransferParams<T, U> = UTXOTransferParams & {
69
+ signTransaction?: (params: T) => Promise<U>;
70
+ };