@silentswap/react 0.1.49 → 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/contexts/AssetsContext.js +1 -0
- package/dist/contexts/BalancesContext.d.ts +3 -1
- package/dist/contexts/BalancesContext.js +235 -7
- package/dist/contexts/SilentSwapContext.d.ts +6 -1
- package/dist/contexts/SilentSwapContext.js +7 -4
- package/dist/hooks/silent/tron-transaction.d.ts +34 -4
- package/dist/hooks/silent/tron-transaction.js +45 -1
- package/dist/hooks/silent/useAuth.js +14 -0
- package/dist/hooks/silent/useBridgeExecution.d.ts +12 -2
- package/dist/hooks/silent/useBridgeExecution.js +341 -114
- package/dist/hooks/silent/useQuoteCalculation.d.ts +3 -1
- package/dist/hooks/silent/useQuoteCalculation.js +72 -5
- package/dist/hooks/silent/useSilentQuote.d.ts +8 -1
- package/dist/hooks/silent/useSilentQuote.js +77 -7
- package/dist/hooks/useContacts.d.ts +2 -2
- package/dist/hooks/useOrderEstimates.d.ts +3 -1
- package/dist/hooks/useOrderEstimates.js +23 -11
- package/dist/hooks/usePlatformHealth.d.ts +8 -1
- package/dist/hooks/usePlatformHealth.js +6 -3
- package/dist/hooks/useQuote.js +53 -15
- package/dist/hooks/useTransaction.d.ts +6 -1
- package/dist/hooks/useTransaction.js +89 -8
- package/dist/hooks/useTransactionAddress.d.ts +3 -2
- package/dist/hooks/useTransactionAddress.js +10 -6
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
-
import { isSolanaAsset, isBitcoinAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, getAssetByCaip19, solveOptimalUsdcAmount, N_RELAY_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, SB58_ADDR_SOL_PROGRAM_SYSTEM, isSolanaNativeToken, parseSolanaCaip19, EVM_PHONY_ADDRESS, isValidSolanaAddress, isValidBitcoinAddress, isValidEvmAddress, getAddressFromCaip10, S0X_ADDR_USDC_AVALANCHE, caip19FungibleEvmToken, FacilitatorKeyType, createHdFacilitatorGroupFromEntropy, PublicKeyArgGroups, SB58_CHAIN_ID_SOLANA_MAINNET, caip19SplToken, DeliveryMethod, X_MAX_IMPACT_PERCENT, SBTC_ADDR_BITCOIN_NATIVE, isEvmAsset, } from '@silentswap/sdk';
|
|
2
|
+
import { isSolanaAsset, isBitcoinAsset, isTronAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, getAssetByCaip19, solveOptimalUsdcAmount, N_RELAY_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_BITCOIN, N_RELAY_CHAIN_ID_TRON, SB58_ADDR_SOL_PROGRAM_SYSTEM, isSolanaNativeToken, parseSolanaCaip19, parseTronCaip19, EVM_PHONY_ADDRESS, isValidSolanaAddress, isValidBitcoinAddress, isValidEvmAddress, isValidTronAddress, getAddressFromCaip10, S0X_ADDR_USDC_AVALANCHE, caip19FungibleEvmToken, FacilitatorKeyType, createHdFacilitatorGroupFromEntropy, PublicKeyArgGroups, SB58_CHAIN_ID_SOLANA_MAINNET, caip19SplToken, DeliveryMethod, X_MAX_IMPACT_PERCENT, SBTC_ADDR_BITCOIN_NATIVE, S0X_ADDR_TRON_NATIVE, isEvmAsset, } from '@silentswap/sdk';
|
|
3
3
|
import { getAddress } from 'viem';
|
|
4
4
|
import { BigNumber } from 'bignumber.js';
|
|
5
5
|
/**
|
|
@@ -13,7 +13,7 @@ import { BigNumber } from 'bignumber.js';
|
|
|
13
13
|
* - Destination amount updates
|
|
14
14
|
*/
|
|
15
15
|
// TODO: Simplify this hook by removing the useCallback and useState and just returning the calculateQuote function.
|
|
16
|
-
export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddress, getQuote, getPrice, setDestinations, proId, forceBridgeProvider, }) {
|
|
16
|
+
export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddress, getQuote, getPrice, setDestinations, proId, tronAddress, forceBridgeProvider, }) {
|
|
17
17
|
const [loadingAmounts, setLoadingAmounts] = useState(false);
|
|
18
18
|
const [depositAmountUsdc, setDepositAmountUsdc] = useState(0);
|
|
19
19
|
const calculateQuote = useCallback(async (debouncedSourceAsset, debouncedSourceAmount, destinations, splits) => {
|
|
@@ -30,6 +30,7 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
30
30
|
const isSourceUsdcAvalanche = debouncedSourceAsset === S_CAIP19_USDC_AVALANCHE;
|
|
31
31
|
const isSourceSolana = isSolanaAsset(debouncedSourceAsset);
|
|
32
32
|
const isSourceBitcoin = isBitcoinAsset(debouncedSourceAsset);
|
|
33
|
+
const isSourceTron = isTronAsset(debouncedSourceAsset);
|
|
33
34
|
let usdcAmountOut;
|
|
34
35
|
let sourceAmountInUnitsForQuote;
|
|
35
36
|
let bridgeProviderResult = 'none';
|
|
@@ -40,6 +41,7 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
40
41
|
isSourceUsdcAvalanche,
|
|
41
42
|
isSourceSolana,
|
|
42
43
|
isSourceBitcoin,
|
|
44
|
+
isSourceTron,
|
|
43
45
|
destinationsCount: destinations.length,
|
|
44
46
|
splits,
|
|
45
47
|
});
|
|
@@ -131,6 +133,31 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
131
133
|
bridgeProviderResult = solveResult.provider;
|
|
132
134
|
allowanceTargetResult = solveResult.allowanceTarget;
|
|
133
135
|
}
|
|
136
|
+
else if (isSourceTron) {
|
|
137
|
+
const assetInfo = getAssetByCaip19(debouncedSourceAsset);
|
|
138
|
+
if (!assetInfo)
|
|
139
|
+
throw new Error(`Tron asset not found`);
|
|
140
|
+
const tronParsed = parseTronCaip19(debouncedSourceAsset);
|
|
141
|
+
if (!tronParsed)
|
|
142
|
+
throw new Error(`Invalid Tron CAIP-19 format: ${debouncedSourceAsset}`);
|
|
143
|
+
const sourceAmountBN = BigNumber(debouncedSourceAmount);
|
|
144
|
+
sourceAmountInUnitsForQuote = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
145
|
+
if (!evmAddress) {
|
|
146
|
+
throw new Error('EVM address required for Tron swaps (needed for deposit calldata and recipient)');
|
|
147
|
+
}
|
|
148
|
+
const tronSenderAddress = typeof address === 'string' && !address.startsWith('0x') ? address : null;
|
|
149
|
+
if (!tronSenderAddress) {
|
|
150
|
+
throw new Error('Tron address required for Tron swaps');
|
|
151
|
+
}
|
|
152
|
+
const solveResult = await solveOptimalUsdcAmount(N_RELAY_CHAIN_ID_TRON, tronParsed.isNative ? S0X_ADDR_TRON_NATIVE : (tronParsed.tokenAddress || S0X_ADDR_TRON_NATIVE), sourceAmountInUnitsForQuote, tronSenderAddress, undefined, X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress), forceBridgeProvider);
|
|
153
|
+
if (abortController.signal.aborted) {
|
|
154
|
+
setLoadingAmounts(false);
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
usdcAmountOut = solveResult.usdcAmountOut.toString();
|
|
158
|
+
bridgeProviderResult = solveResult.provider;
|
|
159
|
+
allowanceTargetResult = solveResult.allowanceTarget;
|
|
160
|
+
}
|
|
134
161
|
else {
|
|
135
162
|
// EVM assets
|
|
136
163
|
const sourceAssetParsed = parseEvmCaip19(debouncedSourceAsset);
|
|
@@ -200,8 +227,9 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
200
227
|
}
|
|
201
228
|
const isDestSolana = isSolanaAsset(dest.asset);
|
|
202
229
|
const isDestBitcoin = isBitcoinAsset(dest.asset);
|
|
230
|
+
const isDestTron = isTronAsset(dest.asset);
|
|
203
231
|
let asset;
|
|
204
|
-
let recipientAddress; //
|
|
232
|
+
let recipientAddress; // Includes Solana, Bitcoin, Tron, and EVM addresses
|
|
205
233
|
if (isDestSolana) {
|
|
206
234
|
// Solana destination
|
|
207
235
|
const destParsed = parseSolanaCaip19(dest.asset);
|
|
@@ -265,6 +293,40 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
265
293
|
throw new Error(`Bitcoin destination ${idx} requires a recipient address in the contact field`);
|
|
266
294
|
}
|
|
267
295
|
}
|
|
296
|
+
else if (isDestTron) {
|
|
297
|
+
asset = dest.asset;
|
|
298
|
+
if (dest.contact) {
|
|
299
|
+
if (dest.contact.startsWith('caip10:tron:')) {
|
|
300
|
+
recipientAddress = getAddressFromCaip10(dest.contact);
|
|
301
|
+
if (!(isValidTronAddress(recipientAddress) && recipientAddress !== S0X_ADDR_TRON_NATIVE)) {
|
|
302
|
+
throw new Error(`Invalid Tron address extracted from CAIP10: ${dest.contact} -> ${recipientAddress}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else if (isValidTronAddress(dest.contact) && dest.contact !== S0X_ADDR_TRON_NATIVE) {
|
|
306
|
+
recipientAddress = dest.contact;
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
if (tronAddress && isValidTronAddress(tronAddress) && tronAddress !== S0X_ADDR_TRON_NATIVE) {
|
|
310
|
+
console.warn(`[SilentSwap:QuoteCalc] Invalid Tron destination contact for index ${idx}, falling back to connected Tron address`, {
|
|
311
|
+
contact: dest.contact,
|
|
312
|
+
tronAddress,
|
|
313
|
+
});
|
|
314
|
+
recipientAddress = tronAddress;
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
throw new Error(`Invalid Tron recipient address for destination ${idx}: ${dest.contact}. Expected Tron address or caip10:tron:*: format.`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
if (tronAddress && isValidTronAddress(tronAddress) && tronAddress !== S0X_ADDR_TRON_NATIVE) {
|
|
323
|
+
recipientAddress = tronAddress;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
throw new Error(`Tron destination ${idx} requires a recipient address in the contact field`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
268
330
|
else {
|
|
269
331
|
// EVM destination (including XRPL which uses eip155 namespace)
|
|
270
332
|
const destParsed = parseEvmCaip19(dest.asset);
|
|
@@ -345,7 +407,12 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
345
407
|
throw new Error(`Invalid recipient address type for Bitcoin destination ${idx}: ${recipientAddress}. Expected Bitcoin address (bc1, 1, or 3 prefix).`);
|
|
346
408
|
}
|
|
347
409
|
}
|
|
348
|
-
else if (
|
|
410
|
+
else if (isDestTron) {
|
|
411
|
+
if (!(isValidTronAddress(recipientAddress) && recipientAddress !== S0X_ADDR_TRON_NATIVE)) {
|
|
412
|
+
throw new Error(`Invalid recipient address type for Tron destination ${idx}: ${recipientAddress}. Expected Tron address.`);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
else if (!isDestSolana && !isDestBitcoin && !isDestTron) {
|
|
349
416
|
// Validate EVM address format
|
|
350
417
|
if (isEvmAsset(dest.asset) && !isValidEvmAddress(recipientAddress)) {
|
|
351
418
|
throw new Error(`Invalid recipient address type for EVM destination ${idx}: ${recipientAddress}. Expected 0x-prefixed EVM address.`);
|
|
@@ -460,7 +527,7 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
460
527
|
// Always ensure loading state is reset (safety net)
|
|
461
528
|
setLoadingAmounts(false);
|
|
462
529
|
}
|
|
463
|
-
}, [wallet, address, evmAddress, getQuote, getPrice, setDestinations, depositorAddress, proId]);
|
|
530
|
+
}, [wallet, address, evmAddress, getQuote, getPrice, setDestinations, depositorAddress, proId, tronAddress, forceBridgeProvider]);
|
|
464
531
|
return {
|
|
465
532
|
calculateQuote,
|
|
466
533
|
loadingAmounts,
|
|
@@ -3,6 +3,7 @@ import type { WalletClient } from 'viem';
|
|
|
3
3
|
import type { Connector } from 'wagmi';
|
|
4
4
|
import type { SolanaWalletConnector, SolanaConnection } from './solana-transaction.js';
|
|
5
5
|
import type { BitcoinWalletConnector, BitcoinConnection } from './bitcoin-transaction.js';
|
|
6
|
+
import type { TronWalletConnector, TronConnection } from './tron-transaction.js';
|
|
6
7
|
import { type SwapTransaction } from '../useTransaction.js';
|
|
7
8
|
import type { SilentSwapWallet } from './useWallet.js';
|
|
8
9
|
export type { SwapTransaction };
|
|
@@ -63,6 +64,12 @@ export interface useSilentQuoteOptions {
|
|
|
63
64
|
bitcoinConnector?: BitcoinWalletConnector;
|
|
64
65
|
/** Bitcoin connection (optional, for consistency) */
|
|
65
66
|
bitcoinConnection?: BitcoinConnection;
|
|
67
|
+
/** Tron wallet connector (required for Tron swaps) */
|
|
68
|
+
tronConnector?: TronWalletConnector;
|
|
69
|
+
/** Tron connection (optional, for consistency) */
|
|
70
|
+
tronConnection?: TronConnection;
|
|
71
|
+
/** Connected Tron address used for Tron destination recipient fallback. */
|
|
72
|
+
tronAddress?: string;
|
|
66
73
|
/** Get price function */
|
|
67
74
|
getPrice: (asset: AssetInfo) => Promise<number>;
|
|
68
75
|
setDestinations: (updater: Destination[] | ((prev: Destination[]) => Destination[])) => void;
|
|
@@ -105,4 +112,4 @@ export interface ExecuteSwapParams {
|
|
|
105
112
|
/** Optional integrator ID for tracking */
|
|
106
113
|
integratorId?: string;
|
|
107
114
|
}
|
|
108
|
-
export declare function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, auth, authenticate, wallet, walletLoading, walletError, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, proId, forceBridgeProvider, }: useSilentQuoteOptions): useSilentQuoteReturn;
|
|
115
|
+
export declare function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, auth, authenticate, wallet, walletLoading, walletError, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, tronConnector, tronConnection, tronAddress, getPrice, setDestinations, proId, forceBridgeProvider, }: useSilentQuoteOptions): useSilentQuoteReturn;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useCallback, useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
-
import { hexToBase58, isSolanaAsset, isBitcoinAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, NI_CHAIN_ID_AVALANCHE, } from '@silentswap/sdk';
|
|
2
|
+
import { hexToBase58, isSolanaAsset, isBitcoinAsset, isTronAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, NI_CHAIN_ID_AVALANCHE, } from '@silentswap/sdk';
|
|
3
3
|
import { getAddress } from 'viem';
|
|
4
4
|
import { useQuoteFetching } from './useQuoteFetching.js';
|
|
5
5
|
import { useOrderSigning } from './useOrderSigning.js';
|
|
6
6
|
import { APPROVE_POST_DELAY_MS, useBridgeExecution } from './useBridgeExecution.js';
|
|
7
7
|
import { useTransaction } from '../useTransaction.js';
|
|
8
8
|
import { useQuoteCalculation } from './useQuoteCalculation.js';
|
|
9
|
-
export function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, auth, authenticate, wallet, walletLoading = false, walletError = null, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, proId, forceBridgeProvider, }) {
|
|
9
|
+
export function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, auth, authenticate, wallet, walletLoading = false, walletError = null, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, tronConnector, tronConnection, tronAddress, getPrice, setDestinations, proId, forceBridgeProvider, }) {
|
|
10
10
|
const [isLoading, setIsLoading] = useState(false);
|
|
11
11
|
const [currentStep, setCurrentStep] = useState('');
|
|
12
12
|
const [quote, setQuote] = useState(null);
|
|
@@ -57,7 +57,7 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
57
57
|
// Initialize specialized hooks
|
|
58
58
|
const { getQuote: getQuoteInternal } = useQuoteFetching(client, rawAddress, setIsLoading, setCurrentStep, setError, onStatus);
|
|
59
59
|
const { signAuthorizations, createOrder } = useOrderSigning(walletClient, connector, client, setCurrentStep, onStatus);
|
|
60
|
-
const { executeSolanaBridge, executeBitcoinBridge, executeEvmBridge } = useBridgeExecution(walletClient, connector, solanaConnector, solanaConnection, solanaRpcUrl, setCurrentStep, depositorAddress, onStatus, bitcoinConnector, bitcoinConnection);
|
|
60
|
+
const { executeSolanaBridge, executeBitcoinBridge, executeTronBridge, executeEvmBridge } = useBridgeExecution(walletClient, connector, solanaConnector, solanaConnection, solanaRpcUrl, setCurrentStep, depositorAddress, onStatus, bitcoinConnector, bitcoinConnection, tronConnector, tronConnection);
|
|
61
61
|
const { executeSwapTransaction, approveTokenSpending } = useTransaction({
|
|
62
62
|
address: normalizedAddress || '0x0000000000000000000000000000000000000000',
|
|
63
63
|
walletClient,
|
|
@@ -65,6 +65,10 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
65
65
|
solanaConnector,
|
|
66
66
|
solanaConnection,
|
|
67
67
|
solanaRpcUrl,
|
|
68
|
+
bitcoinConnector,
|
|
69
|
+
bitcoinConnection,
|
|
70
|
+
tronConnector,
|
|
71
|
+
tronConnection,
|
|
68
72
|
setCurrentStep,
|
|
69
73
|
onStatus,
|
|
70
74
|
});
|
|
@@ -90,6 +94,7 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
90
94
|
getPrice,
|
|
91
95
|
setDestinations,
|
|
92
96
|
proId,
|
|
97
|
+
tronAddress,
|
|
93
98
|
forceBridgeProvider,
|
|
94
99
|
});
|
|
95
100
|
/**
|
|
@@ -268,8 +273,9 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
268
273
|
// Check swap type
|
|
269
274
|
const isSourceSolana = isSolanaAsset(sourceAsset);
|
|
270
275
|
const isSourceBitcoin = isBitcoinAsset(sourceAsset);
|
|
276
|
+
const isSourceTron = isTronAsset(sourceAsset);
|
|
271
277
|
const isDepositingDirectly = sourceAsset === S_CAIP19_USDC_AVALANCHE;
|
|
272
|
-
const isSourceEvm = !isSourceSolana && !isSourceBitcoin && !isDepositingDirectly && sourceAsset.startsWith('eip155:');
|
|
278
|
+
const isSourceEvm = !isSourceSolana && !isSourceBitcoin && !isSourceTron && !isDepositingDirectly && sourceAsset.startsWith('eip155:');
|
|
273
279
|
// Generate viewing authorization
|
|
274
280
|
const viewer = await resolvedGroup.viewer();
|
|
275
281
|
const evmSigner = await viewer.evmSigner();
|
|
@@ -292,7 +298,7 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
292
298
|
viewingAuth,
|
|
293
299
|
provider: providerForSwap,
|
|
294
300
|
});
|
|
295
|
-
const result = await executeSolanaSwap(quoteResponse, sourceAsset, sourceAmountInUnits, effectiveUsdcAmount, senderContactId, solanaConnector, evmSignerAddress, viewingAuth, createOrder, executeSolanaBridge, resolvedGroup, integratorId);
|
|
301
|
+
const result = await executeSolanaSwap(quoteResponse, sourceAsset, sourceAmountInUnits, effectiveUsdcAmount, senderContactId, solanaConnector, evmSignerAddress, viewingAuth, createOrder, executeSolanaBridge, resolvedGroup, providerForSwap, integratorId);
|
|
296
302
|
setOrderId(result.orderId);
|
|
297
303
|
setViewingAuth(result.viewingAuth);
|
|
298
304
|
return result;
|
|
@@ -306,6 +312,13 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
306
312
|
setViewingAuth(result.viewingAuth);
|
|
307
313
|
return result;
|
|
308
314
|
}
|
|
315
|
+
// Handle Tron swaps
|
|
316
|
+
if (isSourceTron) {
|
|
317
|
+
const result = await executeTronSwap(quoteResponse, sourceAsset, sourceAmountInUnits, effectiveUsdcAmount, senderContactId, tronConnector, evmSignerAddress, viewingAuth, createOrder, executeTronBridge, resolvedGroup, providerForSwap, integratorId);
|
|
318
|
+
setOrderId(result.orderId);
|
|
319
|
+
setViewingAuth(result.viewingAuth);
|
|
320
|
+
return result;
|
|
321
|
+
}
|
|
309
322
|
// Sign authorizations (for EVM swaps)
|
|
310
323
|
const signedAuths = await signAuthorizations(quoteResponse.authorizations, isDepositingDirectly);
|
|
311
324
|
// Create order with resolved facilitator group
|
|
@@ -389,10 +402,13 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
389
402
|
generateWallet,
|
|
390
403
|
solanaConnector,
|
|
391
404
|
bitcoinConnector,
|
|
405
|
+
tronConnector,
|
|
392
406
|
signAuthorizations,
|
|
393
407
|
createOrder,
|
|
394
408
|
approveTokenSpending,
|
|
395
409
|
executeSolanaBridge,
|
|
410
|
+
executeBitcoinBridge,
|
|
411
|
+
executeTronBridge,
|
|
396
412
|
executeEvmBridge,
|
|
397
413
|
executeSwapTransaction,
|
|
398
414
|
calculateQuote,
|
|
@@ -433,7 +449,7 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
433
449
|
* 4. Returns swap result
|
|
434
450
|
*/
|
|
435
451
|
async function executeSolanaSwap(quoteResponse, sourceAsset, sourceAmount, usdcAmount, senderContactId, solanaConnector, evmSignerAddress, // EVM signer address (matches Svelte's s0x_signer)
|
|
436
|
-
viewingAuth, createOrder, executeSolanaBridge, facilitatorGroup, integratorId) {
|
|
452
|
+
viewingAuth, createOrder, executeSolanaBridge, facilitatorGroup, provider, integratorId) {
|
|
437
453
|
if (!solanaConnector) {
|
|
438
454
|
throw new Error('Solana connector required for Solana swaps');
|
|
439
455
|
}
|
|
@@ -489,7 +505,10 @@ viewingAuth, createOrder, executeSolanaBridge, facilitatorGroup, integratorId) {
|
|
|
489
505
|
depositParamsKeys: Object.keys(depositParams),
|
|
490
506
|
});
|
|
491
507
|
// Execute bridge transaction
|
|
492
|
-
const bridgeResult = await executeSolanaBridge(sourceAsset, sourceAmount, usdcAmount, solanaSenderAddress, evmSignerAddress,
|
|
508
|
+
const bridgeResult = await executeSolanaBridge(sourceAsset, sourceAmount, usdcAmount, solanaSenderAddress, evmSignerAddress, {
|
|
509
|
+
depositParams,
|
|
510
|
+
provider,
|
|
511
|
+
});
|
|
493
512
|
console.log('[SilentSwap:SolanaSwap] Bridge result', {
|
|
494
513
|
depositTxHash: bridgeResult.depositTxHash,
|
|
495
514
|
provider: bridgeResult.provider,
|
|
@@ -569,6 +588,57 @@ viewingAuth, createOrder, executeBitcoinBridge, facilitatorGroup, integratorId)
|
|
|
569
588
|
},
|
|
570
589
|
};
|
|
571
590
|
}
|
|
591
|
+
/**
|
|
592
|
+
* Execute Tron swap flow
|
|
593
|
+
*
|
|
594
|
+
* Handles the complete flow for Tron-based bridge swaps:
|
|
595
|
+
* 1. Validates Tron connection
|
|
596
|
+
* 2. Creates order (with empty authorizations for Tron)
|
|
597
|
+
* 3. Executes bridge transaction
|
|
598
|
+
* 4. Returns swap result
|
|
599
|
+
*/
|
|
600
|
+
async function executeTronSwap(quoteResponse, sourceAsset, sourceAmount, usdcAmount, senderContactId, tronConnector, evmSignerAddress, viewingAuth, createOrder, executeTronBridge, facilitatorGroup, provider, integratorId) {
|
|
601
|
+
if (!tronConnector) {
|
|
602
|
+
throw new Error('Tron connector required for Tron swaps');
|
|
603
|
+
}
|
|
604
|
+
const accounts = await tronConnector.getAccounts();
|
|
605
|
+
const tronSenderAddress = tronConnector.currentAccount || accounts[0] || '';
|
|
606
|
+
if (!tronSenderAddress) {
|
|
607
|
+
throw new Error('Failed to get Tron sender address');
|
|
608
|
+
}
|
|
609
|
+
const orderResponse = await createOrder(quoteResponse, quoteResponse.authorizations.map((auth) => ({
|
|
610
|
+
...auth,
|
|
611
|
+
signature: '0x',
|
|
612
|
+
})), {
|
|
613
|
+
sourceAsset: {
|
|
614
|
+
caip19: sourceAsset,
|
|
615
|
+
amount: `${BigInt(sourceAmount)}`,
|
|
616
|
+
},
|
|
617
|
+
sourceSender: {
|
|
618
|
+
contactId: senderContactId,
|
|
619
|
+
},
|
|
620
|
+
...(integratorId && { integratorId }),
|
|
621
|
+
}, facilitatorGroup);
|
|
622
|
+
const depositParams = orderResponse.transaction.metadata?.params;
|
|
623
|
+
if (!depositParams) {
|
|
624
|
+
throw new Error('Missing deposit parameters in order response');
|
|
625
|
+
}
|
|
626
|
+
const bridgeResult = await executeTronBridge(sourceAsset, sourceAmount, usdcAmount, tronSenderAddress, evmSignerAddress, {
|
|
627
|
+
depositParams,
|
|
628
|
+
provider,
|
|
629
|
+
});
|
|
630
|
+
const resultOrderId = orderResponse.response.orderId;
|
|
631
|
+
return {
|
|
632
|
+
orderId: resultOrderId,
|
|
633
|
+
viewingAuth,
|
|
634
|
+
depositTransaction: {
|
|
635
|
+
hash: bridgeResult.depositTxHash,
|
|
636
|
+
chainId: NI_CHAIN_ID_AVALANCHE,
|
|
637
|
+
status: 'confirmed',
|
|
638
|
+
confirmations: 1,
|
|
639
|
+
},
|
|
640
|
+
};
|
|
641
|
+
}
|
|
572
642
|
/**
|
|
573
643
|
* Execute EVM swap flow
|
|
574
644
|
*
|
|
@@ -16,7 +16,7 @@ export declare class AddressBookContact {
|
|
|
16
16
|
protected _s_caip10: string;
|
|
17
17
|
protected _s_ens: string;
|
|
18
18
|
protected _s_sns: string;
|
|
19
|
-
protected _s_caip2_ns: 'eip155' | 'solana' | 'bip122' | 'cosmos';
|
|
19
|
+
protected _s_caip2_ns: 'eip155' | 'solana' | 'bip122' | 'cosmos' | 'tron';
|
|
20
20
|
private _saveCallback?;
|
|
21
21
|
constructor(_g_info: AddressBookContactInfo, b_from_id?: boolean, saveCallback?: (contact: AddressBookContact) => void);
|
|
22
22
|
private updateENSRecord;
|
|
@@ -28,7 +28,7 @@ export declare class AddressBookContact {
|
|
|
28
28
|
get label(): string;
|
|
29
29
|
set label(s_label: string);
|
|
30
30
|
get source(): AddressBookContactSource;
|
|
31
|
-
get caip2Ns(): 'eip155' | 'solana' | 'bip122' | 'cosmos';
|
|
31
|
+
get caip2Ns(): 'eip155' | 'solana' | 'bip122' | 'cosmos' | 'tron';
|
|
32
32
|
isEvm(): boolean;
|
|
33
33
|
isSolana(): boolean;
|
|
34
34
|
isBip122(): boolean;
|
|
@@ -15,6 +15,8 @@ export interface UseOrderEstimatesOptions {
|
|
|
15
15
|
evmAddress?: `0x${string}`;
|
|
16
16
|
/** User's Solana address (base58 address) */
|
|
17
17
|
solAddress?: string;
|
|
18
|
+
/** User's Tron address (TVM base58 address) */
|
|
19
|
+
tronAddress?: string;
|
|
18
20
|
/** User's Bitcoin address */
|
|
19
21
|
bitcoinAddress?: string;
|
|
20
22
|
/** Source asset for determining which address to use (if Solana, use solAddress; if EVM, use evmAddress) */
|
|
@@ -32,7 +34,7 @@ export interface UseOrderEstimatesOptions {
|
|
|
32
34
|
*
|
|
33
35
|
* Returns retention rates that account for bridge fees and slippage
|
|
34
36
|
*/
|
|
35
|
-
export declare function useOrderEstimates({ evmAddress, solAddress, bitcoinAddress, sourceAsset, maxImpactPercent, }?: UseOrderEstimatesOptions): {
|
|
37
|
+
export declare function useOrderEstimates({ evmAddress, solAddress, tronAddress, bitcoinAddress, sourceAsset, maxImpactPercent, }?: UseOrderEstimatesOptions): {
|
|
36
38
|
estimateOrder: (usdcPrice: number, sourceAsset: AssetInfo, sourcePrice: number, sourceAmount: number | string, destinationAssets: AssetInfo[], destinationPrices: number[], splits: number[], calculationDirection?: CalculationDirection, outputAmounts?: string[], destinationContacts?: string[]) => Promise<OrderEstimateResult>;
|
|
37
39
|
isLoading: boolean;
|
|
38
40
|
error: Error | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useRef, useState, useMemo } from 'react';
|
|
2
2
|
import BigNumber from 'bignumber.js';
|
|
3
|
-
import { parseEvmCaip19, parseSolanaCaip19, isEvmNativeToken, isSolanaNativeToken, isSolanaAsset, isBitcoinAsset, EVM_PHONY_ADDRESS, SB58_ADDR_SOL_PROGRAM_SYSTEM, CALCULATION_DIRECTION_INPUT_TO_OUTPUT, CALCULATION_DIRECTION_OUTPUT_TO_INPUT, N_RELAY_CHAIN_ID_BITCOIN, SBTC_ADDR_BITCOIN_NATIVE, } from '@silentswap/sdk';
|
|
3
|
+
import { parseEvmCaip19, parseSolanaCaip19, parseTronCaip19, isEvmNativeToken, isSolanaNativeToken, isSolanaAsset, isBitcoinAsset, isTronAsset, EVM_PHONY_ADDRESS, SB58_ADDR_SOL_PROGRAM_SYSTEM, S0X_ADDR_TRON_NATIVE, CALCULATION_DIRECTION_INPUT_TO_OUTPUT, CALCULATION_DIRECTION_OUTPUT_TO_INPUT, N_RELAY_CHAIN_ID_BITCOIN, SBTC_ADDR_BITCOIN_NATIVE, } from '@silentswap/sdk';
|
|
4
4
|
import { useQuote } from './useQuote.js';
|
|
5
5
|
/**
|
|
6
6
|
* Hook for fetching both ingress and egress estimates in parallel
|
|
@@ -12,7 +12,7 @@ import { useQuote } from './useQuote.js';
|
|
|
12
12
|
*
|
|
13
13
|
* Returns retention rates that account for bridge fees and slippage
|
|
14
14
|
*/
|
|
15
|
-
export function useOrderEstimates({ evmAddress, solAddress, bitcoinAddress, sourceAsset, maxImpactPercent, } = {}) {
|
|
15
|
+
export function useOrderEstimates({ evmAddress, solAddress, tronAddress, bitcoinAddress, sourceAsset, maxImpactPercent, } = {}) {
|
|
16
16
|
const [error, setError] = useState(null);
|
|
17
17
|
const [isLoading, setIsLoading] = useState(false);
|
|
18
18
|
// Determine address for ingress quotes based on source chain
|
|
@@ -120,18 +120,23 @@ export function useOrderEstimates({ evmAddress, solAddress, bitcoinAddress, sour
|
|
|
120
120
|
console.log('[OrderEstimates] Step 3: Parsing source asset CAIP-19');
|
|
121
121
|
const isSourceSolana = isSolanaAsset(sourceAsset.caip19);
|
|
122
122
|
const isSourceBitcoin = isBitcoinAsset(sourceAsset.caip19);
|
|
123
|
-
const
|
|
123
|
+
const isSourceTron = isTronAsset(sourceAsset.caip19);
|
|
124
|
+
const sourceEvmParsed = !isSourceSolana && !isSourceBitcoin && !isSourceTron ? parseEvmCaip19(sourceAsset.caip19) : null;
|
|
124
125
|
const sourceSolanaParsed = isSourceSolana ? parseSolanaCaip19(sourceAsset.caip19) : null;
|
|
126
|
+
const sourceTronParsed = isSourceTron ? parseTronCaip19(sourceAsset.caip19) : null;
|
|
125
127
|
const sourceChainId = sourceEvmParsed?.chainId
|
|
126
128
|
?? sourceSolanaParsed?.chainId
|
|
129
|
+
?? sourceTronParsed?.chainId
|
|
127
130
|
?? (isSourceBitcoin ? N_RELAY_CHAIN_ID_BITCOIN : 0);
|
|
128
131
|
const sourceTokenAddress = isEvmNativeToken(sourceAsset.caip19)
|
|
129
132
|
? '0x0000000000000000000000000000000000000000'
|
|
130
133
|
: isSolanaNativeToken(sourceAsset.caip19)
|
|
131
134
|
? '11111111111111111111111111111111'
|
|
132
|
-
:
|
|
133
|
-
?
|
|
134
|
-
:
|
|
135
|
+
: isSourceTron
|
|
136
|
+
? (sourceTronParsed?.isNative ? S0X_ADDR_TRON_NATIVE : (sourceTronParsed?.tokenAddress ?? ''))
|
|
137
|
+
: isSourceBitcoin
|
|
138
|
+
? SBTC_ADDR_BITCOIN_NATIVE
|
|
139
|
+
: (sourceEvmParsed?.tokenAddress ?? sourceSolanaParsed?.tokenAddress ?? '');
|
|
135
140
|
console.log('[OrderEstimates] Step 3: Source asset parsed', { sourceChainId, sourceTokenAddress, isSourceSolana, isSourceBitcoin });
|
|
136
141
|
// For reverse calculation, calculate total output USD value first
|
|
137
142
|
let totalOutputUsd = 0;
|
|
@@ -184,18 +189,23 @@ export function useOrderEstimates({ evmAddress, solAddress, bitcoinAddress, sour
|
|
|
184
189
|
// Parse destination asset to get chain ID and token address from CAIP-19
|
|
185
190
|
const isDestSolana = isSolanaAsset(destAsset.caip19);
|
|
186
191
|
const isDestBitcoin = isBitcoinAsset(destAsset.caip19);
|
|
187
|
-
const
|
|
192
|
+
const isDestTron = isTronAsset(destAsset.caip19);
|
|
193
|
+
const destEvmParsed = !isDestSolana && !isDestBitcoin && !isDestTron ? parseEvmCaip19(destAsset.caip19) : null;
|
|
188
194
|
const destSolanaParsed = isDestSolana ? parseSolanaCaip19(destAsset.caip19) : null;
|
|
195
|
+
const destTronParsed = isDestTron ? parseTronCaip19(destAsset.caip19) : null;
|
|
189
196
|
const destChainId = destEvmParsed?.chainId
|
|
190
197
|
?? destSolanaParsed?.chainId
|
|
198
|
+
?? destTronParsed?.chainId
|
|
191
199
|
?? (isDestBitcoin ? N_RELAY_CHAIN_ID_BITCOIN : 0);
|
|
192
200
|
const destTokenAddress = isEvmNativeToken(destAsset.caip19)
|
|
193
201
|
? '0x0000000000000000000000000000000000000000'
|
|
194
202
|
: isSolanaNativeToken(destAsset.caip19)
|
|
195
203
|
? '11111111111111111111111111111111'
|
|
196
|
-
:
|
|
197
|
-
?
|
|
198
|
-
:
|
|
204
|
+
: isDestTron
|
|
205
|
+
? (destTronParsed?.isNative ? S0X_ADDR_TRON_NATIVE : (destTronParsed?.tokenAddress ?? ''))
|
|
206
|
+
: isDestBitcoin
|
|
207
|
+
? SBTC_ADDR_BITCOIN_NATIVE
|
|
208
|
+
: (destEvmParsed?.tokenAddress ?? destSolanaParsed?.tokenAddress ?? '');
|
|
199
209
|
// Determine recipient address based on destination chain
|
|
200
210
|
// Prefer the entered contact address (e.g. user-entered BTC address without wallet connected)
|
|
201
211
|
const contact = destinationContacts?.[idx];
|
|
@@ -203,7 +213,9 @@ export function useOrderEstimates({ evmAddress, solAddress, bitcoinAddress, sour
|
|
|
203
213
|
? (contact || solAddress)
|
|
204
214
|
: isDestBitcoin
|
|
205
215
|
? (contact || bitcoinAddress || SBTC_ADDR_BITCOIN_NATIVE)
|
|
206
|
-
:
|
|
216
|
+
: isDestTron
|
|
217
|
+
? (contact || tronAddress)
|
|
218
|
+
: (contact && contact.startsWith('0x') ? contact : evmAddress);
|
|
207
219
|
// For reverse calculation, use output amount directly with EXACT_OUTPUT
|
|
208
220
|
if (calculationDirection === CALCULATION_DIRECTION_OUTPUT_TO_INPUT && outputAmounts && outputAmounts[idx]) {
|
|
209
221
|
const outputAmount = parseFloat(outputAmounts[idx]);
|
|
@@ -50,13 +50,20 @@ export type PlatformHealthProviderProps = {
|
|
|
50
50
|
* API's own maximumDepositUusdc limit applies.
|
|
51
51
|
*/
|
|
52
52
|
maxDepositUsd?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Optional maintenance override from admin dashboard settings. When true, the effective
|
|
55
|
+
* platform health is forced to 'MAINTENANCE' regardless of what the platform status API
|
|
56
|
+
* reports — flipping formDisabled and trackingDisabled to true and letting consumers
|
|
57
|
+
* show a maintenance screen.
|
|
58
|
+
*/
|
|
59
|
+
maintenanceMode?: boolean;
|
|
53
60
|
};
|
|
54
61
|
/**
|
|
55
62
|
* Provider that monitors platform health from SilentSwapContext (which calls useStatus
|
|
56
63
|
* once with proId) and provides validation functions for deposit amounts, output limits,
|
|
57
64
|
* and service fee rates.
|
|
58
65
|
*/
|
|
59
|
-
export declare function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, maxDepositUsd, }: PlatformHealthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
66
|
+
export declare function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, maxDepositUsd, maintenanceMode, }: PlatformHealthProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
60
67
|
/**
|
|
61
68
|
* Hook to access platform health context
|
|
62
69
|
*/
|
|
@@ -9,16 +9,19 @@ const PlatformHealthContext = createContext(undefined);
|
|
|
9
9
|
* once with proId) and provides validation functions for deposit amounts, output limits,
|
|
10
10
|
* and service fee rates.
|
|
11
11
|
*/
|
|
12
|
-
export function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, maxDepositUsd, }) {
|
|
12
|
+
export function PlatformHealthProvider({ children, onFormDisabledChange, onTrackingDisabledChange, maxDepositUsd, maintenanceMode, }) {
|
|
13
13
|
// Consume status data from parent SilentSwapContext instead of calling useStatus again
|
|
14
14
|
const { status } = useSilentSwap();
|
|
15
15
|
const { platformHealth: statusPlatformHealth, maximumDepositUusdc, minimumDepositUusdc, outputLimit, serviceFeeRate, overheadUsd, identity, volume, liquidity, storage, } = status;
|
|
16
|
-
// Normalize platform health status
|
|
16
|
+
// Normalize platform health status. A dashboard-driven maintenance override forces
|
|
17
|
+
// the effective status to 'MAINTENANCE' regardless of what the status API reports.
|
|
17
18
|
const platformHealth = useMemo(() => {
|
|
19
|
+
if (maintenanceMode)
|
|
20
|
+
return 'MAINTENANCE';
|
|
18
21
|
if (!statusPlatformHealth)
|
|
19
22
|
return null;
|
|
20
23
|
return statusPlatformHealth;
|
|
21
|
-
}, [statusPlatformHealth]);
|
|
24
|
+
}, [statusPlatformHealth, maintenanceMode]);
|
|
22
25
|
// Track disabled states locally for context value
|
|
23
26
|
const [formDisabled, setFormDisabled] = React.useState(false);
|
|
24
27
|
const [trackingDisabled, setTrackingDisabled] = React.useState(false);
|