@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
@@ -3,7 +3,6 @@ import {
3
3
  BaseDecimal,
4
4
  Chain,
5
5
  type ChainSigner,
6
- type GenericCreateTransactionParams,
7
6
  type GenericTransferParams,
8
7
  SKConfig,
9
8
  SwapKitError,
@@ -14,6 +13,12 @@ import { Client, type Payment, Wallet, isValidAddress, xrpToDrops } from "xrpl";
14
13
 
15
14
  export type RippleWallet = Awaited<ReturnType<typeof getRippleToolbox>>;
16
15
 
16
+ export { hashes, type Transaction } from "xrpl";
17
+
18
+ const RIPPLE_ERROR_CODES = {
19
+ ACCOUNT_NOT_FOUND: 19,
20
+ } as const;
21
+
17
22
  // Note: Ripple seeds generate a single address, no derivation path/index support.
18
23
  function createSigner(phrase: string): ChainSigner<Transaction, { tx_blob: string; hash: string }> {
19
24
  const wallet = Wallet.fromMnemonic(phrase);
@@ -65,11 +70,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
65
70
  const addr = address || (await getAddress());
66
71
 
67
72
  try {
68
- await client.connect();
69
- const accountInfo = await client.request({
70
- command: "account_info",
71
- account: addr,
72
- });
73
+ const accountInfo = await client.request({ command: "account_info", account: addr });
73
74
 
74
75
  const balance = accountInfo.result.account_data.Balance;
75
76
 
@@ -82,7 +83,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
82
83
  ];
83
84
  } catch (error) {
84
85
  // empty account
85
- if ((error as any).data.error_code === 19) {
86
+ if ((error as any).data.error_code === RIPPLE_ERROR_CODES.ACCOUNT_NOT_FOUND) {
86
87
  return [
87
88
  AssetValue.from({
88
89
  chain: Chain.Ripple,
@@ -111,10 +112,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
111
112
  recipient,
112
113
  memo,
113
114
  sender,
114
- }: Omit<GenericCreateTransactionParams, "feeRate">) => {
115
- if (!signer) {
116
- throw new SwapKitError({ errorKey: "toolbox_ripple_signer_not_found" });
117
- }
115
+ }: { assetValue: AssetValue; recipient: string; sender?: string; memo?: string }) => {
118
116
  if (!rippleValidateAddress(recipient)) {
119
117
  throw new SwapKitError({ errorKey: "core_transaction_invalid_recipient_address" });
120
118
  }
@@ -152,22 +150,15 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
152
150
 
153
151
  const broadcastTransaction = async (signedTxHex: string) => {
154
152
  const submitResult = await client.submitAndWait(signedTxHex);
155
- // Cast result to any to bypass potential type mismatches in xrpl.js definitions
156
- const result: any = submitResult.result;
153
+ const result = submitResult.result;
157
154
 
158
- // Check engine_result directly on result
159
- if (result.engine_result === "tesSUCCESS" || result.engine_result === "terQUEUED") {
160
- // Access hash from tx_json if available, otherwise fallback to result.hash
161
- return result.tx_json?.hash || result.hash;
155
+ if (result.validated) {
156
+ return result.hash;
162
157
  }
163
158
 
164
- const message = result.engine_result_message || "Unknown error";
165
- const code = result.engine_result || "Unknown code";
166
-
167
159
  throw new SwapKitError({
168
160
  errorKey: "toolbox_ripple_broadcast_error",
169
- info: { chain: Chain.Ripple, message, code, result },
170
- // Remove explicit message when using object format
161
+ info: { chain: Chain.Ripple },
171
162
  });
172
163
  };
173
164
 
@@ -181,9 +172,7 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
181
172
  return broadcastTransaction(signedTx.tx_blob);
182
173
  };
183
174
 
184
- // Disconnect client on demand or handle elsewhere?
185
- // For now, let's assume connection is managed outside or persists.
186
- // const disconnect = () => client.disconnect();
175
+ const disconnect = () => client.disconnect();
187
176
 
188
177
  return {
189
178
  // Signer related
@@ -198,6 +187,6 @@ export const getRippleToolbox = async (params: RippleToolboxParams = {}) => {
198
187
  broadcastTransaction,
199
188
  transfer,
200
189
  estimateTransactionFee,
201
- // disconnect, // Optional: expose disconnect
190
+ disconnect,
202
191
  };
203
192
  };
@@ -22,10 +22,77 @@ import {
22
22
  import { P } from "ts-pattern";
23
23
  import { match } from "ts-pattern";
24
24
  import type { SolanaCreateTransactionParams, SolanaProvider, SolanaTransferParams } from ".";
25
- import { getBalance } from "../utils";
26
25
 
27
26
  type SolanaSigner = SolanaProvider | Signer;
28
27
 
28
+ type TokenMetadata = {
29
+ name: string;
30
+ symbol: string;
31
+ decimals: number;
32
+ logoURI?: string;
33
+ tags?: string[];
34
+ daily_volume?: number;
35
+ };
36
+
37
+ async function fetchTokenMetaData(mintAddress: string): Promise<TokenMetadata | null> {
38
+ try {
39
+ const response = await fetch(`https://lite-api.jup.ag/tokens/v1/token/${mintAddress}`);
40
+ if (!response.ok) return null;
41
+ return await response.json();
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ async function getSolanaBalance(address: string) {
48
+ const connection = await getConnection();
49
+ const { PublicKey } = await import("@solana/web3.js");
50
+ const { TOKEN_PROGRAM_ID } = await import("@solana/spl-token");
51
+ const publicKey = new PublicKey(address);
52
+
53
+ const balances: AssetValue[] = [];
54
+
55
+ // Get SOL balance
56
+ const solBalance = await connection.getBalance(publicKey);
57
+ if (solBalance > 0) {
58
+ balances.push(
59
+ AssetValue.from({
60
+ chain: Chain.Solana,
61
+ value: solBalance,
62
+ fromBaseDecimal: BaseDecimal[Chain.Solana],
63
+ }),
64
+ );
65
+ }
66
+
67
+ // Get token balances
68
+ const tokenAccounts = await connection.getParsedTokenAccountsByOwner(publicKey, {
69
+ programId: TOKEN_PROGRAM_ID,
70
+ });
71
+
72
+ for (const { account } of tokenAccounts.value) {
73
+ const tokenInfo = account.data.parsed.info;
74
+ const mintAddress = tokenInfo.mint;
75
+ const amount = tokenInfo.tokenAmount.amount;
76
+
77
+ if (Number(amount) === 0) continue;
78
+
79
+ // Fetch token metadata from Jupiter
80
+ const metadata = await fetchTokenMetaData(mintAddress);
81
+ const symbol = metadata?.symbol || "UNKNOWN";
82
+ const decimals = metadata?.decimals || tokenInfo.tokenAmount.decimals;
83
+
84
+ balances.push(
85
+ AssetValue.from({
86
+ asset: `${Chain.Solana}.${symbol}-${mintAddress}`,
87
+ value: amount,
88
+ fromBaseDecimal: decimals,
89
+ }),
90
+ );
91
+ }
92
+
93
+ return balances;
94
+ }
95
+
29
96
  export async function getSolanaAddressValidator() {
30
97
  const { PublicKey } = await import("@solana/web3.js");
31
98
 
@@ -68,7 +135,11 @@ export async function getSolanaToolbox(
68
135
  getPubkeyFromAddress,
69
136
  createTransaction: createTransaction(getConnection),
70
137
  createTransactionFromInstructions,
71
- getBalance: getBalance(Chain.Solana),
138
+ getBalance: (addressParam?: string) => {
139
+ const address = addressParam || getAddress();
140
+ if (!address) throw new SwapKitError("core_wallet_connection_not_found");
141
+ return getSolanaBalance(address);
142
+ },
72
143
  transfer: transfer(getConnection, signer),
73
144
  broadcastTransaction: broadcastTransaction(getConnection),
74
145
  getAddressValidator: getSolanaAddressValidator,
@@ -0,0 +1,92 @@
1
+ import type { ApiPromise } from "@polkadot/api";
2
+ import { AssetValue, Chain, SwapKitNumber } from "@swapkit/helpers";
3
+
4
+ /**
5
+ * Get balance for standard Substrate chains (Polkadot, etc.)
6
+ * Uses api.query.system.account to query free and reserved balances
7
+ */
8
+ export async function getSubstrateBalance(
9
+ api: ApiPromise,
10
+ gasAsset: AssetValue,
11
+ address: string,
12
+ ): Promise<AssetValue[]> {
13
+ try {
14
+ const account = await api.query.system?.account?.(address);
15
+
16
+ if (!account) {
17
+ return [gasAsset.set(0)];
18
+ }
19
+
20
+ const {
21
+ // @ts-expect-error
22
+ data: { free },
23
+ } = account;
24
+
25
+ // Convert the free balance to string using SwapKitNumber for proper decimal handling
26
+ const freeBalance = SwapKitNumber.fromBigInt(
27
+ BigInt(free.toString()),
28
+ gasAsset.decimal,
29
+ ).getValue("string");
30
+
31
+ return [gasAsset.set(freeBalance)];
32
+ } catch (error) {
33
+ console.error("Error fetching substrate balance:", error);
34
+ return [gasAsset.set(0)];
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Get balance for Chainflip chain
40
+ * Uses api.query.flip.account to query FLIP balances
41
+ */
42
+ export async function getChainflipBalance(
43
+ api: ApiPromise,
44
+ gasAsset: AssetValue,
45
+ address: string,
46
+ ): Promise<AssetValue[]> {
47
+ try {
48
+ // Chainflip uses a custom flip pallet for account balances
49
+ const flipAccount = await api.query.flip?.account?.(address);
50
+
51
+ if (!flipAccount) {
52
+ return [gasAsset.set(0)];
53
+ }
54
+
55
+ // Extract balance from the flip account structure
56
+ // The structure has a balance field directly
57
+ //@ts-expect-error
58
+ const balance = flipAccount.balance || flipAccount.data?.balance;
59
+
60
+ if (!balance || balance.isEmpty) {
61
+ return [gasAsset.set(0)];
62
+ }
63
+
64
+ // Convert balance to string using SwapKitNumber
65
+ const balanceStr = SwapKitNumber.fromBigInt(
66
+ BigInt(balance.toString()),
67
+ gasAsset.decimal,
68
+ ).getValue("string");
69
+
70
+ return [gasAsset.set(balanceStr)];
71
+ } catch (error) {
72
+ console.error("Error fetching chainflip balance:", error);
73
+ return [gasAsset.set(0)];
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Factory function to create chain-specific balance getter
79
+ */
80
+ export function createBalanceGetter(chain: Chain, api: ApiPromise) {
81
+ return function getBalance(address: string): Promise<AssetValue[]> {
82
+ const gasAsset = AssetValue.from({ chain });
83
+
84
+ switch (chain) {
85
+ case Chain.Chainflip:
86
+ return getChainflipBalance(api, gasAsset, address);
87
+
88
+ default:
89
+ return getSubstrateBalance(api, gasAsset, address);
90
+ }
91
+ };
92
+ }
@@ -19,7 +19,7 @@ import {
19
19
  } from "@swapkit/helpers";
20
20
 
21
21
  import { P, match } from "ts-pattern";
22
- import { getBalance } from "../utils";
22
+ import { createBalanceGetter } from "./balance";
23
23
  import { SubstrateNetwork, type SubstrateTransferParams } from "./types";
24
24
 
25
25
  export const PolkadotToolbox = ({ generic = false, ...signerParams }: ToolboxParams = {}) => {
@@ -36,7 +36,7 @@ export const ChainflipToolbox = async ({
36
36
  ...signerParams,
37
37
  });
38
38
 
39
- return { ...toolbox, getBalance: getBalance(Chain.Chainflip) };
39
+ return { ...toolbox };
40
40
  };
41
41
 
42
42
  export type SubstrateToolboxes = {
@@ -53,7 +53,7 @@ export function getSubstrateToolbox<T extends SubstrateChain>(chain: T, params?:
53
53
  return PolkadotToolbox(params);
54
54
  }
55
55
  default:
56
- throw new Error(`Chain ${chain} is not supported`);
56
+ throw new SwapKitError("toolbox_substrate_not_supported", { chain });
57
57
  }
58
58
  }
59
59
 
@@ -208,11 +208,13 @@ export const BaseSubstrateToolbox = ({
208
208
  network,
209
209
  gasAsset,
210
210
  signer,
211
+ chain,
211
212
  }: {
212
213
  api: ApiPromise;
213
214
  network: SubstrateNetwork;
214
215
  gasAsset: AssetValue;
215
216
  signer?: IKeyringPair | Signer;
217
+ chain?: SubstrateChain;
216
218
  }) => ({
217
219
  api,
218
220
  network,
@@ -220,7 +222,7 @@ export const BaseSubstrateToolbox = ({
220
222
  decodeAddress,
221
223
  encodeAddress,
222
224
  convertAddress,
223
- getBalance: getBalance(Chain.Polkadot),
225
+ getBalance: createBalanceGetter(chain || Chain.Polkadot, api),
224
226
  createKeyring: (phrase: string) => createKeyring(phrase, network.prefix),
225
227
  getAddress: (keyring?: IKeyringPair | Signer) => {
226
228
  const keyringPair = keyring || signer;
@@ -301,7 +303,7 @@ export async function createSubstrateToolbox({
301
303
  .with({ signer: P.any }, ({ signer }) => signer)
302
304
  .otherwise(() => undefined);
303
305
 
304
- return BaseSubstrateToolbox({ api, signer, gasAsset, network });
306
+ return BaseSubstrateToolbox({ api, signer, gasAsset, network, chain });
305
307
  }
306
308
 
307
309
  export type ToolboxParams = {
@@ -0,0 +1,147 @@
1
+ import { beforeAll, beforeEach, describe, expect, test } from "bun:test";
2
+ import { AssetValue, Chain, SKConfig } from "@swapkit/helpers";
3
+ import { createTronToolbox, getTronAddressValidator } from "../toolbox";
4
+
5
+ // Test mnemonic for consistent testing
6
+ const TEST_PHRASE =
7
+ "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
8
+
9
+ const context: {
10
+ toolbox: Awaited<ReturnType<typeof createTronToolbox>>;
11
+ validateAddress: (address: string) => boolean;
12
+ } = {} as any;
13
+
14
+ beforeAll(async () => {
15
+ // Set up TRON mainnet configuration
16
+ SKConfig.set({
17
+ rpcUrls: {
18
+ [Chain.Tron]: "https://api.trongrid.io",
19
+ },
20
+ });
21
+
22
+ // Get the address validator
23
+ context.validateAddress = await getTronAddressValidator();
24
+ });
25
+
26
+ beforeEach(async () => {
27
+ context.toolbox = await createTronToolbox({ phrase: TEST_PHRASE });
28
+ });
29
+
30
+ describe("TRON Address Validation", () => {
31
+ test("should validate valid TRON addresses", () => {
32
+ const validAddresses = [
33
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", // USDT contract
34
+ "TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7", // Mainnet address
35
+ "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", // Another valid address
36
+ ];
37
+
38
+ for (const address of validAddresses) {
39
+ expect(context.validateAddress(address)).toBe(true);
40
+ expect(context.toolbox.validateAddress(address)).toBe(true);
41
+ }
42
+ });
43
+
44
+ test("should reject invalid TRON addresses", () => {
45
+ const invalidAddresses = [
46
+ "", // Empty string
47
+ "invalid", // Random string
48
+ "0x742d35Cc6648C532F5e7c3d2a7a8E1e1e5b7c8D3", // Ethereum address
49
+ "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", // Bitcoin address
50
+ "cosmos1abc123", // Cosmos address
51
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6", // Too short
52
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6tt", // Too long
53
+ "XR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", // Wrong prefix
54
+ "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6O", // Invalid checksum
55
+ ];
56
+
57
+ for (const address of invalidAddresses) {
58
+ expect(context.validateAddress(address)).toBe(false);
59
+ expect(context.toolbox.validateAddress(address)).toBe(false);
60
+ }
61
+ });
62
+
63
+ test("should validate address from generated account", async () => {
64
+ const toolbox = context.toolbox;
65
+
66
+ // Get address from the toolbox
67
+ const address = await toolbox.getAddress();
68
+
69
+ expect(address).toBeDefined();
70
+ expect(typeof address).toBe("string");
71
+ expect(address.length).toBeGreaterThan(0);
72
+
73
+ // The generated address should be valid
74
+ expect(context.validateAddress(address)).toBe(true);
75
+ expect(toolbox.validateAddress(address)).toBe(true);
76
+
77
+ // Address should start with 'T'
78
+ expect(address.startsWith("T")).toBe(true);
79
+ });
80
+
81
+ test("should create TRON transaction with valid addresses", async () => {
82
+ const toolbox = context.toolbox;
83
+ const fromAddress = "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE";
84
+ const toAddress = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"; // Valid TRON address
85
+
86
+ // Both addresses should be valid
87
+ expect(toolbox.validateAddress(fromAddress)).toBe(true);
88
+ expect(toolbox.validateAddress(toAddress)).toBe(true);
89
+
90
+ // Create a transaction
91
+ const transaction = await toolbox.createTransaction({
92
+ recipient: toAddress,
93
+ sender: fromAddress,
94
+ assetValue: AssetValue.from({
95
+ chain: Chain.Tron,
96
+ value: "1", // 1 TRX
97
+ }),
98
+ });
99
+
100
+ expect(transaction).toBeDefined();
101
+ expect(transaction.raw_data_hex).toBeDefined();
102
+ });
103
+
104
+ test("should create TRON.USDT transaction with valid addresses", async () => {
105
+ const toolbox = context.toolbox;
106
+ const fromAddress = "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE";
107
+ const toAddress = "TT87ESmqUmH87hMx1MKCEqYrJKaQyNg9ao"; // Valid TRON address
108
+
109
+ // Both addresses should be valid
110
+ expect(toolbox.validateAddress(fromAddress)).toBe(true);
111
+ expect(toolbox.validateAddress(toAddress)).toBe(true);
112
+
113
+ // Create a transaction
114
+ const transaction = await toolbox.createTransaction({
115
+ recipient: toAddress,
116
+ sender: fromAddress,
117
+ assetValue: AssetValue.from({
118
+ asset: "TRX.USDT-TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
119
+ value: "100", // 1 TRX
120
+ }),
121
+ });
122
+
123
+ expect(transaction).toBeDefined();
124
+ expect(transaction.raw_data_hex).toBeDefined();
125
+ });
126
+
127
+ test("should handle case sensitivity in addresses", () => {
128
+ const address = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
129
+ const lowerCase = address.toLowerCase();
130
+ const upperCase = address.toUpperCase();
131
+
132
+ // TRON addresses are case sensitive - only the original should be valid
133
+ expect(context.validateAddress(address)).toBe(true);
134
+ expect(context.validateAddress(lowerCase)).toBe(false);
135
+ expect(context.validateAddress(upperCase)).toBe(false);
136
+ });
137
+
138
+ test("should handle edge cases", () => {
139
+ const edgeCases = [null, undefined, 123, {}, [], true, false];
140
+
141
+ for (const testCase of edgeCases) {
142
+ // Should not throw but return false for invalid inputs
143
+ expect(context.validateAddress(testCase as any)).toBe(false);
144
+ expect(context.toolbox.validateAddress(testCase as any)).toBe(false);
145
+ }
146
+ });
147
+ });
@@ -0,0 +1,40 @@
1
+ export const trc20ABI = [
2
+ {
3
+ constant: true,
4
+ inputs: [{ name: "_owner", type: "address" }],
5
+ name: "balanceOf",
6
+ outputs: [{ name: "balance", type: "uint256" }],
7
+ type: "function",
8
+ },
9
+ {
10
+ constant: false,
11
+ inputs: [
12
+ { name: "_to", type: "address" },
13
+ { name: "_value", type: "uint256" },
14
+ ],
15
+ name: "transfer",
16
+ outputs: [{ name: "success", type: "bool" }],
17
+ type: "function",
18
+ },
19
+ {
20
+ constant: true,
21
+ inputs: [],
22
+ name: "decimals",
23
+ outputs: [{ name: "", type: "uint8" }],
24
+ type: "function",
25
+ },
26
+ {
27
+ constant: true,
28
+ inputs: [],
29
+ name: "symbol",
30
+ outputs: [{ name: "", type: "string" }],
31
+ type: "function",
32
+ },
33
+ {
34
+ constant: true,
35
+ inputs: [],
36
+ name: "name",
37
+ outputs: [{ name: "", type: "string" }],
38
+ type: "function",
39
+ },
40
+ ] as const;
@@ -0,0 +1,16 @@
1
+ export {
2
+ createTronToolbox,
3
+ getTronAddressValidator,
4
+ getTronPrivateKeyFromMnemonic,
5
+ } from "./toolbox";
6
+ export type {
7
+ TronSigner,
8
+ TronToolboxOptions,
9
+ TronTransferParams,
10
+ TronContract,
11
+ TronTransaction,
12
+ } from "./types";
13
+ export { trc20ABI } from "./helpers/trc20.abi";
14
+
15
+ import type { createTronToolbox } from "./toolbox.js";
16
+ export type TronWallet = Awaited<ReturnType<typeof createTronToolbox>>;