@swapkit/toolboxes 1.0.0-beta.3 → 1.0.0-beta.31

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 (131) hide show
  1. package/dist/{chunk-fjfxga2v.js → chunk-5yxc1e69.js} +1 -1
  2. package/dist/{chunk-fjfxga2v.js.map → chunk-5yxc1e69.js.map} +1 -1
  3. package/dist/chunk-6f98phv2.js +4 -0
  4. package/dist/{chunk-0h4xdrwz.js.map → chunk-6f98phv2.js.map} +2 -2
  5. package/dist/{chunk-0f0249b1.js → chunk-9bqegm61.js} +1 -1
  6. package/dist/{chunk-p1kdg37m.js → chunk-s47y8512.js} +2 -2
  7. package/dist/{chunk-p1kdg37m.js.map → chunk-s47y8512.js.map} +1 -1
  8. package/dist/chunk-vtd17cje.js +3 -0
  9. package/dist/chunk-vtd17cje.js.map +10 -0
  10. package/dist/chunk-zcdeg6h9.js +4 -0
  11. package/dist/chunk-zcdeg6h9.js.map +10 -0
  12. package/dist/src/cosmos/index.cjs +3 -0
  13. package/dist/src/cosmos/index.cjs.map +16 -0
  14. package/dist/src/cosmos/index.js +3 -0
  15. package/dist/src/cosmos/index.js.map +16 -0
  16. package/dist/src/evm/index.cjs +3 -0
  17. package/dist/src/evm/index.cjs.map +18 -0
  18. package/dist/src/evm/index.js +3 -0
  19. package/dist/src/evm/index.js.map +18 -0
  20. package/dist/src/index.cjs +3 -0
  21. package/dist/src/index.cjs.map +10 -0
  22. package/dist/src/index.js +3 -0
  23. package/dist/src/index.js.map +10 -0
  24. package/dist/src/near/index.cjs +3 -0
  25. package/dist/src/near/index.cjs.map +13 -0
  26. package/dist/src/near/index.js +3 -0
  27. package/dist/src/near/index.js.map +13 -0
  28. package/dist/{radix → src/radix}/index.cjs +2 -2
  29. package/dist/src/radix/index.cjs.map +10 -0
  30. package/dist/src/radix/index.js +3 -0
  31. package/dist/src/radix/index.js.map +10 -0
  32. package/dist/src/ripple/index.cjs +3 -0
  33. package/dist/src/ripple/index.cjs.map +10 -0
  34. package/dist/src/ripple/index.js +3 -0
  35. package/dist/src/ripple/index.js.map +10 -0
  36. package/dist/src/solana/index.cjs +3 -0
  37. package/dist/src/solana/index.cjs.map +10 -0
  38. package/dist/src/solana/index.js +3 -0
  39. package/dist/src/solana/index.js.map +10 -0
  40. package/dist/src/substrate/index.cjs +3 -0
  41. package/dist/src/substrate/index.cjs.map +12 -0
  42. package/dist/src/substrate/index.js +3 -0
  43. package/dist/src/substrate/index.js.map +12 -0
  44. package/dist/src/tron/index.cjs +3 -0
  45. package/dist/src/tron/index.cjs.map +11 -0
  46. package/dist/src/tron/index.js +3 -0
  47. package/dist/src/tron/index.js.map +11 -0
  48. package/dist/src/utxo/index.cjs +5 -0
  49. package/dist/src/utxo/index.cjs.map +17 -0
  50. package/dist/src/utxo/index.js +5 -0
  51. package/dist/src/utxo/index.js.map +17 -0
  52. package/package.json +49 -37
  53. package/src/cosmos/thorchainUtils/addressFormat.ts +4 -1
  54. package/src/cosmos/thorchainUtils/messages.ts +2 -2
  55. package/src/cosmos/thorchainUtils/registry.ts +3 -3
  56. package/src/cosmos/toolbox/cosmos.ts +35 -16
  57. package/src/cosmos/toolbox/index.ts +2 -2
  58. package/src/cosmos/toolbox/thorchain.ts +11 -9
  59. package/src/cosmos/util.ts +76 -6
  60. package/src/evm/__tests__/address-validation.test.ts +86 -0
  61. package/src/evm/__tests__/ethereum.test.ts +1 -1
  62. package/src/evm/helpers.ts +4 -3
  63. package/src/evm/toolbox/baseEVMToolbox.ts +37 -25
  64. package/src/evm/toolbox/index.ts +2 -2
  65. package/src/evm/toolbox/op.ts +21 -7
  66. package/src/index.ts +118 -100
  67. package/src/near/__tests__/core.test.ts +80 -0
  68. package/src/near/helpers/contractFactory.ts +22 -0
  69. package/src/near/helpers/core.ts +89 -0
  70. package/src/near/helpers/gasEstimation.ts +110 -0
  71. package/src/near/helpers/index.ts +5 -0
  72. package/src/near/helpers/nep141.ts +110 -0
  73. package/src/near/index.ts +24 -0
  74. package/src/near/toolbox.ts +498 -0
  75. package/src/near/types/contract.ts +48 -0
  76. package/src/near/types/nep141.ts +66 -0
  77. package/src/near/types.ts +57 -0
  78. package/src/radix/index.ts +8 -2
  79. package/src/ripple/index.ts +15 -26
  80. package/src/solana/toolbox.ts +73 -2
  81. package/src/substrate/balance.ts +92 -0
  82. package/src/substrate/substrate.ts +7 -5
  83. package/src/tron/__tests__/toolbox.test.ts +147 -0
  84. package/src/tron/helpers/trc20.abi.ts +40 -0
  85. package/src/tron/index.ts +16 -0
  86. package/src/tron/toolbox.ts +336 -0
  87. package/src/tron/types.ts +31 -0
  88. package/src/utxo/__tests__/zcash-integration.test.ts +114 -0
  89. package/src/utxo/helpers/api.ts +66 -16
  90. package/src/utxo/helpers/bchaddrjs.ts +8 -8
  91. package/src/utxo/helpers/coinselect.ts +4 -2
  92. package/src/utxo/helpers/txSize.ts +4 -3
  93. package/src/utxo/index.ts +1 -0
  94. package/src/utxo/toolbox/bitcoinCash.ts +22 -14
  95. package/src/utxo/toolbox/index.ts +16 -4
  96. package/src/utxo/toolbox/utxo.ts +42 -27
  97. package/src/utxo/toolbox/zcash.ts +208 -0
  98. package/src/utxo/types.ts +2 -0
  99. package/dist/chunk-0h4xdrwz.js +0 -4
  100. package/dist/cosmos/index.cjs +0 -3
  101. package/dist/cosmos/index.cjs.map +0 -16
  102. package/dist/cosmos/index.js +0 -3
  103. package/dist/cosmos/index.js.map +0 -16
  104. package/dist/evm/index.cjs +0 -3
  105. package/dist/evm/index.cjs.map +0 -18
  106. package/dist/evm/index.js +0 -3
  107. package/dist/evm/index.js.map +0 -18
  108. package/dist/index.cjs +0 -3
  109. package/dist/index.cjs.map +0 -10
  110. package/dist/index.js +0 -3
  111. package/dist/index.js.map +0 -10
  112. package/dist/radix/index.cjs.map +0 -10
  113. package/dist/radix/index.js +0 -3
  114. package/dist/radix/index.js.map +0 -10
  115. package/dist/ripple/index.cjs +0 -3
  116. package/dist/ripple/index.cjs.map +0 -10
  117. package/dist/ripple/index.js +0 -3
  118. package/dist/ripple/index.js.map +0 -10
  119. package/dist/solana/index.cjs +0 -3
  120. package/dist/solana/index.cjs.map +0 -10
  121. package/dist/solana/index.js +0 -3
  122. package/dist/solana/index.js.map +0 -10
  123. package/dist/substrate/index.cjs +0 -3
  124. package/dist/substrate/index.cjs.map +0 -11
  125. package/dist/substrate/index.js +0 -3
  126. package/dist/substrate/index.js.map +0 -11
  127. package/dist/utxo/index.cjs +0 -3
  128. package/dist/utxo/index.cjs.map +0 -16
  129. package/dist/utxo/index.js +0 -3
  130. package/dist/utxo/index.js.map +0 -16
  131. /package/dist/{chunk-0f0249b1.js.map → chunk-9bqegm61.js.map} +0 -0
package/package.json CHANGED
@@ -11,16 +11,19 @@
11
11
  "@cosmjs/proto-signing": "0.33.1",
12
12
  "@cosmjs/stargate": "0.33.1",
13
13
  "@polkadot/api": "15.9.2",
14
- "@polkadot/keyring": "13.4.4",
15
- "@polkadot/util": "13.4.4",
16
- "@polkadot/util-crypto": "13.4.4",
14
+ "@polkadot/keyring": "13.5.1",
15
+ "@polkadot/util": "13.5.1",
16
+ "@polkadot/util-crypto": "13.5.1",
17
17
  "@psf/bitcoincashjs-lib": "4.0.3",
18
18
  "@radixdlt/babylon-gateway-api-sdk": "1.10.1",
19
19
  "@radixdlt/radix-dapp-toolkit": "2.2.1",
20
- "@scure/base": "1.2.4",
21
- "@scure/bip32": "1.6.2",
22
- "@scure/bip39": "1.5.4",
23
- "@swapkit/helpers": "3.0.0-beta.3",
20
+ "@scure/base": "1.2.6",
21
+ "@scure/bip32": "1.7.0",
22
+ "@scure/bip39": "1.6.0",
23
+ "@solana/spl-memo": "0.2.5",
24
+ "@solana/spl-token": "0.4.13",
25
+ "@solana/web3.js": "1.98.2",
26
+ "@swapkit/helpers": "3.0.0-beta.21",
24
27
  "base64-js": "1.5.1",
25
28
  "bitcoinjs-lib": "6.1.7",
26
29
  "bs58check": "4.0.0",
@@ -28,65 +31,74 @@
28
31
  "coininfo": "5.2.1",
29
32
  "cosmjs-types": "0.9.0",
30
33
  "ecpair": "2.1.0",
31
- "ethers": "6.13.5",
32
- "micro-key-producer": "0.7.5",
33
- "protobufjs": "7.4.0",
34
- "ts-pattern": "5.7.0",
35
- "xrpl": "4.2.0"
36
- },
37
- "peerDependencies": {
38
- "@solana/spl-memo": "0.2.5",
39
- "@solana/spl-token": "0.4.13",
40
- "@solana/web3.js": "1.98.0"
34
+ "ethers": "6.14.3",
35
+ "micro-key-producer": "0.7.6",
36
+ "near-api-js": "^6.1.0",
37
+ "near-sdk-js": "^2.0.0",
38
+ "near-seed-phrase": "^0.2.0",
39
+ "protobufjs": "7.5.3",
40
+ "tronweb": "6.0.3",
41
+ "ts-pattern": "5.7.1",
42
+ "xrpl": "4.3.0"
41
43
  },
42
44
  "devDependencies": {
43
- "@nomicfoundation/hardhat-ethers": "3.0.8",
45
+ "@nomicfoundation/hardhat-ethers": "3.0.9",
44
46
  "@nomicfoundation/hardhat-toolbox": "5.0.0",
45
47
  "@polkadot/types": "15.9.2",
46
- "@types/bn.js": "5.1.6",
48
+ "@types/bn.js": "5.2.0",
47
49
  "@types/crypto-js": "4.2.2",
48
50
  "@types/elliptic": "6.4.18",
49
- "hardhat": "2.23.0"
51
+ "hardhat": "2.24.2"
50
52
  },
51
53
  "exports": {
52
54
  ".": {
53
- "default": "./dist/index.js",
54
- "require": "./dist/index.cjs",
55
+ "default": "./dist/src/index.js",
56
+ "require": "./dist/src/index.cjs",
55
57
  "types": "./src/index.ts"
56
58
  },
57
59
  "./cosmos": {
58
- "default": "./dist/cosmos/index.js",
59
- "require": "./dist/cosmos/index.cjs",
60
+ "default": "./dist/src/cosmos/index.js",
61
+ "require": "./dist/src/cosmos/index.cjs",
60
62
  "types": "./src/cosmos/index.ts"
61
63
  },
62
64
  "./evm": {
63
- "default": "./dist/evm/index.js",
64
- "require": "./dist/evm/index.cjs",
65
+ "default": "./dist/src/evm/index.js",
66
+ "require": "./dist/src/evm/index.cjs",
65
67
  "types": "./src/evm/index.ts"
66
68
  },
69
+ "./near": {
70
+ "default": "./dist/src/near/index.js",
71
+ "require": "./dist/src/near/index.cjs",
72
+ "types": "./src/near/index.ts"
73
+ },
67
74
  "./radix": {
68
- "default": "./dist/radix/index.js",
69
- "require": "./dist/radix/index.cjs",
75
+ "default": "./dist/src/radix/index.js",
76
+ "require": "./dist/src/radix/index.cjs",
70
77
  "types": "./src/radix/index.ts"
71
78
  },
72
79
  "./ripple": {
73
- "default": "./dist/ripple/index.js",
74
- "require": "./dist/ripple/index.cjs",
80
+ "default": "./dist/src/ripple/index.js",
81
+ "require": "./dist/src/ripple/index.cjs",
75
82
  "types": "./src/ripple/index.ts"
76
83
  },
77
84
  "./solana": {
78
- "default": "./dist/solana/index.js",
79
- "require": "./dist/solana/index.cjs",
85
+ "default": "./dist/src/solana/index.js",
86
+ "require": "./dist/src/solana/index.cjs",
80
87
  "types": "./src/solana/index.ts"
81
88
  },
82
89
  "./substrate": {
83
- "default": "./dist/substrate/index.js",
84
- "require": "./dist/substrate/index.cjs",
90
+ "default": "./dist/src/substrate/index.js",
91
+ "require": "./dist/src/substrate/index.cjs",
85
92
  "types": "./src/substrate/index.ts"
86
93
  },
94
+ "./tron": {
95
+ "default": "./dist/src/tron/index.js",
96
+ "require": "./dist/src/tron/index.cjs",
97
+ "types": "./src/tron/index.ts"
98
+ },
87
99
  "./utxo": {
88
- "default": "./dist/utxo/index.js",
89
- "require": "./dist/utxo/index.cjs",
100
+ "default": "./dist/src/utxo/index.js",
101
+ "require": "./dist/src/utxo/index.cjs",
90
102
  "types": "./src/utxo/index.ts"
91
103
  }
92
104
  },
@@ -107,5 +119,5 @@
107
119
  "type-check:go": "tsgo"
108
120
  },
109
121
  "type": "module",
110
- "version": "1.0.0-beta.3"
122
+ "version": "1.0.0-beta.31"
111
123
  }
@@ -1,4 +1,5 @@
1
1
  import { base64, bech32 } from "@scure/base";
2
+ import { SwapKitError } from "@swapkit/helpers";
2
3
  import { fromByteArray, toByteArray } from "base64-js";
3
4
 
4
5
  export function bech32ToBase64(address: string) {
@@ -17,7 +18,9 @@ export function toBase64(data: Uint8Array) {
17
18
 
18
19
  export function fromBase64(base64String: string) {
19
20
  if (!base64String.match(/^[a-zA-Z0-9+/]*={0,2}$/)) {
20
- throw new Error("Invalid base64 string format");
21
+ throw new SwapKitError("toolbox_cosmos_invalid_params", {
22
+ error: "Invalid base64 string format",
23
+ });
21
24
  }
22
25
  return toByteArray(base64String);
23
26
  }
@@ -1,5 +1,5 @@
1
1
  import type { TxBodyEncodeObject } from "@cosmjs/proto-signing";
2
- import { AssetValue, Chain, ChainToChainId } from "@swapkit/helpers";
2
+ import { AssetValue, Chain, ChainToChainId, SwapKitError } from "@swapkit/helpers";
3
3
 
4
4
  import {
5
5
  createStargateClient,
@@ -104,7 +104,7 @@ const getAccount = async ({ rpcUrl, sender }: { sender: string; rpcUrl: string }
104
104
  const account = await client.getAccount(sender);
105
105
 
106
106
  if (!account) {
107
- throw new Error("Account does not exist");
107
+ throw new SwapKitError("toolbox_cosmos_account_not_found", { sender });
108
108
  }
109
109
 
110
110
  return account;
@@ -3,8 +3,8 @@ import { base64ToBech32, bech32ToBase64 } from "./addressFormat";
3
3
 
4
4
  export async function createDefaultRegistry() {
5
5
  const { $root } = await import("./types/MsgCompiled");
6
- const { Registry } = await import("@cosmjs/proto-signing");
7
- const { defaultRegistryTypes } = await import("@cosmjs/stargate");
6
+ const { Registry } = (await import("@cosmjs/proto-signing")).default;
7
+ const { defaultRegistryTypes } = (await import("@cosmjs/stargate")).default;
8
8
 
9
9
  return new Registry([
10
10
  ...defaultRegistryTypes,
@@ -14,7 +14,7 @@ export async function createDefaultRegistry() {
14
14
  }
15
15
 
16
16
  export async function createDefaultAminoTypes(chain: Chain.THORChain | Chain.Maya) {
17
- const { AminoTypes } = await import("@cosmjs/stargate");
17
+ const { AminoTypes } = (await import("@cosmjs/stargate")).default;
18
18
  const aminoTypePrefix = chain === Chain.THORChain ? "thorchain" : "mayachain";
19
19
 
20
20
  return new AminoTypes({
@@ -17,17 +17,18 @@ import {
17
17
  SKConfig,
18
18
  SwapKitError,
19
19
  SwapKitNumber,
20
+ applyFeeMultiplier,
20
21
  derivationPathToString,
21
22
  updateDerivationPath,
22
23
  } from "@swapkit/helpers";
23
24
  import { SwapKitApi } from "@swapkit/helpers/api";
24
25
  import { P, match } from "ts-pattern";
25
- import { getBalance } from "../../utils";
26
26
  import type { CosmosToolboxParams } from "../types";
27
27
  import {
28
28
  cosmosCreateTransaction,
29
29
  createSigningStargateClient,
30
30
  createStargateClient,
31
+ getAssetFromDenom,
31
32
  getDenomWithChain,
32
33
  getMsgSendDenom,
33
34
  } from "../util";
@@ -38,8 +39,7 @@ export async function fetchFeeRateFromSwapKit(chainId: ChainId, safeDefault: num
38
39
  const responseGasRate = response.find((gas) => gas.chainId === chainId)?.value;
39
40
 
40
41
  return responseGasRate ? Number.parseFloat(responseGasRate) : safeDefault;
41
- } catch (e) {
42
- console.error(e);
42
+ } catch (_e) {
43
43
  return safeDefault;
44
44
  }
45
45
  }
@@ -52,8 +52,8 @@ export async function getSignerFromPhrase({
52
52
  | { chain: Chain; index?: number }
53
53
  | { derivationPath: string }
54
54
  )) {
55
- const { DirectSecp256k1HdWallet } = await import("@cosmjs/proto-signing");
56
- const { stringToPath } = await import("@cosmjs/crypto");
55
+ const { DirectSecp256k1HdWallet } = (await import("@cosmjs/proto-signing")).default;
56
+ const { stringToPath } = (await import("@cosmjs/crypto")).default;
57
57
 
58
58
  const derivationPath =
59
59
  "derivationPath" in derivationParams
@@ -73,7 +73,7 @@ export async function getSignerFromPrivateKey({
73
73
  privateKey: Uint8Array;
74
74
  prefix: string;
75
75
  }) {
76
- const { DirectSecp256k1Wallet } = await import("@cosmjs/proto-signing");
76
+ const { DirectSecp256k1Wallet } = (await import("@cosmjs/proto-signing")).default;
77
77
 
78
78
  return DirectSecp256k1Wallet.fromKey(privateKey, prefix);
79
79
  }
@@ -97,7 +97,7 @@ export function verifySignature(getAccount: (address: string) => Promise<Account
97
97
  }) {
98
98
  const account = await getAccount(address);
99
99
  if (!account?.pubkey) throw new SwapKitError("toolbox_cosmos_verify_signature_no_pubkey");
100
- const { Secp256k1Signature, Secp256k1 } = await import("@cosmjs/crypto");
100
+ const { Secp256k1Signature, Secp256k1 } = (await import("@cosmjs/crypto")).default;
101
101
 
102
102
  const secpSignature = Secp256k1Signature.fromFixedLength(base64.decode(signature));
103
103
  return Secp256k1.verifySignature(secpSignature, base64.decode(message), account.pubkey.value);
@@ -185,7 +185,21 @@ export async function createCosmosToolbox({ chain, ...toolboxParams }: CosmosToo
185
185
  transfer,
186
186
  getAddress,
187
187
  getAccount,
188
- getBalance: getBalance(chain),
188
+ getBalance: async (address: string, _potentialScamFilter?: boolean) => {
189
+ const denomBalances = await cosmosBalanceDenomsGetter(rpcUrl)(address);
190
+ return await Promise.all(
191
+ denomBalances
192
+ .filter(({ denom }) => denom && !denom.includes("IBC/"))
193
+ .map(({ denom, amount }) => {
194
+ const fullDenom =
195
+ [Chain.THORChain, Chain.Maya].includes(chain) &&
196
+ (denom.includes("/") || denom.includes("˜"))
197
+ ? `${chain}.${denom}`
198
+ : denom;
199
+ return getAssetFromDenom(fullDenom, amount);
200
+ }),
201
+ );
202
+ },
189
203
  getSignerFromPhrase: async ({
190
204
  phrase,
191
205
  derivationPath,
@@ -197,7 +211,7 @@ export async function createCosmosToolbox({ chain, ...toolboxParams }: CosmosToo
197
211
  index,
198
212
  }),
199
213
  getSignerFromPrivateKey: async (privateKey: Uint8Array) => {
200
- const { DirectSecp256k1Wallet } = await import("@cosmjs/proto-signing");
214
+ const { DirectSecp256k1Wallet } = (await import("@cosmjs/proto-signing")).default;
201
215
  return DirectSecp256k1Wallet.fromKey(privateKey, chainPrefix);
202
216
  },
203
217
  createPrivateKeyFromPhrase: createPrivateKeyFromPhrase(derivationPath),
@@ -217,8 +231,7 @@ export async function getFeeRateFromThorswap(chainId: ChainId, safeDefault: numb
217
231
  const responseGasRate = response.find((gas) => gas.chainId === chainId)?.value;
218
232
 
219
233
  return responseGasRate ? Number.parseFloat(responseGasRate) : safeDefault;
220
- } catch (e) {
221
- console.error(e);
234
+ } catch (_e) {
222
235
  return safeDefault;
223
236
  }
224
237
  }
@@ -262,8 +275,14 @@ async function getFees(chain: Chain, safeDefault: number) {
262
275
  const baseFee = await fetchFeeRateFromSwapKit(ChainToChainId[chain], safeDefault);
263
276
  return {
264
277
  average: SwapKitNumber.fromBigInt(BigInt(baseFee), BaseDecimal[chain]),
265
- fast: SwapKitNumber.fromBigInt(BigInt(Math.floor(baseFee * 1.5)), BaseDecimal[chain]),
266
- fastest: SwapKitNumber.fromBigInt(BigInt(Math.floor(baseFee * 2)), BaseDecimal[chain]),
278
+ fast: SwapKitNumber.fromBigInt(
279
+ BigInt(applyFeeMultiplier(baseFee, FeeOption.Fast, true)),
280
+ BaseDecimal[chain],
281
+ ),
282
+ fastest: SwapKitNumber.fromBigInt(
283
+ BigInt(applyFeeMultiplier(baseFee, FeeOption.Fastest, true)),
284
+ BaseDecimal[chain],
285
+ ),
267
286
  } as { [key in FeeOption]: SwapKitNumber };
268
287
  }
269
288
 
@@ -316,9 +335,9 @@ function cosmosBalanceDenomsGetter(rpcUrl: string) {
316
335
 
317
336
  function createPrivateKeyFromPhrase(derivationPath: string) {
318
337
  return async function createPrivateKeyFromPhrase(phrase: string) {
319
- const { Bip39, EnglishMnemonic, Slip10, Slip10Curve, stringToPath } = await import(
320
- "@cosmjs/crypto"
321
- );
338
+ const { Bip39, EnglishMnemonic, Slip10, Slip10Curve, stringToPath } = (
339
+ await import("@cosmjs/crypto")
340
+ ).default;
322
341
 
323
342
  const mnemonicChecked = new EnglishMnemonic(phrase);
324
343
  const seed = await Bip39.mnemonicToSeed(mnemonicChecked);
@@ -1,4 +1,4 @@
1
- import { Chain, type CosmosChain } from "@swapkit/helpers";
1
+ import { Chain, type CosmosChain, SwapKitError } from "@swapkit/helpers";
2
2
 
3
3
  import type { CosmosToolboxParams } from "../types";
4
4
  import { createCosmosToolbox } from "./cosmos";
@@ -25,7 +25,7 @@ export const getCosmosToolbox = <T extends CosmosChain>(
25
25
  return createThorchainToolbox({ chain, ...params }) as CosmosToolboxes[T];
26
26
 
27
27
  default:
28
- throw new Error(`Chain ${chain} is not supported`);
28
+ throw new SwapKitError("toolbox_cosmos_not_supported", { chain });
29
29
  }
30
30
  };
31
31
 
@@ -9,6 +9,7 @@ import {
9
9
  NetworkDerivationPath,
10
10
  RequestClient,
11
11
  SKConfig,
12
+ SwapKitError,
12
13
  SwapKitNumber,
13
14
  derivationPathToString,
14
15
  updateDerivationPath,
@@ -43,8 +44,8 @@ function secp256k1HdWalletFromMnemonic({
43
44
  derivationPath?: string;
44
45
  }) {
45
46
  return async function secp256k1HdWalletFromMnemonic(mnemonic: string, index = 0) {
46
- const { Secp256k1HdWallet } = await import("@cosmjs/amino");
47
- const { stringToPath } = await import("@cosmjs/crypto");
47
+ const { Secp256k1HdWallet } = (await import("@cosmjs/amino")).default;
48
+ const { stringToPath } = (await import("@cosmjs/crypto")).default;
48
49
 
49
50
  return Secp256k1HdWallet.fromMnemonic(mnemonic, {
50
51
  hdPaths: [stringToPath(`${derivationPath}/${index}`)],
@@ -114,8 +115,8 @@ function broadcastMultisigTx({
114
115
  threshold: number,
115
116
  bodyBytes: Uint8Array,
116
117
  ) {
117
- const { encodeSecp256k1Pubkey, pubkeyToAddress } = await import("@cosmjs/amino");
118
- const { makeMultisignedTxBytes } = await import("@cosmjs/stargate");
118
+ const { encodeSecp256k1Pubkey, pubkeyToAddress } = (await import("@cosmjs/amino")).default;
119
+ const { makeMultisignedTxBytes } = (await import("@cosmjs/stargate")).default;
119
120
 
120
121
  const { sequence, fee } = JSON.parse(tx);
121
122
  const multisigPubkey = await createMultisig(membersPubKeys, threshold);
@@ -142,7 +143,8 @@ function broadcastMultisigTx({
142
143
  }
143
144
 
144
145
  async function createMultisig(pubKeys: string[], threshold: number, noSortPubKeys = true) {
145
- const { createMultisigThresholdPubkey, encodeSecp256k1Pubkey } = await import("@cosmjs/amino");
146
+ const { createMultisigThresholdPubkey, encodeSecp256k1Pubkey } = (await import("@cosmjs/amino"))
147
+ .default;
146
148
  return createMultisigThresholdPubkey(
147
149
  pubKeys.map((pubKey) => encodeSecp256k1Pubkey(base64.decode(pubKey))),
148
150
  threshold,
@@ -161,7 +163,7 @@ async function signWithPrivateKey({
161
163
  privateKey: Uint8Array;
162
164
  message: string;
163
165
  }) {
164
- const { Secp256k1 } = await import("@cosmjs/crypto");
166
+ const { Secp256k1 } = (await import("@cosmjs/crypto")).default;
165
167
 
166
168
  const signature = await Secp256k1.createSignature(base64.decode(message), privateKey);
167
169
  return base64.encode(Buffer.concat([signature.r(32), signature.s(32)]));
@@ -209,7 +211,7 @@ export async function createThorchainToolbox({
209
211
  } = await RequestClient.get<ThorchainConstantsResponse>(constantsUrl);
210
212
 
211
213
  if (!nativeFee || Number.isNaN(nativeFee) || nativeFee < 0) {
212
- throw new Error(`Invalid nativeFee: ${nativeFee.toString()}`);
214
+ throw new SwapKitError("toolbox_cosmos_invalid_fee", { nativeFee: nativeFee.toString() });
213
215
  }
214
216
 
215
217
  fee = new SwapKitNumber(nativeFee);
@@ -230,7 +232,7 @@ export async function createThorchainToolbox({
230
232
  }: Omit<GenericTransferParams, "recipient"> & { recipient?: string }) {
231
233
  const { TxRaw } = await import("cosmjs-types/cosmos/tx/v1beta1/tx");
232
234
  const sender = (await signer?.getAccounts())?.[0]?.address;
233
- if (!(sender && signer)) throw new Error("Signer not defined");
235
+ if (!(sender && signer)) throw new SwapKitError("toolbox_cosmos_no_signer");
234
236
 
235
237
  const isAminoSigner = "signAmino" in signer;
236
238
  const registry = await createDefaultRegistry();
@@ -301,7 +303,7 @@ export async function createThorchainToolbox({
301
303
  signWithPrivateKey,
302
304
  transfer,
303
305
  pubkeyToAddress: async (pubkey: Pubkey) => {
304
- const { pubkeyToAddress } = await import("@cosmjs/amino");
306
+ const { pubkeyToAddress } = (await import("@cosmjs/amino")).default;
305
307
  return pubkeyToAddress(pubkey, chainPrefix);
306
308
  },
307
309
  };
@@ -1,6 +1,14 @@
1
1
  import type { OfflineSigner } from "@cosmjs/proto-signing";
2
2
  import type { SigningStargateClientOptions } from "@cosmjs/stargate";
3
- import { AssetValue, Chain, ChainId, type CosmosChain, SKConfig } from "@swapkit/helpers";
3
+ import {
4
+ AssetValue,
5
+ BaseDecimal,
6
+ Chain,
7
+ ChainId,
8
+ type CosmosChain,
9
+ SKConfig,
10
+ SwapKitError,
11
+ } from "@swapkit/helpers";
4
12
 
5
13
  import type { CosmosCreateTransactionParams } from "./thorchainUtils";
6
14
 
@@ -69,7 +77,7 @@ export const getDenomWithChain = ({ symbol, chain }: AssetValue) => {
69
77
  };
70
78
 
71
79
  export async function createStargateClient(url: string) {
72
- const { StargateClient } = await import("@cosmjs/stargate");
80
+ const { StargateClient } = (await import("@cosmjs/stargate")).default;
73
81
 
74
82
  return StargateClient.connect(url);
75
83
  }
@@ -79,7 +87,7 @@ export async function createSigningStargateClient(
79
87
  signer: any,
80
88
  optionsOrBaseGas: string | SigningStargateClientOptions = {},
81
89
  ) {
82
- const { SigningStargateClient, GasPrice } = await import("@cosmjs/stargate");
90
+ const { SigningStargateClient, GasPrice } = (await import("@cosmjs/stargate")).default;
83
91
  const gasPrice = typeof optionsOrBaseGas === "string" ? optionsOrBaseGas : "0.0003uatom";
84
92
  const options = typeof optionsOrBaseGas === "string" ? {} : optionsOrBaseGas;
85
93
 
@@ -93,7 +101,7 @@ export async function createOfflineStargateClient(
93
101
  wallet: OfflineSigner,
94
102
  registry?: SigningStargateClientOptions,
95
103
  ) {
96
- const { SigningStargateClient } = await import("@cosmjs/stargate");
104
+ const { SigningStargateClient } = (await import("@cosmjs/stargate")).default;
97
105
 
98
106
  return SigningStargateClient.offline(wallet, registry);
99
107
  }
@@ -126,7 +134,7 @@ const getTransferMsgTypeByChain = (chain: CosmosChain) => {
126
134
  case Chain.Kujira:
127
135
  return "/cosmos.bank.v1beta1.MsgSend";
128
136
  default:
129
- throw new Error("Unsupported chain");
137
+ throw new SwapKitError("toolbox_cosmos_not_supported", { chain });
130
138
  }
131
139
  };
132
140
 
@@ -149,7 +157,7 @@ export const cosmosCreateTransaction = async ({
149
157
  const accountOnChain = await client.getAccount(sender);
150
158
 
151
159
  if (!accountOnChain) {
152
- throw new Error("Account does not exist");
160
+ throw new SwapKitError("toolbox_cosmos_account_not_found", { sender });
153
161
  }
154
162
 
155
163
  const gasAsset = AssetValue.from({ chain });
@@ -178,3 +186,65 @@ export const cosmosCreateTransaction = async ({
178
186
  msgs: [{ typeUrl: getTransferMsgTypeByChain(chain as CosmosChain), value: msgSend }],
179
187
  };
180
188
  };
189
+
190
+ // Map of known denoms to their asset configurations
191
+ const DENOM_MAP = {
192
+ // THORChain denoms
193
+ rune: { chain: Chain.THORChain, decimals: BaseDecimal[Chain.THORChain] },
194
+ tcy: { asset: "THOR.TCY", decimals: BaseDecimal[Chain.THORChain] },
195
+ "x/kuji": { asset: "THOR.KUJI", decimals: BaseDecimal[Chain.THORChain] },
196
+
197
+ // Cosmos denoms
198
+ uatom: { chain: Chain.Cosmos, decimals: BaseDecimal[Chain.Cosmos] },
199
+ atom: { chain: Chain.Cosmos, decimals: BaseDecimal[Chain.Cosmos] },
200
+
201
+ // Maya denoms
202
+ cacao: { chain: Chain.Maya, decimals: 10 }, // Maya uses 10 decimals for CACAO
203
+ maya: { asset: `${Chain.Maya}.${Chain.Maya}`, decimals: 4 }, // MAYA token uses 4 decimals
204
+
205
+ // Kujira denoms
206
+ ukuji: { chain: Chain.Kujira, decimals: BaseDecimal[Chain.Kujira] },
207
+ kuji: { chain: Chain.Kujira, decimals: BaseDecimal[Chain.Kujira] },
208
+
209
+ // USK on Kujira (lowercase version of the factory denom)
210
+ [USK_KUJIRA_FACTORY_DENOM.toLowerCase()]: {
211
+ asset: `${Chain.Kujira}.USK`,
212
+ decimals: BaseDecimal[Chain.Kujira],
213
+ },
214
+ };
215
+
216
+ /**
217
+ * Converts a Cosmos denom and amount to an AssetValue with proper decimal handling
218
+ * @param denom - The denomination string
219
+ * @param amount - The amount in base units as a string
220
+ * @returns AssetValue with the correct decimal conversion
221
+ */
222
+ export const getAssetFromDenom = (denom: string, amount: string) => {
223
+ const config = DENOM_MAP[denom.toLowerCase()];
224
+
225
+ if (!config) {
226
+ // For unknown denoms, default to 8 decimals (common for many Cosmos chains)
227
+ // This preserves the original behavior while using fromBaseDecimal
228
+ return AssetValue.from({
229
+ asset: denom,
230
+ value: amount,
231
+ fromBaseDecimal: 8,
232
+ });
233
+ }
234
+
235
+ const { chain, asset, decimals } = config;
236
+
237
+ const assetOrChain = (
238
+ chain
239
+ ? {
240
+ chain,
241
+ }
242
+ : { asset }
243
+ ) as { asset: string } | { chain: CosmosChain };
244
+
245
+ return AssetValue.from({
246
+ ...assetOrChain,
247
+ value: amount,
248
+ fromBaseDecimal: decimals,
249
+ });
250
+ };
@@ -0,0 +1,86 @@
1
+ import { beforeAll, describe, expect, test } from "bun:test";
2
+ import { Chain } from "@swapkit/helpers";
3
+ import { getEvmToolbox } from "../toolbox";
4
+
5
+ const context: {
6
+ validateAddress: (address: string) => boolean;
7
+ } = {} as any;
8
+
9
+ beforeAll(async () => {
10
+ // Get EVM toolbox for address validation
11
+ const toolbox = await getEvmToolbox(Chain.Ethereum);
12
+ context.validateAddress = toolbox.validateAddress;
13
+ });
14
+
15
+ describe("EVM Address Validation", () => {
16
+ test("should validate valid EVM addresses", () => {
17
+ const validAddresses = [
18
+ "0xa052Ddf1c1739419B90FB7bf722843AD3e63114B", // User provided address
19
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC contract
20
+ "0x6d6e022eE439C8aB8B7a7dBb0576f8090319CDc6", // Test address
21
+ "0xE29E61479420Dd1029A9946710Ac31A0d140e77F", // Another valid address
22
+ "0x0000000000000000000000000000000000000000", // Zero address
23
+ "0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF", // Max address
24
+ "0x1234567890123456789012345678901234567890", // Mixed case
25
+ ];
26
+
27
+ for (const address of validAddresses) {
28
+ expect(context.validateAddress(address)).toBe(true);
29
+ }
30
+ });
31
+
32
+ test("should reject invalid EVM addresses", () => {
33
+ const invalidAddresses = [
34
+ "", // Empty string
35
+ "invalid", // Random string
36
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", // TRON address
37
+ "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", // Bitcoin address
38
+ "cosmos1abc123", // Cosmos address
39
+ "0xa052Ddf1c1739419B90FB7bf722843AD3e63114", // Too short (missing 1 char)
40
+ "0xa052Ddf1c1739419B90FB7bf722843AD3e63114BB", // Too long (extra char)
41
+ "0XA052DDF1C1739419B90FB7BF722843AD3E63114B", // Uppercase 0X prefix
42
+ "0xG052Ddf1c1739419B90FB7bf722843AD3e63114B", // Invalid hex character
43
+ "0x", // Only prefix
44
+ ];
45
+
46
+ for (const address of invalidAddresses) {
47
+ expect(context.validateAddress(address)).toBe(false);
48
+ }
49
+ });
50
+
51
+ test("should handle case normalization properly", () => {
52
+ const address = "0xa052Ddf1c1739419B90FB7bf722843AD3e63114B"; // Proper checksum
53
+ const lowerCase = address.toLowerCase();
54
+
55
+ // Valid case variations should be accepted
56
+ expect(context.validateAddress(address)).toBe(true);
57
+ expect(context.validateAddress(lowerCase)).toBe(true);
58
+ });
59
+
60
+ test("should reject invalid checksum addresses", () => {
61
+ const invalidChecksumAddress = "0xA052dDF1C1739419b90fb7BF722843ad3E63114b"; // Invalid checksum
62
+
63
+ // Should reject mixed case with invalid checksum
64
+ expect(context.validateAddress(invalidChecksumAddress)).toBe(false);
65
+ });
66
+
67
+ test("should handle edge cases", () => {
68
+ const edgeCases = [null, undefined, 123, {}, [], true, false];
69
+
70
+ for (const testCase of edgeCases) {
71
+ // Should not throw but return false for invalid inputs
72
+ expect(context.validateAddress(testCase as any)).toBe(false);
73
+ }
74
+ });
75
+
76
+ test("should validate checksummed addresses", () => {
77
+ const checksummedAddresses = [
78
+ "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC with proper checksum
79
+ "0x6d6e022eE439C8aB8B7a7dBb0576f8090319CDc6", // Another checksummed address
80
+ ];
81
+
82
+ for (const address of checksummedAddresses) {
83
+ expect(context.validateAddress(address)).toBe(true);
84
+ }
85
+ });
86
+ });
@@ -35,7 +35,7 @@ beforeEach(async () => {
35
35
  },
36
36
  });
37
37
  context.provider = provider;
38
- context.toolbox = await getEvmToolbox(Chain.Ethereum, { provider, signer });
38
+ context.toolbox = await getEvmToolbox(Chain.Ethereum, { provider, signer: signer as any });
39
39
  });
40
40
 
41
41
  afterEach(async () => {
@@ -8,6 +8,7 @@ import {
8
8
  FeeOption,
9
9
  type NetworkParams,
10
10
  SKConfig,
11
+ SwapKitError,
11
12
  SwapKitNumber,
12
13
  } from "@swapkit/helpers";
13
14
  import type { BrowserProvider, Provider } from "ethers";
@@ -71,7 +72,7 @@ export const estimateMaxSendableAmount = async ({
71
72
  const isFeeEVMLegacyCompatible = "gasPrice" in gasRate && gasRate.gasPrice !== undefined;
72
73
 
73
74
  if (!(gasRate && (isFeeEVMLegacyCompatible || isFeeEIP1559Compatible))) {
74
- throw new Error("Could not fetch fee data");
75
+ throw new SwapKitError("toolbox_evm_no_fee_data");
75
76
  }
76
77
 
77
78
  const gasPrice = isFeeEIP1559Compatible
@@ -116,7 +117,7 @@ export function getEstimateTransactionFee({
116
117
  return assetValue.set(SwapKitNumber.fromBigInt(fee, assetValue.decimal));
117
118
  }
118
119
 
119
- throw new Error("No gas price found");
120
+ throw new SwapKitError("toolbox_evm_no_gas_price");
120
121
  };
121
122
  }
122
123
 
@@ -168,6 +169,6 @@ function getNetworkInfo<C extends EVMChain>({ chain }: { chain: C }) {
168
169
  nativeCurrency: { name: "Polygon", symbol: Chain.Polygon, decimals },
169
170
  };
170
171
  default:
171
- throw new Error(`Chain ${chain} is not supported`);
172
+ throw new SwapKitError("toolbox_evm_not_supported", { chain });
172
173
  }
173
174
  }