@swapkit/toolboxes 0.0.0-nightly-20250304130539

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