@silentswap/sdk 0.1.50 → 0.1.51

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/address.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Address utilities for validating, formatting, and working with blockchain addresses.
3
- * Supports EVM (Ethereum-compatible) and Solana addresses.
3
+ * Supports EVM (Ethereum-compatible), Solana, Bitcoin, and Tron addresses.
4
4
  */
5
5
  /**
6
6
  * Contact source types
@@ -45,6 +45,15 @@ export declare function isValidSolanaAddress(address: string): boolean;
45
45
  * @returns True if valid Bitcoin address format
46
46
  */
47
47
  export declare function isValidBitcoinAddress(address: string): boolean;
48
+ /**
49
+ * Validate Tron address format
50
+ * Supports:
51
+ * - Base58 addresses starting with 'T' (common user-facing format)
52
+ * - Hex addresses starting with 0x41 (low-level representation)
53
+ * @param address - Address string to validate
54
+ * @returns True if valid Tron address format
55
+ */
56
+ export declare function isValidTronAddress(address: string): boolean;
48
57
  /**
49
58
  * Validate any supported blockchain address
50
59
  * @param address - Address string to validate
@@ -52,7 +61,7 @@ export declare function isValidBitcoinAddress(address: string): boolean;
52
61
  */
53
62
  export declare function validateAddress(address: string): {
54
63
  valid: boolean;
55
- type: 'evm' | 'solana' | 'bitcoin' | 'unknown';
64
+ type: 'evm' | 'solana' | 'bitcoin' | 'tron' | 'unknown';
56
65
  };
57
66
  /**
58
67
  * Normalize an address to its canonical form
package/dist/address.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Address utilities for validating, formatting, and working with blockchain addresses.
3
- * Supports EVM (Ethereum-compatible) and Solana addresses.
3
+ * Supports EVM (Ethereum-compatible), Solana, Bitcoin, and Tron addresses.
4
4
  */
5
5
  import { getAddress as viemGetAddress, isAddress as isEvmAddress } from 'viem';
6
6
  // ============================================================================
@@ -48,6 +48,26 @@ export function isValidBitcoinAddress(address) {
48
48
  }
49
49
  return false;
50
50
  }
51
+ /**
52
+ * Validate Tron address format
53
+ * Supports:
54
+ * - Base58 addresses starting with 'T' (common user-facing format)
55
+ * - Hex addresses starting with 0x41 (low-level representation)
56
+ * @param address - Address string to validate
57
+ * @returns True if valid Tron address format
58
+ */
59
+ export function isValidTronAddress(address) {
60
+ const trimmed = address.trim();
61
+ // Base58 Tron address (starts with 'T', 34 chars typical)
62
+ if (/^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(trimmed)) {
63
+ return true;
64
+ }
65
+ // Hex Tron address (0x41 + 20 bytes)
66
+ if (/^0x41[a-fA-F0-9]{40}$/.test(trimmed)) {
67
+ return true;
68
+ }
69
+ return false;
70
+ }
51
71
  /**
52
72
  * Validate any supported blockchain address
53
73
  * @param address - Address string to validate
@@ -63,6 +83,9 @@ export function validateAddress(address) {
63
83
  if (isValidBitcoinAddress(address)) {
64
84
  return { valid: true, type: 'bitcoin' };
65
85
  }
86
+ if (isValidTronAddress(address)) {
87
+ return { valid: true, type: 'tron' };
88
+ }
66
89
  return { valid: false, type: 'unknown' };
67
90
  }
68
91
  /**
@@ -68,7 +68,7 @@ export declare const extractChainIdsFromAssets: (assets: string[], options?: {
68
68
  * Extract chain ID from a single asset (CAIP-19 string or AssetInfo)
69
69
  * Returns number for EVM chains, 'solana' for Solana, null if invalid
70
70
  */
71
- export declare const extractChainIdFromAsset: (asset: string | AssetInfo | null, solanaChainId?: number) => number | "solana" | "bitcoin" | null;
71
+ export declare const extractChainIdFromAsset: (asset: string | AssetInfo | null, solanaChainId?: number) => number | "solana" | "bitcoin" | "tron" | null;
72
72
  /**
73
73
  * Get chain info object for the token's chain
74
74
  */
@@ -1,7 +1,7 @@
1
1
  import { getChainByCaip2 } from './assets.js';
2
2
  // Core CAIP-19 parsing utilities
3
- import { parseCaip19 as coreParseCaip19, getChainNamespace as coreGetChainNamespace, getChainId as coreGetChainId, getAssetNamespace as coreGetAssetNamespace, getAssetReference as coreGetAssetReference, getCaip2FromCaip19, getEvmChainId, isNativeToken as coreIsNativeToken, isEvmAsset, isSolanaAsset, parseEvmCaip19, isEvmNativeToken as coreIsEvmNativeToken, isErc20Token, isSolanaNativeToken as coreIsSolanaNativeToken, isSplToken, isBitcoinAsset, } from './caip19.js';
4
- import { BITCOIN_CHAIN_ID } from './chains.js';
3
+ import { parseCaip19 as coreParseCaip19, getChainNamespace as coreGetChainNamespace, getChainId as coreGetChainId, getAssetNamespace as coreGetAssetNamespace, getAssetReference as coreGetAssetReference, getCaip2FromCaip19, getEvmChainId, isNativeToken as coreIsNativeToken, isEvmAsset, isSolanaAsset, parseEvmCaip19, isEvmNativeToken as coreIsEvmNativeToken, isErc20Token, isSolanaNativeToken as coreIsSolanaNativeToken, isSplToken, isBitcoinAsset, isTronAsset as coreIsTronAsset, } from './caip19.js';
4
+ import { BITCOIN_CHAIN_ID, TRON_CHAIN_ID } from './chains.js';
5
5
  import { N_DEBRIDGE_CHAIN_ID_SOLANA } from './constants.js';
6
6
  // ============================================================================
7
7
  // CAIP-19 Parsing Wrappers (for AssetInfo convenience)
@@ -130,6 +130,9 @@ export const getTokenChainId = (token) => {
130
130
  if (isBitcoinAsset(token.caip19)) {
131
131
  return BITCOIN_CHAIN_ID;
132
132
  }
133
+ if (coreIsTronAsset(token.caip19)) {
134
+ return TRON_CHAIN_ID;
135
+ }
133
136
  // For EVM chains, return the numeric chain ID
134
137
  return getEvmChainId(token.caip19);
135
138
  };
@@ -179,6 +182,9 @@ export const extractChainIdFromAsset = (asset, solanaChainId) => {
179
182
  if (isBitcoinAsset(caip19)) {
180
183
  return 'bitcoin';
181
184
  }
185
+ if (coreIsTronAsset(caip19)) {
186
+ return 'tron';
187
+ }
182
188
  const parsed = parseEvmCaip19(caip19);
183
189
  if (parsed?.chainId) {
184
190
  // Convert Solana numeric chain ID to 'solana' if provided
package/dist/assets.js CHANGED
@@ -27,6 +27,7 @@ export function getAllAssetsArray() {
27
27
  export const COMMON_ASSETS = getAllAssetsArray().filter(asset => {
28
28
  // Filter to commonly used tokens (matches Svelte PopularTokensArea.svelte)
29
29
  const commonCaip19s = [
30
+ 'tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', // USDT on Tron
30
31
  'bip122:000000000019d6689c085ae165831e93/slip44:0', // BTC on Bitcoin
31
32
  'eip155:1/slip44:60', // ETH on Ethereum
32
33
  'eip155:1/erc20:0xdAC17F958D2ee523a2206206994597C13D831ec7', // USDT on Ethereum
package/dist/bridge.js CHANGED
@@ -1,18 +1,19 @@
1
1
  import { encodeFunctionData, erc20Abi } from 'viem';
2
2
  import BigNumber from 'bignumber.js';
3
- import { NI_CHAIN_ID_AVALANCHE, S0X_ADDR_USDC_AVALANCHE, N_DEBRIDGE_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, N_RELAY_CHAIN_ID_SUI, N_RELAY_CHAIN_ID_TRON, SB58_ADDR_SOL_PROGRAM_SYSTEM, } from './constants.js';
3
+ import { NI_CHAIN_ID_AVALANCHE, S0X_ADDR_USDC_AVALANCHE, S0X_ADDR_EVM_ZERO, UINT256_MAX, N_DEBRIDGE_CHAIN_ID_SOLANA, N_DEBRIDGE_CHAIN_ID_TRON, N_RELAY_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, N_RELAY_CHAIN_ID_SUI, N_RELAY_CHAIN_ID_TRON, S0X_ADDR_TRON_NATIVE, SB58_ADDR_SOL_PROGRAM_SYSTEM, } from './constants.js';
4
4
  import { createPhonyDepositCalldata } from './wallet.js';
5
- // Zero address for native tokens (EVM)
6
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
7
5
  /**
8
6
  * Map relay.link chain IDs to deBridge chain IDs
9
7
  * Different bridge providers use different chain ID schemes
10
8
  */
11
9
  function mapChainIdToDebridge(chainId) {
12
10
  // Map relay.link Solana chain ID to deBridge Solana chain ID
13
- if (chainId === 792703809) { // N_RELAY_CHAIN_ID_SOLANA
11
+ if (chainId === N_RELAY_CHAIN_ID_SOLANA) {
14
12
  return N_DEBRIDGE_CHAIN_ID_SOLANA;
15
13
  }
14
+ if (chainId === N_RELAY_CHAIN_ID_TRON) {
15
+ return N_DEBRIDGE_CHAIN_ID_TRON;
16
+ }
16
17
  // For other chains, return as-is (EVM chains use the same IDs)
17
18
  return chainId;
18
19
  }
@@ -22,6 +23,9 @@ function mapChainIdToDebridge(chainId) {
22
23
  function isSolanaChainId(chainId) {
23
24
  return chainId === N_DEBRIDGE_CHAIN_ID_SOLANA || chainId === N_RELAY_CHAIN_ID_SOLANA;
24
25
  }
26
+ function isTronChainId(chainId) {
27
+ return chainId === N_RELAY_CHAIN_ID_TRON || chainId === N_DEBRIDGE_CHAIN_ID_TRON;
28
+ }
25
29
  /**
26
30
  * Check if a chain ID represents a non-EVM chain (Solana, Bitcoin, Sui, Tron)
27
31
  */
@@ -80,6 +84,7 @@ export function getRelayOriginAsset(srcChainId, srcToken) {
80
84
  function normalizeTokenAddress(srcChainId, srcToken) {
81
85
  // Check if this is a Solana chain
82
86
  const isSolanaChain = isSolanaChainId(srcChainId);
87
+ const tronChain = isTronChainId(srcChainId);
83
88
  if (isSolanaChain) {
84
89
  // For Solana, check if it's a native token (system program) or empty
85
90
  // Solana native token address is the system program: 11111111111111111111111111111111
@@ -91,11 +96,17 @@ function normalizeTokenAddress(srcChainId, srcToken) {
91
96
  // Matches relay_origin_asset() line 191: k_asset_src.isSolanaToken()? k_asset_src.address()
92
97
  return srcToken;
93
98
  }
99
+ else if (tronChain) {
100
+ if (!srcToken || srcToken === '' || srcToken === '0x0' || srcToken === '0x0000000000000000000000000000000000000000') {
101
+ return S0X_ADDR_TRON_NATIVE;
102
+ }
103
+ return srcToken;
104
+ }
94
105
  else {
95
106
  // For EVM chains, normalize to zero address for native tokens
96
107
  // Matches relay_origin_asset() line 188: k_asset_src.isEvmNative()? S0X_ADDR_EVM_ZERO
97
108
  if (!srcToken || srcToken === '0x0' || srcToken === '0x0000000000000000000000000000000000000000') {
98
- return ZERO_ADDRESS;
109
+ return S0X_ADDR_EVM_ZERO;
99
110
  }
100
111
  // Return the EVM token address as-is
101
112
  // Matches relay_origin_asset() line 189: k_asset_src.isEvmErc20()? k_asset_src.address()
@@ -109,9 +120,10 @@ function normalizeTokenAddress(srcChainId, srcToken) {
109
120
  export async function executeRelayBridge(quote, executeTransaction, switchChain, setStep) {
110
121
  const txHashes = [];
111
122
  for (const tx of quote.txs) {
112
- // Solana and Bitcoin transactions don't need chain switching (handled by connector)
123
+ // Solana, Bitcoin, and Tron transactions don't need EVM chain switching (handled by chain-specific connectors)
113
124
  const isBitcoinTx = tx.chainId === N_RELAY_CHAIN_ID_BITCOIN || tx.psbt;
114
- if (!tx.instructions && !isBitcoinTx) {
125
+ const isTronTx = tx.chainId === N_RELAY_CHAIN_ID_TRON;
126
+ if (!tx.instructions && !isBitcoinTx && !isTronTx) {
115
127
  setStep(`Switching to chain ${tx.chainId}`);
116
128
  // Switch to the correct chain for EVM transactions
117
129
  await switchChain(tx.chainId);
@@ -139,12 +151,13 @@ export async function executeDebridgeBridge(quote, executeTransaction, switchCha
139
151
  throw new Error('No transactions in debridge quote');
140
152
  }
141
153
  const tx = quote.txs[0];
142
- // Non-EVM transactions don't need EVM chain switching.
154
+ // Non-EVM transactions (Solana/Bitcoin/Tron) don't need EVM chain switching.
143
155
  const isNonEvmTx = !!tx.instructions ||
144
156
  tx.chainId === N_DEBRIDGE_CHAIN_ID_SOLANA ||
145
157
  tx.chainId === N_RELAY_CHAIN_ID_SOLANA ||
146
158
  tx.chainId === N_RELAY_CHAIN_ID_BITCOIN ||
147
159
  tx.chainId === N_RELAY_CHAIN_ID_TRON ||
160
+ tx.chainId === N_DEBRIDGE_CHAIN_ID_TRON ||
148
161
  !!tx.psbt;
149
162
  if (!isNonEvmTx) {
150
163
  setStep(`Switching to chain ${tx.chainId}`);
@@ -417,7 +430,6 @@ async function fetchDebridgeSingleChainOrder(params, signal) {
417
430
  },
418
431
  };
419
432
  }
420
- const UINT256_MAX = 2n ** 256n - 1n;
421
433
  /**
422
434
  * Solve for optimal USDC amount using relay.link
423
435
  */
package/dist/caip19.d.ts CHANGED
@@ -16,6 +16,13 @@ export declare const EVM_CAIP19_REGEX: RegExp;
16
16
  * Groups: [1] chainId, [2] token address (for token), [3] slip44 number (for native)
17
17
  */
18
18
  export declare const SOLANA_CAIP19_REGEX: RegExp;
19
+ /**
20
+ * Tron CAIP-19 regex pattern for parsing native and TRC-20 tokens
21
+ * Native: tron:chainRef/slip44:195
22
+ * TRC-20: tron:chainRef/trc20:ADDRESS or tron:chainRef/token:ADDRESS
23
+ */
24
+ export declare const TRON_CAIP19_NATIVE_REGEX: RegExp;
25
+ export declare const TRON_CAIP19_TOKEN_REGEX: RegExp;
19
26
  export declare enum Caip19Namespace {
20
27
  BIP122 = "bip122",
21
28
  EIP155 = "eip155",
@@ -57,6 +64,14 @@ export interface ParsedSolanaCaip19 {
57
64
  tokenAddress: string | null;
58
65
  slip44: number | null;
59
66
  }
67
+ /**
68
+ * Parsed Tron CAIP-19 result
69
+ */
70
+ export interface ParsedTronCaip19 {
71
+ chainId: number;
72
+ isNative: boolean;
73
+ tokenAddress: string | null;
74
+ }
60
75
  /**
61
76
  * Parse a CAIP-19 string into its components
62
77
  * @param caip19 - CAIP-19 formatted string
@@ -82,6 +97,15 @@ export declare function parseEvmCaip19(caip19: string): ParsedEvmCaip19 | null;
82
97
  * @returns Parsed Solana-specific components or null if not Solana
83
98
  */
84
99
  export declare function parseSolanaCaip19(caip19: string): ParsedSolanaCaip19 | null;
100
+ /**
101
+ * Parse a Tron CAIP-19 string
102
+ * @param caip19 - CAIP-19 formatted string
103
+ * @returns Parsed Tron-specific components or null if not Tron
104
+ * @example
105
+ * parseTronCaip19('tron:728126428/slip44:195') // { chainId: 728126428, isNative: true, tokenAddress: null }
106
+ * parseTronCaip19('tron:728126428/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t') // { chainId: 728126428, isNative: false, tokenAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' }
107
+ */
108
+ export declare function parseTronCaip19(caip19: string): ParsedTronCaip19 | null;
85
109
  /**
86
110
  * Get chain namespace from CAIP-19
87
111
  * @param caip19 - CAIP-19 string
@@ -142,6 +166,12 @@ export declare function isEvmAsset(caip19: string): boolean;
142
166
  * @returns True if Solana asset
143
167
  */
144
168
  export declare function isSolanaAsset(caip19: string): boolean;
169
+ /**
170
+ * Check if CAIP-19 represents a Tron asset
171
+ * @param caip19 - CAIP-19 string
172
+ * @returns True if Tron asset
173
+ */
174
+ export declare function isTronAsset(caip19: string): boolean;
145
175
  /** BIP122 chain ID for Bitcoin mainnet (genesis hash). */
146
176
  export declare const BIP122_BITCOIN_MAINNET_CHAIN_ID = "000000000019d6689c085ae165831e93";
147
177
  /**
package/dist/caip19.js CHANGED
@@ -18,6 +18,13 @@ export const EVM_CAIP19_REGEX = /eip155:(\d+)\/(?:erc20:(0x[a-fA-F0-9]+)|slip44:
18
18
  * Groups: [1] chainId, [2] token address (for token), [3] slip44 number (for native)
19
19
  */
20
20
  export const SOLANA_CAIP19_REGEX = /solana:([a-zA-Z0-9]+)\/(?:token:([a-zA-Z0-9]+)|slip44:(\d+))/;
21
+ /**
22
+ * Tron CAIP-19 regex pattern for parsing native and TRC-20 tokens
23
+ * Native: tron:chainRef/slip44:195
24
+ * TRC-20: tron:chainRef/trc20:ADDRESS or tron:chainRef/token:ADDRESS
25
+ */
26
+ export const TRON_CAIP19_NATIVE_REGEX = /^tron:([^/]+)\/slip44:\d+$/i;
27
+ export const TRON_CAIP19_TOKEN_REGEX = /^tron:([^/]+)\/(?:trc20|token):([A-Za-z0-9]+)$/i;
21
28
  // ============================================================================
22
29
  // Enums / Types
23
30
  // ============================================================================
@@ -97,6 +104,35 @@ export function parseSolanaCaip19(caip19) {
97
104
  slip44,
98
105
  };
99
106
  }
107
+ /**
108
+ * Parse a Tron CAIP-19 string
109
+ * @param caip19 - CAIP-19 formatted string
110
+ * @returns Parsed Tron-specific components or null if not Tron
111
+ * @example
112
+ * parseTronCaip19('tron:728126428/slip44:195') // { chainId: 728126428, isNative: true, tokenAddress: null }
113
+ * parseTronCaip19('tron:728126428/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t') // { chainId: 728126428, isNative: false, tokenAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' }
114
+ */
115
+ export function parseTronCaip19(caip19) {
116
+ const nativeMatch = TRON_CAIP19_NATIVE_REGEX.exec(caip19);
117
+ if (nativeMatch) {
118
+ const chainId = Number(nativeMatch[1]);
119
+ return {
120
+ chainId: Number.isFinite(chainId) ? chainId : 0,
121
+ isNative: true,
122
+ tokenAddress: null,
123
+ };
124
+ }
125
+ const tokenMatch = TRON_CAIP19_TOKEN_REGEX.exec(caip19);
126
+ if (tokenMatch) {
127
+ const chainId = Number(tokenMatch[1]);
128
+ return {
129
+ chainId: Number.isFinite(chainId) ? chainId : 0,
130
+ isNative: false,
131
+ tokenAddress: tokenMatch[2] || null,
132
+ };
133
+ }
134
+ return null;
135
+ }
100
136
  // ============================================================================
101
137
  // Helper Functions - Extraction
102
138
  // ============================================================================
@@ -187,6 +223,14 @@ export function isEvmAsset(caip19) {
187
223
  export function isSolanaAsset(caip19) {
188
224
  return caip19.startsWith('solana:');
189
225
  }
226
+ /**
227
+ * Check if CAIP-19 represents a Tron asset
228
+ * @param caip19 - CAIP-19 string
229
+ * @returns True if Tron asset
230
+ */
231
+ export function isTronAsset(caip19) {
232
+ return caip19.startsWith('tron:');
233
+ }
190
234
  /** BIP122 chain ID for Bitcoin mainnet (genesis hash). */
191
235
  export const BIP122_BITCOIN_MAINNET_CHAIN_ID = '000000000019d6689c085ae165831e93';
192
236
  /**
package/dist/chain.d.ts CHANGED
@@ -26,6 +26,17 @@ export declare function pingWalletConnectSession(connector: {
26
26
  type: string;
27
27
  getProvider: () => Promise<unknown>;
28
28
  }): Promise<boolean>;
29
+ /**
30
+ * Clear stale WalletConnect data from localStorage.
31
+ *
32
+ * Browsers accumulate WC relay messages, expired pairings, and orphaned session
33
+ * keys across page reloads. Stale symmetric keys cause "onRelayMessage → failed
34
+ * to process an inbound message" errors because the relay delivers messages for
35
+ * topics whose keys have already been garbage-collected locally.
36
+ *
37
+ * Call on app startup and after disconnecting a wallet.
38
+ */
39
+ export declare function clearStaleWalletConnectSessions(): void;
29
40
  /**
30
41
  * Create a public client with RPC fallback configuration
31
42
  *
package/dist/chain.js CHANGED
@@ -115,6 +115,78 @@ export async function pingWalletConnectSession(connector) {
115
115
  return false;
116
116
  }
117
117
  }
118
+ /**
119
+ * Clear stale WalletConnect data from localStorage.
120
+ *
121
+ * Browsers accumulate WC relay messages, expired pairings, and orphaned session
122
+ * keys across page reloads. Stale symmetric keys cause "onRelayMessage → failed
123
+ * to process an inbound message" errors because the relay delivers messages for
124
+ * topics whose keys have already been garbage-collected locally.
125
+ *
126
+ * Call on app startup and after disconnecting a wallet.
127
+ */
128
+ export function clearStaleWalletConnectSessions() {
129
+ if (typeof localStorage === 'undefined')
130
+ return;
131
+ try {
132
+ const keys = Object.keys(localStorage).filter(k => k.startsWith('wc@2:'));
133
+ const nowSec = Math.floor(Date.now() / 1000);
134
+ let cleaned = 0;
135
+ for (const key of keys) {
136
+ // Accumulated relay messages — safe to purge entirely; the relay
137
+ // will re-deliver anything the active session still needs.
138
+ if (key.includes('//messages')) {
139
+ localStorage.removeItem(key);
140
+ cleaned++;
141
+ continue;
142
+ }
143
+ // Prune expired pairings
144
+ if (key.includes('//pairing')) {
145
+ cleaned += pruneExpiredEntries(key, nowSec);
146
+ continue;
147
+ }
148
+ // Prune expired sessions
149
+ if (key.includes('//session')) {
150
+ cleaned += pruneExpiredEntries(key, nowSec);
151
+ continue;
152
+ }
153
+ // Prune expired proposals
154
+ if (key.includes('//proposal')) {
155
+ cleaned += pruneExpiredEntries(key, nowSec);
156
+ continue;
157
+ }
158
+ }
159
+ if (cleaned > 0) {
160
+ console.log(`[clearStaleWC] cleaned ${cleaned} stale WalletConnect entries`);
161
+ }
162
+ }
163
+ catch (err) {
164
+ console.warn('[clearStaleWC] cleanup failed:', err.message);
165
+ }
166
+ }
167
+ /** Remove expired entries from a JSON-array localStorage key. Returns 1 if anything was pruned, 0 otherwise. */
168
+ function pruneExpiredEntries(storageKey, nowSec) {
169
+ try {
170
+ const raw = localStorage.getItem(storageKey);
171
+ if (!raw)
172
+ return 0;
173
+ const data = JSON.parse(raw);
174
+ if (!Array.isArray(data))
175
+ return 0;
176
+ const valid = data.filter((entry) => !entry.expiry || entry.expiry > nowSec);
177
+ if (valid.length < data.length) {
178
+ if (valid.length === 0) {
179
+ localStorage.removeItem(storageKey);
180
+ }
181
+ else {
182
+ localStorage.setItem(storageKey, JSON.stringify(valid));
183
+ }
184
+ return 1;
185
+ }
186
+ }
187
+ catch { /* ignore parse errors */ }
188
+ return 0;
189
+ }
118
190
  /**
119
191
  * Create a public client with RPC fallback configuration
120
192
  *
package/dist/chains.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { type Chain } from 'viem/chains';
2
2
  export declare const SOLANA_CHAIN_ID = 7565164;
3
3
  export declare const BITCOIN_CHAIN_ID = 8253038;
4
+ export declare const TRON_CHAIN_ID = 728126428;
4
5
  /**
5
6
  * Supported EVM chains for public client creation
6
7
  *
package/dist/chains.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { mainnet, avalanche, base, polygon, arbitrum, bsc, optimism, berachain, kava, taiko, filecoin, gnosis, coreDao, soneium, hedera, immutableZkEvm, hemi, unichain, rootstock, cronos, sei, linea, mantle, pulsechain, evmos, } from 'viem/chains';
2
2
  export const SOLANA_CHAIN_ID = 7565164;
3
3
  export const BITCOIN_CHAIN_ID = 8253038; // Relay chain ID for Bitcoin
4
+ export const TRON_CHAIN_ID = 728126428; // Relay chain ID for Tron
4
5
  /**
5
6
  * Supported EVM chains for public client creation
6
7
  *
@@ -2,6 +2,8 @@ import { type Hex } from 'viem';
2
2
  export declare const EVM_PHONY_ADDRESS: Hex;
3
3
  export declare const EVM_NATIVE_ADDRESS: Hex;
4
4
  export declare const DEAD_ADDRESS: Hex;
5
+ export declare const S0X_ADDR_EVM_ZERO: Hex;
6
+ export declare const UINT256_MAX: bigint;
5
7
  export declare const MAINNET_GATEWAY_ADDRESS = "0xA798d4D04faad17C309127C2B9B99Cc459635eDC";
6
8
  export declare const MAINNET_GATEWAY_PUBLIC_KEY = "0x0494913354a94d40604cd453d2a654489aa78472daf953c63cae4ceaaa40740d682905847e99618c34b360d8ef4645a954cc9686619995465dfdba6da34f35642f";
7
9
  export declare enum ENVIRONMENT {
@@ -32,11 +34,14 @@ export declare const SB58_ADDR_SOL_RELAY_LINK_RECIPIENT = "CbKGgVKLJFb8bBrf58DnA
32
34
  export declare const SB58_ADDR_SOL_DEAD = "1nc1nerator11111111111111111111111111111111";
33
35
  export declare const SBTC_ADDR_BITCOIN_NATIVE = "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8";
34
36
  export declare const SBTC_ADDR_BTC_RELAY_LINK_RECIPIENT = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4";
37
+ export declare const S0X_ADDR_TRON_NATIVE: "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb";
38
+ export declare const SB58_ADDR_TRON_DEAD = "TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy";
35
39
  export declare const N_RELAY_CHAIN_ID_SOLANA = 792703809;
36
40
  export declare const N_RELAY_CHAIN_ID_BITCOIN = 8253038;
37
41
  export declare const N_RELAY_CHAIN_ID_TRON = 728126428;
38
42
  export declare const N_RELAY_CHAIN_ID_SUI = 103665049;
39
43
  export declare const N_DEBRIDGE_CHAIN_ID_SOLANA = 7565164;
44
+ export declare const N_DEBRIDGE_CHAIN_ID_TRON = 100000026;
40
45
  export declare const S0X_ADDR_EVM_RELAY_LINK_DEAD = "0x000000000000000000000000000000000000dead";
41
46
  export declare const P_URL_API_RPC_SOLANA = "https://api.mainnet-beta.solana.com";
42
47
  export declare const CALCULATION_DIRECTION_INPUT_TO_OUTPUT: "input-to-output";
package/dist/constants.js CHANGED
@@ -2,6 +2,8 @@
2
2
  export const EVM_PHONY_ADDRESS = '0x1111111111111111111111111111111111111111';
3
3
  export const EVM_NATIVE_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
4
4
  export const DEAD_ADDRESS = '0x000000000000000000000000000000000000dead';
5
+ export const S0X_ADDR_EVM_ZERO = '0x0000000000000000000000000000000000000000';
6
+ export const UINT256_MAX = 2n ** 256n - 1n;
5
7
  // Mainnet constants
6
8
  const MAINNET_SILENTSWAP_API = 'https://api.silentswap.com';
7
9
  const STAGING_SILENTSWAP_API = 'https://api-staging.silentswap.com';
@@ -59,6 +61,13 @@ export const SBTC_ADDR_BITCOIN_NATIVE = 'bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8
59
61
  // Valid Bitcoin recipient address for relay.link quote estimation (BIP-173 test vector P2WPKH)
60
62
  // relay.link rejects the phony zero address (SBTC_ADDR_BITCOIN_NATIVE) as recipient — use this fallback
61
63
  export const SBTC_ADDR_BTC_RELAY_LINK_RECIPIENT = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4';
64
+ // Tron constants
65
+ // Tron native token (TRX) pseudo-address used by Relay/deBridge for native TRX.
66
+ // Note: despite the historic "dead" naming, this is the canonical Tron native placeholder.
67
+ export const S0X_ADDR_TRON_NATIVE = 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb';
68
+ // Valid Tron recipient address for relay.link quote estimation (Tron Foundation burn address).
69
+ // relay.link rejects the native TRX pseudo-address (S0X_ADDR_TRON_NATIVE) as recipient — use this fallback.
70
+ export const SB58_ADDR_TRON_DEAD = 'TLsV52sRDL79HXGGm9yzwKibb6BeruhUzy';
62
71
  // Relay.link chain IDs for non-EVM chains
63
72
  export const N_RELAY_CHAIN_ID_SOLANA = 792703809;
64
73
  export const N_RELAY_CHAIN_ID_BITCOIN = 8253038;
@@ -66,6 +75,7 @@ export const N_RELAY_CHAIN_ID_TRON = 728126428;
66
75
  export const N_RELAY_CHAIN_ID_SUI = 103665049;
67
76
  // deBridge chain IDs for non-EVM chains
68
77
  export const N_DEBRIDGE_CHAIN_ID_SOLANA = 7565164;
78
+ export const N_DEBRIDGE_CHAIN_ID_TRON = 100000026;
69
79
  // Relay.link EVM constants
70
80
  export const S0X_ADDR_EVM_RELAY_LINK_DEAD = '0x000000000000000000000000000000000000dead';
71
81
  // Solana RPC endpoint (default, can be overridden via environment)
@@ -485,6 +485,18 @@
485
485
  "nativeCoinId": "ethereum",
486
486
  "name": "Soneium"
487
487
  },
488
+ "tron:0x2b6653dc": {
489
+ "coingeckoPlatformId": "tron",
490
+ "coingeckoId": "tron",
491
+ "native": {
492
+ "slip44": 195,
493
+ "decimals": 6,
494
+ "symbol": "TRX"
495
+ },
496
+ "caip2": "tron:0x2b6653dc",
497
+ "nativeCoinId": "tron",
498
+ "name": "TRON"
499
+ },
488
500
  "bip122:000000000019d6689c085ae165831e93": {
489
501
  "coingeckoPlatformId": "bitcoin",
490
502
  "coingeckoId": "bitcoin",
@@ -3590,6 +3602,28 @@
3590
3602
  "1C0E00"
3591
3603
  ]
3592
3604
  },
3605
+ "tron:0x2b6653dc/slip44:195": {
3606
+ "caip19": "tron:0x2b6653dc/slip44:195",
3607
+ "coingeckoId": "tron",
3608
+ "name": "TRON",
3609
+ "symbol": "TRX",
3610
+ "decimals": 6,
3611
+ "gradient": [
3612
+ "000000",
3613
+ "1C0E00"
3614
+ ]
3615
+ },
3616
+ "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t": {
3617
+ "caip19": "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
3618
+ "coingeckoId": "tether",
3619
+ "name": "Tether USD (Tron)",
3620
+ "symbol": "USDT",
3621
+ "decimals": 6,
3622
+ "gradient": [
3623
+ "26A17B",
3624
+ "125C48"
3625
+ ]
3626
+ },
3593
3627
  "eip155:56/erc20:0x000Ae314E2A2172a039B26378814C252734f556A": {
3594
3628
  "caip19": "eip155:56/erc20:0x000Ae314E2A2172a039B26378814C252734f556A",
3595
3629
  "coingeckoId": "aster-2",
@@ -1,16 +1,19 @@
1
1
  import BigNumber from 'bignumber.js';
2
2
  import { fetchRelayQuote, fetchDebridgeOrder, } from './bridge.js';
3
- import { N_DEBRIDGE_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, SB58_ADDR_SOL_PROGRAM_SYSTEM, SB58_ADDR_SOL_DEAD, SB58_ADDR_SOL_RELAY_LINK_RECIPIENT, SBTC_ADDR_BITCOIN_NATIVE, SBTC_ADDR_BTC_RELAY_LINK_RECIPIENT, DEAD_ADDRESS, } from './constants.js';
4
- const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
3
+ import { N_DEBRIDGE_CHAIN_ID_SOLANA, N_DEBRIDGE_CHAIN_ID_TRON, N_RELAY_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, N_RELAY_CHAIN_ID_TRON, S0X_ADDR_EVM_ZERO, SB58_ADDR_SOL_PROGRAM_SYSTEM, SB58_ADDR_SOL_DEAD, SB58_ADDR_SOL_RELAY_LINK_RECIPIENT, SBTC_ADDR_BITCOIN_NATIVE, SB58_ADDR_TRON_DEAD, S0X_ADDR_TRON_NATIVE, SBTC_ADDR_BTC_RELAY_LINK_RECIPIENT, DEAD_ADDRESS, } from './constants.js';
5
4
  /**
6
5
  * Map relay.link chain IDs to deBridge chain IDs
7
6
  * Different bridge providers use different chain ID schemes
8
7
  */
9
8
  function mapChainIdToDebridge(chainId) {
10
9
  // Map relay.link Solana chain ID to deBridge Solana chain ID
11
- if (chainId === 792703809) { // N_RELAY_CHAIN_ID_SOLANA
10
+ if (chainId === N_RELAY_CHAIN_ID_SOLANA) {
12
11
  return N_DEBRIDGE_CHAIN_ID_SOLANA;
13
12
  }
13
+ // Map relay.link Tron chain ID to deBridge Tron chain ID
14
+ if (chainId === N_RELAY_CHAIN_ID_TRON) {
15
+ return N_DEBRIDGE_CHAIN_ID_TRON;
16
+ }
14
17
  // For other chains, return as-is (EVM chains use the same IDs)
15
18
  return chainId;
16
19
  }
@@ -18,7 +21,7 @@ function mapChainIdToDebridge(chainId) {
18
21
  * Check if a chain ID represents Solana (either relay or deBridge format)
19
22
  */
20
23
  function isSolanaChainId(chainId) {
21
- return chainId === N_DEBRIDGE_CHAIN_ID_SOLANA || chainId === 792703809; // N_RELAY_CHAIN_ID_SOLANA
24
+ return chainId === N_DEBRIDGE_CHAIN_ID_SOLANA || chainId === N_RELAY_CHAIN_ID_SOLANA;
22
25
  }
23
26
  /**
24
27
  * Check if a chain ID represents Bitcoin
@@ -26,6 +29,23 @@ function isSolanaChainId(chainId) {
26
29
  function isBitcoinChainId(chainId) {
27
30
  return chainId === N_RELAY_CHAIN_ID_BITCOIN;
28
31
  }
32
+ /**
33
+ * Check if a chain ID represents Tron
34
+ */
35
+ function isTronChainId(chainId) {
36
+ return chainId === N_RELAY_CHAIN_ID_TRON || chainId === N_DEBRIDGE_CHAIN_ID_TRON;
37
+ }
38
+ function isTronAddress(address) {
39
+ if (!address)
40
+ return false;
41
+ return /^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(address) || /^0x41[a-fA-F0-9]{40}$/.test(address);
42
+ }
43
+ function isValidTronRecipientAddress(address) {
44
+ if (!isTronAddress(address))
45
+ return false;
46
+ // The native-token pseudo-address must never be used as recipient/authority.
47
+ return address !== S0X_ADDR_TRON_NATIVE;
48
+ }
29
49
  /**
30
50
  * Normalize token address for bridge API calls
31
51
  * Handles EVM (hex addresses), Solana (base58 addresses), and Bitcoin
@@ -35,7 +55,16 @@ function normalizeTokenAddressForQuote(chainId, token) {
35
55
  const isSolanaChain = isSolanaChainId(chainId);
36
56
  // Check if this is a Bitcoin chain
37
57
  const isBitcoinChain = isBitcoinChainId(chainId);
38
- if (isBitcoinChain) {
58
+ // Check if this is a Tron chain
59
+ const isTronChain = isTronChainId(chainId);
60
+ if (isTronChain) {
61
+ // For Tron native, relay/deBridge expect Tron native pseudo-address (T9y...).
62
+ if (!token || token === '' || token === '0x0' || token === '0x0000000000000000000000000000000000000000') {
63
+ return S0X_ADDR_TRON_NATIVE;
64
+ }
65
+ return token;
66
+ }
67
+ else if (isBitcoinChain) {
39
68
  // For Bitcoin, native token (BTC) uses the Bitcoin native token address
40
69
  // relay.link expects "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8" for native Bitcoin
41
70
  if (!token || token === '' || token === '0x0' || token === '0x0000000000000000000000000000000000000000') {
@@ -56,7 +85,7 @@ function normalizeTokenAddressForQuote(chainId, token) {
56
85
  else {
57
86
  // For EVM chains, normalize to zero address for native tokens
58
87
  if (!token || token === '0x0' || token === '0x0000000000000000000000000000000000000000') {
59
- return ZERO_ADDRESS;
88
+ return S0X_ADDR_EVM_ZERO;
60
89
  }
61
90
  return token;
62
91
  }
@@ -323,15 +352,31 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
323
352
  // Map chain IDs for deBridge (relay.link uses different chain IDs for Solana)
324
353
  const debridgeSrcChainId = mapChainIdToDebridge(srcChainId);
325
354
  const debridgeDstChainId = mapChainIdToDebridge(dstChainId);
326
- // Check if destination is Solana or Bitcoin
355
+ // Check if destination is Solana, Bitcoin, or Tron
327
356
  const isDestSolana = isSolanaChainId(debridgeDstChainId);
328
357
  const isSrcSolana = isSolanaChainId(debridgeSrcChainId);
329
358
  const isDestBitcoin = isBitcoinChainId(dstChainId);
330
359
  const isSrcBitcoin = isBitcoinChainId(srcChainId);
360
+ const isDestTron = isTronChainId(dstChainId);
361
+ const isSrcTron = isTronChainId(srcChainId);
331
362
  // Determine the correct user address for relay.link based on source chain
332
363
  // Relay.link requires the user address to match the source chain format
333
364
  let relayUserAddress;
334
- if (isSrcBitcoin) {
365
+ if (isSrcTron) {
366
+ // Source is Tron - user must be Tron address (starts with 'T')
367
+ if (sourceAddress && sourceAddress.startsWith('T')) {
368
+ relayUserAddress = sourceAddress;
369
+ }
370
+ else if (typeof userAddress === 'string' && userAddress.startsWith('T')) {
371
+ relayUserAddress = userAddress;
372
+ }
373
+ else {
374
+ // Fallback to Tron dead address for estimation
375
+ console.warn('Tron address required for Tron source chain, using Tron dead address');
376
+ relayUserAddress = SB58_ADDR_TRON_DEAD;
377
+ }
378
+ }
379
+ else if (isSrcBitcoin) {
335
380
  // Source is Bitcoin - user must be Bitcoin address
336
381
  // Prefer sourceAddress if provided, then check userAddress format
337
382
  if (sourceAddress && !sourceAddress.startsWith('0x') && !sourceAddress.startsWith('1111')) {
@@ -430,7 +475,11 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
430
475
  };
431
476
  // Set user address (must match source chain format)
432
477
  relayParams.user = relayUserAddress;
433
- // Set recipient based on destination chain
478
+ // Set recipient based on destination chain.
479
+ // IMPORTANT: Destination-based branches MUST come before source-based branches.
480
+ // The recipient format is dictated by the DESTINATION chain, not the source.
481
+ // Otherwise e.g. BTC→SOL would fall into `isSrcBitcoin` and get an EVM
482
+ // dead address as the Solana recipient, which relay.link rejects.
434
483
  if (isDestBitcoin) {
435
484
  // For Bitcoin destinations, relay.link requires:
436
485
  // - user to be the source chain address (EVM address if source is EVM)
@@ -446,24 +495,23 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
446
495
  relayParams.recipient = SBTC_ADDR_BTC_RELAY_LINK_RECIPIENT;
447
496
  }
448
497
  }
449
- else if (isSrcBitcoin) {
450
- // For EVM destinations when source is Bitcoin, relay.link requires:
451
- // - user to be the Bitcoin address (source chain)
452
- // - recipient to be the EVM address (destination chain)
453
- if (recipientAddress && recipientAddress.startsWith('0x')) {
454
- // Use provided EVM recipient address
498
+ else if (isDestTron) {
499
+ // For Tron destinations, relay.link requires:
500
+ // - recipient to be a valid Tron address (starts with 'T')
501
+ if (isValidTronRecipientAddress(recipientAddress)) {
455
502
  relayParams.recipient = recipientAddress;
456
503
  }
457
504
  else {
458
- // Fallback to EVM dead address if no recipient provided
459
- relayParams.recipient = DEAD_ADDRESS;
505
+ throw new Error('Tron recipient address required for Tron destination');
460
506
  }
461
507
  }
462
508
  else if (isDestSolana) {
463
509
  // For Solana destinations, relay.link requires:
464
510
  // - user to be DEAD_ADDRESS (EVM dead address) when source is EVM
465
511
  // - recipient to be the Solana address
466
- if (!isSrcSolana) {
512
+ // For non-EVM sources (Solana/Bitcoin/Tron), keep the source-chain user
513
+ // address that relayUserAddress was already populated with above.
514
+ if (!isSrcSolana && !isSrcBitcoin && !isSrcTron) {
467
515
  // Source is EVM, destination is Solana
468
516
  relayParams.user = DEAD_ADDRESS;
469
517
  }
@@ -477,6 +525,19 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
477
525
  relayParams.recipient = SB58_ADDR_SOL_RELAY_LINK_RECIPIENT;
478
526
  }
479
527
  }
528
+ else if (isSrcBitcoin) {
529
+ // For EVM destinations when source is Bitcoin, relay.link requires:
530
+ // - user to be the Bitcoin address (source chain)
531
+ // - recipient to be the EVM address (destination chain)
532
+ if (recipientAddress && recipientAddress.startsWith('0x')) {
533
+ // Use provided EVM recipient address
534
+ relayParams.recipient = recipientAddress;
535
+ }
536
+ else {
537
+ // Fallback to EVM dead address if no recipient provided
538
+ relayParams.recipient = DEAD_ADDRESS;
539
+ }
540
+ }
480
541
  else if (isSrcSolana) {
481
542
  // For EVM destinations when source is Solana, relay.link requires:
482
543
  // - user to be the Solana address (source chain)
@@ -512,10 +573,12 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
512
573
  if (!useDebridge)
513
574
  return null;
514
575
  try {
515
- // Skip deBridge for Bitcoin - Bitcoin only supports relay
576
+ // Skip deBridge for Bitcoin only.
516
577
  if (isSrcBitcoin || isDestBitcoin) {
517
578
  return null;
518
579
  }
580
+ // deBridge account/authority should follow source-chain address format
581
+ const debridgeSourceAddress = relayUserAddress;
519
582
  const isExactOutput = tradeType === 'EXACT_OUTPUT' && dstAmount;
520
583
  const debridgeParams = {
521
584
  srcChainId: debridgeSrcChainId,
@@ -523,16 +586,14 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
523
586
  srcChainTokenInAmount: isExactOutput ? 'auto' : srcAmount,
524
587
  dstChainId: debridgeDstChainId,
525
588
  dstChainTokenOut: dstTokenNorm,
589
+ dstChainTokenOutAmount: isExactOutput ? dstAmount : 'auto',
526
590
  prependOperatingExpenses: true,
527
- account: userAddress,
591
+ additionalTakerRewardBps: 0,
592
+ account: debridgeSourceAddress,
528
593
  };
529
- if (isExactOutput) {
530
- debridgeParams.dstChainTokenOutAmount = dstAmount;
531
- }
532
594
  // Handle Solana source or destination
533
595
  if (isSrcSolana || isDestSolana) {
534
596
  // For Solana source or destination
535
- // Don't set dstChainTokenOutAmount unless EXACT_OUTPUT (omit it for EXACT_INPUT mode)
536
597
  debridgeParams.enableEstimate = false;
537
598
  // Set recipient address (required for Solana source or destination)
538
599
  if (!recipientAddress) {
@@ -544,13 +605,22 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
544
605
  // Set authority addresses based on source/destination
545
606
  if (isSrcSolana) {
546
607
  // Source is Solana
547
- debridgeParams.srcChainOrderAuthorityAddress = userAddress; // Solana sender
548
- debridgeParams.srcChainRefundAddress = userAddress; // Solana sender
608
+ debridgeParams.srcChainOrderAuthorityAddress = debridgeSourceAddress; // Solana sender
609
+ debridgeParams.srcChainRefundAddress = debridgeSourceAddress; // Solana sender
549
610
  if (isDestSolana) {
550
611
  // Solana to Solana
551
612
  debridgeParams.dstChainTokenOutRecipient = recipientAddress; // Solana recipient
552
613
  debridgeParams.dstChainOrderAuthorityAddress = recipientAddress; // Solana recipient
553
614
  }
615
+ else if (isDestTron) {
616
+ // Solana to Tron
617
+ if (!isValidTronRecipientAddress(recipientAddress)) {
618
+ throw new Error('Tron recipient address required for Tron destination');
619
+ }
620
+ const tronRecipient = recipientAddress;
621
+ debridgeParams.dstChainTokenOutRecipient = tronRecipient; // Tron recipient (TVM)
622
+ debridgeParams.dstChainOrderAuthorityAddress = tronRecipient; // Tron authority (TVM)
623
+ }
554
624
  else {
555
625
  // Solana to EVM
556
626
  debridgeParams.dstChainTokenOutRecipient = recipientAddress; // EVM recipient
@@ -559,8 +629,8 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
559
629
  }
560
630
  else {
561
631
  // Source is EVM, destination is Solana
562
- debridgeParams.srcChainOrderAuthorityAddress = userAddress; // EVM sender
563
- debridgeParams.srcChainRefundAddress = userAddress; // EVM sender
632
+ debridgeParams.srcChainOrderAuthorityAddress = debridgeSourceAddress; // EVM sender
633
+ debridgeParams.srcChainRefundAddress = debridgeSourceAddress; // EVM sender
564
634
  debridgeParams.dstChainTokenOutRecipient = recipientAddress; // Solana recipient
565
635
  debridgeParams.dstChainOrderAuthorityAddress = recipientAddress; // Solana recipient
566
636
  }
@@ -569,18 +639,18 @@ forceProvider, tradeType = 'EXACT_INPUT', dstAmount) {
569
639
  // Both source and destination are EVM
570
640
  // API requires dstChainTokenOutRecipient, srcChainOrderAuthorityAddress, dstChainOrderAuthorityAddress for transaction construction
571
641
  // Use recipientAddress when provided (user-set recipient), otherwise fall back to userAddress (send to self)
572
- const evmRecipient = recipientAddress && recipientAddress.startsWith('0x') ? recipientAddress : userAddress;
573
- debridgeParams.dstChainTokenOutRecipient = evmRecipient;
574
- debridgeParams.srcChainOrderAuthorityAddress = userAddress;
575
- debridgeParams.dstChainOrderAuthorityAddress = evmRecipient;
576
- debridgeParams.srcChainRefundAddress = userAddress;
577
- debridgeParams.senderAddress = userAddress;
578
- if (!isExactOutput) {
579
- debridgeParams.dstChainTokenOutAmount = 'auto';
642
+ const evmRecipient = recipientAddress && recipientAddress.startsWith('0x') ? recipientAddress : debridgeSourceAddress;
643
+ if (isDestTron && !isValidTronRecipientAddress(recipientAddress)) {
644
+ throw new Error('Tron recipient address required for Tron destination');
580
645
  }
581
- debridgeParams.enableEstimate = true;
646
+ const tronRecipient = recipientAddress;
647
+ debridgeParams.dstChainTokenOutRecipient = isDestTron ? tronRecipient : evmRecipient;
648
+ debridgeParams.srcChainOrderAuthorityAddress = debridgeSourceAddress;
649
+ debridgeParams.dstChainOrderAuthorityAddress = isDestTron ? tronRecipient : evmRecipient;
650
+ debridgeParams.srcChainRefundAddress = debridgeSourceAddress;
651
+ debridgeParams.senderAddress = debridgeSourceAddress;
652
+ debridgeParams.enableEstimate = isDestTron || isSrcTron ? false : true;
582
653
  // Optional params matching deSwap app for consistent API behavior
583
- debridgeParams.additionalTakerRewardBps = 0;
584
654
  debridgeParams.deBridgeApp = 'DESWAP';
585
655
  debridgeParams.ptp = false;
586
656
  debridgeParams.srcChainPriorityLevel = 'normal';
package/dist/rpc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { arbitrum, avalanche, base, berachain, bsc, mainnet, optimism, polygon } from 'viem/chains';
2
- import { SOLANA_CHAIN_ID, BITCOIN_CHAIN_ID } from './chains.js';
2
+ import { SOLANA_CHAIN_ID, BITCOIN_CHAIN_ID, TRON_CHAIN_ID } from './chains.js';
3
3
  /**
4
4
  * Custom RPC endpoint configuration for EVM chains, Solana, and Bitcoin
5
5
  *
@@ -36,4 +36,6 @@ export const H_RPCS = {
36
36
  [bsc.id]: 'https://yolo-wandering-fire.bsc.quiknode.pro/07aae5c8f9c95c4d596a6997e6a28a786dc3d4a0/',
37
37
  // Berachain
38
38
  [berachain.id]: 'https://capable-purple-dream.bera-mainnet.quiknode.pro/11502780a6ec104db00d7940f6a61c90868a4402/',
39
+ // Tron
40
+ [TRON_CHAIN_ID]: 'https://multi-icy-borough.tron-mainnet.quiknode.pro/58b72b5b6563a1122911fb254444777c9214d96c/jsonrpc',
39
41
  };
@@ -11,25 +11,30 @@ export type SolanaTransactionExecutor = (tx: BridgeTransaction) => Promise<strin
11
11
  * Returns transaction signature string
12
12
  */
13
13
  export type BitcoinTransactionExecutor = (tx: BridgeTransaction) => Promise<string>;
14
+ /**
15
+ * Tron transaction executor type
16
+ * Returns transaction signature string
17
+ */
18
+ export type TronTransactionExecutor = (tx: BridgeTransaction) => Promise<string>;
14
19
  /**
15
20
  * Universal transaction executor type
16
- * Returns Hex for EVM, base58 string for Solana, string for Bitcoin
21
+ * Returns Hex for EVM, base58 string for Solana, string for Bitcoin/Tron
17
22
  */
18
23
  export type UniversalTransactionExecutor = (tx: BridgeTransaction) => Promise<Hex | string>;
19
24
  /**
20
25
  * Create transaction execution wrapper for framework-agnostic bridge execution
21
- * Supports EVM, Solana, and Bitcoin transactions
26
+ * Supports EVM, Solana, Bitcoin, and Tron transactions
22
27
  */
23
- export declare function createTransactionExecutor(walletClient: WalletClient, connector: Connector, solanaExecutor?: SolanaTransactionExecutor, bitcoinExecutor?: BitcoinTransactionExecutor): UniversalTransactionExecutor;
28
+ export declare function createTransactionExecutor(walletClient: WalletClient | undefined, connector: Connector | undefined, solanaExecutor?: SolanaTransactionExecutor, bitcoinExecutor?: BitcoinTransactionExecutor, tronExecutor?: TronTransactionExecutor): UniversalTransactionExecutor;
24
29
  /**
25
30
  * Create chain switching wrapper
26
31
  */
27
32
  export declare function createChainSwitcher(walletClient: WalletClient, connector: Connector): (chainId: number) => Promise<void>;
28
33
  /**
29
34
  * Execute a bridge transaction (framework-agnostic)
30
- * Supports EVM, Solana, and Bitcoin transactions
35
+ * Supports EVM, Solana, Bitcoin, and Tron transactions
31
36
  */
32
- export declare function executeBridgeTransaction(quote: BridgeQuote, walletClient: WalletClient, connector: Connector, setStep: (step: string) => void, solanaExecutor?: SolanaTransactionExecutor, bitcoinExecutor?: BitcoinTransactionExecutor): Promise<BridgeStatus>;
37
+ export declare function executeBridgeTransaction(quote: BridgeQuote, walletClient: WalletClient, connector: Connector, setStep: (step: string) => void, solanaExecutor?: SolanaTransactionExecutor, bitcoinExecutor?: BitcoinTransactionExecutor, tronExecutor?: TronTransactionExecutor): Promise<BridgeStatus>;
33
38
  /**
34
39
  * Get bridge status (framework-agnostic)
35
40
  */
@@ -1,10 +1,10 @@
1
1
  import { executeRelayBridge, executeDebridgeBridge, getRelayStatus, getDebridgeStatus, } from './bridge.js';
2
- import { N_DEBRIDGE_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, N_RELAY_CHAIN_ID_SOLANA } from './constants.js';
2
+ import { N_RELAY_CHAIN_ID_BITCOIN, N_RELAY_CHAIN_ID_TRON, N_RELAY_CHAIN_ID_SOLANA, N_DEBRIDGE_CHAIN_ID_SOLANA, N_DEBRIDGE_CHAIN_ID_TRON, } from './constants.js';
3
3
  /**
4
4
  * Create transaction execution wrapper for framework-agnostic bridge execution
5
- * Supports EVM, Solana, and Bitcoin transactions
5
+ * Supports EVM, Solana, Bitcoin, and Tron transactions
6
6
  */
7
- export function createTransactionExecutor(walletClient, connector, solanaExecutor, bitcoinExecutor) {
7
+ export function createTransactionExecutor(walletClient, connector, solanaExecutor, bitcoinExecutor, tronExecutor) {
8
8
  return async (tx) => {
9
9
  // Bitcoin transaction - check for Bitcoin chainId or psbt field
10
10
  if (tx.chainId === N_RELAY_CHAIN_ID_BITCOIN || tx.psbt) {
@@ -14,7 +14,15 @@ export function createTransactionExecutor(walletClient, connector, solanaExecuto
14
14
  }
15
15
  return await bitcoinExecutor(tx);
16
16
  }
17
- // Solana transaction - relay instructions or deBridge serialized Solana tx
17
+ // Tron transaction - check for both relay and deBridge Tron chain IDs
18
+ if (tx.chainId === N_RELAY_CHAIN_ID_TRON || tx.chainId === N_DEBRIDGE_CHAIN_ID_TRON) {
19
+ if (!tronExecutor) {
20
+ throw new Error('Tron transaction detected but Tron executor not provided. ' +
21
+ 'Please provide tronExecutor when creating the transaction executor.');
22
+ }
23
+ return await tronExecutor(tx);
24
+ }
25
+ // Solana transaction - relay instructions or deBridge serialized Solana tx.
18
26
  const isSolanaTx = !!tx.instructions ||
19
27
  tx.chainId === N_RELAY_CHAIN_ID_SOLANA ||
20
28
  tx.chainId === N_DEBRIDGE_CHAIN_ID_SOLANA;
@@ -29,6 +37,9 @@ export function createTransactionExecutor(walletClient, connector, solanaExecuto
29
37
  if (!tx.to || tx.value === undefined || !tx.data) {
30
38
  throw new Error('Invalid EVM transaction: missing required fields (to, value, data)');
31
39
  }
40
+ if (!walletClient || !connector) {
41
+ throw new Error('EVM transaction detected but walletClient/connector not provided.');
42
+ }
32
43
  // Switch to the correct chain if needed
33
44
  let currentChainId;
34
45
  try {
@@ -82,10 +93,10 @@ export function createChainSwitcher(walletClient, connector) {
82
93
  }
83
94
  /**
84
95
  * Execute a bridge transaction (framework-agnostic)
85
- * Supports EVM, Solana, and Bitcoin transactions
96
+ * Supports EVM, Solana, Bitcoin, and Tron transactions
86
97
  */
87
- export async function executeBridgeTransaction(quote, walletClient, connector, setStep, solanaExecutor, bitcoinExecutor) {
88
- const executeTransaction = createTransactionExecutor(walletClient, connector, solanaExecutor, bitcoinExecutor);
98
+ export async function executeBridgeTransaction(quote, walletClient, connector, setStep, solanaExecutor, bitcoinExecutor, tronExecutor) {
99
+ const executeTransaction = createTransactionExecutor(walletClient, connector, solanaExecutor, bitcoinExecutor, tronExecutor);
89
100
  const switchChain = createChainSwitcher(walletClient, connector);
90
101
  switch (quote.provider) {
91
102
  case 'relay':
@@ -14,14 +14,16 @@ export type Caip2NsCosmos = 'cosmos';
14
14
  export type Caip2NsSolana = 'solana';
15
15
  export type Caip2NsSui = 'sui';
16
16
  export type Caip2NsStellar = 'stellar';
17
- export type Caip2Ns = Caip2NsBip122 | Caip2NsEip155 | Caip2NsCosmos | Caip2NsSolana | Caip2NsSui | Caip2NsStellar;
17
+ export type Caip2NsTron = 'tron';
18
+ export type Caip2Ns = Caip2NsBip122 | Caip2NsEip155 | Caip2NsCosmos | Caip2NsSolana | Caip2NsSui | Caip2NsStellar | Caip2NsTron;
18
19
  export type Caip2Bip122 = `${Caip2NsBip122}:${string}`;
19
20
  export type Caip2Eip155 = `${Caip2NsEip155}:${IntStr}`;
20
21
  export type Caip2Cosmos = `${Caip2NsCosmos}:${string}`;
21
22
  export type Caip2Solana = `${Caip2NsSolana}:${string}`;
22
23
  export type Caip2Sui = `${Caip2NsSui}:${'mainnet' | 'testnet' | 'devnet'}`;
23
24
  export type Caip2Stellar = `${Caip2NsStellar}:${string}`;
24
- export type Caip2 = Caip2Bip122 | Caip2Eip155 | Caip2Cosmos | Caip2Solana | Caip2Sui | Caip2Stellar;
25
+ export type Caip2Tron = `${Caip2NsTron}:${string}`;
26
+ export type Caip2 = Caip2Bip122 | Caip2Eip155 | Caip2Cosmos | Caip2Solana | Caip2Sui | Caip2Stellar | Caip2Tron;
25
27
  export type Caip19NsEip155 = `erc${bigint}:${Hex}`;
26
28
  export type Caip19NsIcs20 = `ics20:${string}`;
27
29
  export type Caip19NsSolana = `solana:${Base58}/token:${Base58}`;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@silentswap/sdk",
3
3
  "type": "module",
4
- "version": "0.1.50",
4
+ "version": "0.1.51",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
7
7
  "files": [
@@ -485,6 +485,18 @@
485
485
  "nativeCoinId": "ethereum",
486
486
  "name": "Soneium"
487
487
  },
488
+ "tron:0x2b6653dc": {
489
+ "coingeckoPlatformId": "tron",
490
+ "coingeckoId": "tron",
491
+ "native": {
492
+ "slip44": 195,
493
+ "decimals": 6,
494
+ "symbol": "TRX"
495
+ },
496
+ "caip2": "tron:0x2b6653dc",
497
+ "nativeCoinId": "tron",
498
+ "name": "TRON"
499
+ },
488
500
  "bip122:000000000019d6689c085ae165831e93": {
489
501
  "coingeckoPlatformId": "bitcoin",
490
502
  "coingeckoId": "bitcoin",
@@ -3590,6 +3602,28 @@
3590
3602
  "1C0E00"
3591
3603
  ]
3592
3604
  },
3605
+ "tron:0x2b6653dc/slip44:195": {
3606
+ "caip19": "tron:0x2b6653dc/slip44:195",
3607
+ "coingeckoId": "tron",
3608
+ "name": "TRON",
3609
+ "symbol": "TRX",
3610
+ "decimals": 6,
3611
+ "gradient": [
3612
+ "000000",
3613
+ "1C0E00"
3614
+ ]
3615
+ },
3616
+ "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t": {
3617
+ "caip19": "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
3618
+ "coingeckoId": "tether",
3619
+ "name": "Tether USD (Tron)",
3620
+ "symbol": "USDT",
3621
+ "decimals": 6,
3622
+ "gradient": [
3623
+ "26A17B",
3624
+ "125C48"
3625
+ ]
3626
+ },
3593
3627
  "eip155:56/erc20:0x000Ae314E2A2172a039B26378814C252734f556A": {
3594
3628
  "caip19": "eip155:56/erc20:0x000Ae314E2A2172a039B26378814C252734f556A",
3595
3629
  "coingeckoId": "aster-2",