@swapkit/toolboxes 1.0.0-beta.3 → 1.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-fjfxga2v.js → chunk-5yxc1e69.js} +1 -1
- package/dist/{chunk-fjfxga2v.js.map → chunk-5yxc1e69.js.map} +1 -1
- package/dist/chunk-6f98phv2.js +4 -0
- package/dist/{chunk-0h4xdrwz.js.map → chunk-6f98phv2.js.map} +2 -2
- package/dist/{chunk-0f0249b1.js → chunk-9bqegm61.js} +1 -1
- package/dist/{chunk-p1kdg37m.js → chunk-s47y8512.js} +2 -2
- package/dist/{chunk-p1kdg37m.js.map → chunk-s47y8512.js.map} +1 -1
- package/dist/chunk-vtd17cje.js +3 -0
- package/dist/chunk-vtd17cje.js.map +10 -0
- package/dist/chunk-zcdeg6h9.js +4 -0
- package/dist/chunk-zcdeg6h9.js.map +10 -0
- package/dist/src/cosmos/index.cjs +3 -0
- package/dist/src/cosmos/index.cjs.map +16 -0
- package/dist/src/cosmos/index.js +3 -0
- package/dist/src/cosmos/index.js.map +16 -0
- package/dist/src/evm/index.cjs +3 -0
- package/dist/src/evm/index.cjs.map +18 -0
- package/dist/src/evm/index.js +3 -0
- package/dist/src/evm/index.js.map +18 -0
- package/dist/src/index.cjs +3 -0
- package/dist/src/index.cjs.map +10 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +10 -0
- package/dist/src/near/index.cjs +3 -0
- package/dist/src/near/index.cjs.map +13 -0
- package/dist/src/near/index.js +3 -0
- package/dist/src/near/index.js.map +13 -0
- package/dist/{radix → src/radix}/index.cjs +2 -2
- package/dist/src/radix/index.cjs.map +10 -0
- package/dist/src/radix/index.js +3 -0
- package/dist/src/radix/index.js.map +10 -0
- package/dist/src/ripple/index.cjs +3 -0
- package/dist/src/ripple/index.cjs.map +10 -0
- package/dist/src/ripple/index.js +3 -0
- package/dist/src/ripple/index.js.map +10 -0
- package/dist/src/solana/index.cjs +3 -0
- package/dist/src/solana/index.cjs.map +10 -0
- package/dist/src/solana/index.js +3 -0
- package/dist/src/solana/index.js.map +10 -0
- package/dist/src/substrate/index.cjs +3 -0
- package/dist/src/substrate/index.cjs.map +12 -0
- package/dist/src/substrate/index.js +3 -0
- package/dist/src/substrate/index.js.map +12 -0
- package/dist/src/tron/index.cjs +3 -0
- package/dist/src/tron/index.cjs.map +11 -0
- package/dist/src/tron/index.js +3 -0
- package/dist/src/tron/index.js.map +11 -0
- package/dist/src/utxo/index.cjs +5 -0
- package/dist/src/utxo/index.cjs.map +17 -0
- package/dist/src/utxo/index.js +5 -0
- package/dist/src/utxo/index.js.map +17 -0
- package/package.json +49 -37
- package/src/cosmos/thorchainUtils/addressFormat.ts +4 -1
- package/src/cosmos/thorchainUtils/messages.ts +2 -2
- package/src/cosmos/thorchainUtils/registry.ts +3 -3
- package/src/cosmos/toolbox/cosmos.ts +35 -16
- package/src/cosmos/toolbox/index.ts +2 -2
- package/src/cosmos/toolbox/thorchain.ts +11 -9
- package/src/cosmos/util.ts +76 -6
- package/src/evm/__tests__/address-validation.test.ts +86 -0
- package/src/evm/__tests__/ethereum.test.ts +1 -1
- package/src/evm/helpers.ts +4 -3
- package/src/evm/toolbox/baseEVMToolbox.ts +37 -25
- package/src/evm/toolbox/index.ts +2 -2
- package/src/evm/toolbox/op.ts +21 -7
- package/src/index.ts +118 -100
- package/src/near/__tests__/core.test.ts +80 -0
- package/src/near/helpers/contractFactory.ts +22 -0
- package/src/near/helpers/core.ts +89 -0
- package/src/near/helpers/gasEstimation.ts +110 -0
- package/src/near/helpers/index.ts +5 -0
- package/src/near/helpers/nep141.ts +110 -0
- package/src/near/index.ts +24 -0
- package/src/near/toolbox.ts +498 -0
- package/src/near/types/contract.ts +48 -0
- package/src/near/types/nep141.ts +66 -0
- package/src/near/types.ts +57 -0
- package/src/radix/index.ts +8 -2
- package/src/ripple/index.ts +15 -26
- package/src/solana/toolbox.ts +73 -2
- package/src/substrate/balance.ts +92 -0
- package/src/substrate/substrate.ts +7 -5
- package/src/tron/__tests__/toolbox.test.ts +147 -0
- package/src/tron/helpers/trc20.abi.ts +40 -0
- package/src/tron/index.ts +16 -0
- package/src/tron/toolbox.ts +336 -0
- package/src/tron/types.ts +31 -0
- package/src/utxo/__tests__/zcash-integration.test.ts +114 -0
- package/src/utxo/helpers/api.ts +66 -16
- package/src/utxo/helpers/bchaddrjs.ts +8 -8
- package/src/utxo/helpers/coinselect.ts +4 -2
- package/src/utxo/helpers/txSize.ts +4 -3
- package/src/utxo/index.ts +1 -0
- package/src/utxo/toolbox/bitcoinCash.ts +22 -14
- package/src/utxo/toolbox/index.ts +16 -4
- package/src/utxo/toolbox/utxo.ts +42 -27
- package/src/utxo/toolbox/zcash.ts +208 -0
- package/src/utxo/types.ts +2 -0
- package/dist/chunk-0h4xdrwz.js +0 -4
- package/dist/cosmos/index.cjs +0 -3
- package/dist/cosmos/index.cjs.map +0 -16
- package/dist/cosmos/index.js +0 -3
- package/dist/cosmos/index.js.map +0 -16
- package/dist/evm/index.cjs +0 -3
- package/dist/evm/index.cjs.map +0 -18
- package/dist/evm/index.js +0 -3
- package/dist/evm/index.js.map +0 -18
- package/dist/index.cjs +0 -3
- package/dist/index.cjs.map +0 -10
- package/dist/index.js +0 -3
- package/dist/index.js.map +0 -10
- package/dist/radix/index.cjs.map +0 -10
- package/dist/radix/index.js +0 -3
- package/dist/radix/index.js.map +0 -10
- package/dist/ripple/index.cjs +0 -3
- package/dist/ripple/index.cjs.map +0 -10
- package/dist/ripple/index.js +0 -3
- package/dist/ripple/index.js.map +0 -10
- package/dist/solana/index.cjs +0 -3
- package/dist/solana/index.cjs.map +0 -10
- package/dist/solana/index.js +0 -3
- package/dist/solana/index.js.map +0 -10
- package/dist/substrate/index.cjs +0 -3
- package/dist/substrate/index.cjs.map +0 -11
- package/dist/substrate/index.js +0 -3
- package/dist/substrate/index.js.map +0 -11
- package/dist/utxo/index.cjs +0 -3
- package/dist/utxo/index.cjs.map +0 -16
- package/dist/utxo/index.js +0 -3
- package/dist/utxo/index.js.map +0 -16
- /package/dist/{chunk-0f0249b1.js.map → chunk-9bqegm61.js.map} +0 -0
package/src/ripple/index.ts
CHANGED
|
@@ -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.
|
|
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 ===
|
|
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
|
-
}:
|
|
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
|
-
|
|
156
|
-
const result: any = submitResult.result;
|
|
153
|
+
const result = submitResult.result;
|
|
157
154
|
|
|
158
|
-
|
|
159
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
190
|
+
disconnect,
|
|
202
191
|
};
|
|
203
192
|
};
|
package/src/solana/toolbox.ts
CHANGED
|
@@ -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:
|
|
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 {
|
|
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
|
|
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
|
|
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:
|
|
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>>;
|