@silentswap/react 0.0.91 → 0.0.92
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/SilentSwapContext.d.ts +3 -1
- package/dist/contexts/SilentSwapContext.js +4 -3
- package/dist/hooks/silent/solana-transaction.js +128 -65
- package/dist/hooks/silent/tron-transaction.d.ts +43 -0
- package/dist/hooks/silent/tron-transaction.js +40 -0
- package/dist/hooks/silent/useQuoteCalculation.d.ts +3 -1
- package/dist/hooks/silent/useQuoteCalculation.js +6 -4
- package/dist/hooks/silent/useSilentQuote.d.ts +3 -1
- package/dist/hooks/silent/useSilentQuote.js +2 -1
- package/dist/hooks/useQuote.js +14 -3
- package/dist/hooks/useTransaction.js +8 -5
- package/dist/isTronAssetCaip19.d.ts +1 -0
- package/dist/isTronAssetCaip19.js +3 -0
- package/package.json +3 -3
|
@@ -65,7 +65,7 @@ export interface SilentSwapContextType {
|
|
|
65
65
|
solanaRpcUrl?: string;
|
|
66
66
|
}
|
|
67
67
|
export declare function useSilentSwap(): SilentSwapContextType;
|
|
68
|
-
export declare function SilentSwapProvider({ children, client, evmAddress, solAddress, connector, isConnected, solanaConnector, solanaConnection, bitcoinConnector, bitcoinConnection, environment, baseUrl, solanaRpcUrl, walletClient, bitcoinAddress, bitcoinRpcUrl, proId, requestWalletConnect, }: {
|
|
68
|
+
export declare function SilentSwapProvider({ children, client, evmAddress, solAddress, connector, isConnected, solanaConnector, solanaConnection, bitcoinConnector, bitcoinConnection, environment, baseUrl, solanaRpcUrl, walletClient, bitcoinAddress, bitcoinRpcUrl, proId, requestWalletConnect, forceBridgeProvider, }: {
|
|
69
69
|
children: React.ReactNode;
|
|
70
70
|
client: SilentSwapClient;
|
|
71
71
|
evmAddress?: string;
|
|
@@ -86,4 +86,6 @@ export declare function SilentSwapProvider({ children, client, evmAddress, solAd
|
|
|
86
86
|
proId?: string;
|
|
87
87
|
/** Optional: request wallet connection when walletClient is missing (e.g. user switched account on mobile). */
|
|
88
88
|
requestWalletConnect?: () => Promise<void>;
|
|
89
|
+
/** Optional: force a single bridge provider for testing. */
|
|
90
|
+
forceBridgeProvider?: 'relay' | 'debridge';
|
|
89
91
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -80,7 +80,7 @@ export function useSilentSwap() {
|
|
|
80
80
|
}
|
|
81
81
|
return context;
|
|
82
82
|
}
|
|
83
|
-
function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bitcoinAddress, solanaConnector, solanaConnection, bitcoinConnector, bitcoinConnection, environment, config, solanaRpcUrl, connector, isConnected = false, walletClient, proId, requestWalletConnect, }) {
|
|
83
|
+
function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bitcoinAddress, solanaConnector, solanaConnection, bitcoinConnector, bitcoinConnection, environment, config, solanaRpcUrl, connector, isConnected = false, walletClient, proId, requestWalletConnect, forceBridgeProvider, }) {
|
|
84
84
|
// Authentication hook - only for EVM
|
|
85
85
|
const { auth, isLoading: authLoading } = useAuth({
|
|
86
86
|
client,
|
|
@@ -149,6 +149,7 @@ function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bit
|
|
|
149
149
|
bitcoinConnection,
|
|
150
150
|
getPrice,
|
|
151
151
|
proId,
|
|
152
|
+
forceBridgeProvider,
|
|
152
153
|
});
|
|
153
154
|
const effectiveDepositAmountUsd = useMemo(() => {
|
|
154
155
|
return depositAmountUsdFromEstimates > 0 ? depositAmountUsdFromEstimates : depositAmountUsdc;
|
|
@@ -257,7 +258,7 @@ function SilentSwapInnerProvider({ children, client, evmAddress, solAddress, bit
|
|
|
257
258
|
solanaRpcUrl,
|
|
258
259
|
}, children: children });
|
|
259
260
|
}
|
|
260
|
-
export function SilentSwapProvider({ children, client, evmAddress, solAddress, connector, isConnected, solanaConnector, solanaConnection, bitcoinConnector, bitcoinConnection, environment = ENVIRONMENT.STAGING, baseUrl, solanaRpcUrl, walletClient, bitcoinAddress, bitcoinRpcUrl, proId, requestWalletConnect, }) {
|
|
261
|
+
export function SilentSwapProvider({ children, client, evmAddress, solAddress, connector, isConnected, solanaConnector, solanaConnection, bitcoinConnector, bitcoinConnection, environment = ENVIRONMENT.STAGING, baseUrl, solanaRpcUrl, walletClient, bitcoinAddress, bitcoinRpcUrl, proId, requestWalletConnect, forceBridgeProvider, }) {
|
|
261
262
|
const config = useMemo(() => {
|
|
262
263
|
const computedBaseUrl = baseUrl ?? ENVIRONMENT_CONFIGS[environment].baseUrl;
|
|
263
264
|
console.log('[SilentSwapProvider] Creating config:', { environment, baseUrl, computedBaseUrl });
|
|
@@ -266,5 +267,5 @@ export function SilentSwapProvider({ children, client, evmAddress, solAddress, c
|
|
|
266
267
|
baseUrl: computedBaseUrl,
|
|
267
268
|
};
|
|
268
269
|
}, [environment, baseUrl]);
|
|
269
|
-
return (_jsx(AssetsProvider, { children: _jsx(PricesProvider, { children: _jsx(BalancesProvider, { evmAddress: evmAddress, solAddress: solAddress, solanaRpcUrl: solanaRpcUrl, bitcoinAddress: bitcoinAddress, bitcoinRpcUrl: bitcoinRpcUrl, children: _jsx(OrdersProvider, { baseUrl: config.baseUrl, children: _jsx(SilentSwapInnerProvider, { client: client, connector: connector, isConnected: isConnected, evmAddress: evmAddress, solAddress: solAddress, bitcoinAddress: bitcoinAddress, solanaConnector: solanaConnector, solanaConnection: solanaConnection, bitcoinConnector: bitcoinConnector, bitcoinConnection: bitcoinConnection, environment: environment, config: config, solanaRpcUrl: solanaRpcUrl, walletClient: walletClient, proId: proId, requestWalletConnect: requestWalletConnect, children: children }) }) }) }) }));
|
|
270
|
+
return (_jsx(AssetsProvider, { children: _jsx(PricesProvider, { children: _jsx(BalancesProvider, { evmAddress: evmAddress, solAddress: solAddress, solanaRpcUrl: solanaRpcUrl, bitcoinAddress: bitcoinAddress, bitcoinRpcUrl: bitcoinRpcUrl, children: _jsx(OrdersProvider, { baseUrl: config.baseUrl, children: _jsx(SilentSwapInnerProvider, { client: client, connector: connector, isConnected: isConnected, evmAddress: evmAddress, solAddress: solAddress, bitcoinAddress: bitcoinAddress, solanaConnector: solanaConnector, solanaConnection: solanaConnection, bitcoinConnector: bitcoinConnector, bitcoinConnection: bitcoinConnection, environment: environment, config: config, solanaRpcUrl: solanaRpcUrl, walletClient: walletClient, proId: proId, requestWalletConnect: requestWalletConnect, forceBridgeProvider: forceBridgeProvider, children: children }) }) }) }) }));
|
|
270
271
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { address, appendTransactionMessageInstructions, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, compileTransaction, getBase64EncodedWireTransaction,
|
|
1
|
+
import { address, appendTransactionMessageInstructions, createTransactionMessage, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, compileTransaction, getBase64EncodedWireTransaction, pipe, AccountRole, } from '@solana/kit';
|
|
2
2
|
import { createSolanaRpc } from '@solana/rpc';
|
|
3
3
|
import { VersionedTransaction } from '@solana/web3.js';
|
|
4
4
|
/**
|
|
@@ -25,30 +25,54 @@ export function createSolanaTransactionExecutor(connector, connection) {
|
|
|
25
25
|
});
|
|
26
26
|
// Get RPC client from connection or create a default one
|
|
27
27
|
const rpc = connection.rpc || createSolanaRpc('https://api.mainnet-beta.solana.com');
|
|
28
|
+
const rpcEndpoint = connection.connection?.rpcEndpoint ||
|
|
29
|
+
connection.connection?._rpcEndpoint ||
|
|
30
|
+
'https://api.mainnet-beta.solana.com';
|
|
31
|
+
console.log('[SolanaTx] Execution context:', {
|
|
32
|
+
chainId: tx.chainId,
|
|
33
|
+
hasAdapterConnection: !!connection.connection,
|
|
34
|
+
rpcEndpoint,
|
|
35
|
+
});
|
|
28
36
|
let transactionMessage;
|
|
37
|
+
let versionedTransaction;
|
|
29
38
|
let blockhash;
|
|
30
39
|
let lastValidBlockHeight;
|
|
40
|
+
const sendSignedViaRpc = async (txToSignAndSend) => {
|
|
41
|
+
console.log('Requesting signature...');
|
|
42
|
+
const signedTransaction = await connector.signTransaction(txToSignAndSend);
|
|
43
|
+
console.log('Transaction signed');
|
|
44
|
+
const signedTransactionBytes = signedTransaction.serialize();
|
|
45
|
+
const signedTransactionBase64 = Buffer.from(signedTransactionBytes).toString('base64');
|
|
46
|
+
console.log('Sending transaction via RPC...');
|
|
47
|
+
const sig = await rpc
|
|
48
|
+
.sendTransaction(signedTransactionBase64, {
|
|
49
|
+
encoding: 'base64',
|
|
50
|
+
skipPreflight: true,
|
|
51
|
+
preflightCommitment: 'confirmed',
|
|
52
|
+
})
|
|
53
|
+
.send();
|
|
54
|
+
console.log('Transaction sent via RPC:', sig);
|
|
55
|
+
return sig;
|
|
56
|
+
};
|
|
31
57
|
// Check if transaction has serialized data (from deBridge)
|
|
32
58
|
// deBridge returns Solana transactions as serialized hex strings in tx.data
|
|
33
59
|
if (tx.data && !tx.instructions && !tx.to) {
|
|
34
|
-
//
|
|
35
|
-
//
|
|
60
|
+
// deBridge returns a serialized v0 transaction (often with Address Lookup Tables).
|
|
61
|
+
// Do NOT decompile here: decompilation requires ALT contents and fails for unknown tables.
|
|
36
62
|
const hexData = tx.data.replace(/^0x/, '');
|
|
37
63
|
const buffer = Buffer.from(hexData, 'hex');
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
lastValidBlockHeight = blockhashResponse.value.lastValidBlockHeight;
|
|
51
|
-
}
|
|
64
|
+
versionedTransaction = VersionedTransaction.deserialize(buffer);
|
|
65
|
+
blockhash = versionedTransaction.message.recentBlockhash;
|
|
66
|
+
console.log('[SolanaTx] Using serialized deBridge tx:', {
|
|
67
|
+
dataBytes: buffer.length,
|
|
68
|
+
recentBlockhash: blockhash,
|
|
69
|
+
signaturesCount: versionedTransaction.signatures.length,
|
|
70
|
+
staticAccounts: versionedTransaction.message.staticAccountKeys.length,
|
|
71
|
+
addressTableLookups: versionedTransaction.message.addressTableLookups.length,
|
|
72
|
+
});
|
|
73
|
+
// Fetch latest lastValidBlockHeight for confirmation flow.
|
|
74
|
+
const blockhashResponse = await rpc.getLatestBlockhash({ commitment: 'finalized' }).send();
|
|
75
|
+
lastValidBlockHeight = blockhashResponse.value.lastValidBlockHeight;
|
|
52
76
|
}
|
|
53
77
|
else if (tx.instructions) {
|
|
54
78
|
// Transaction has instructions (from relay.link)
|
|
@@ -152,56 +176,95 @@ export function createSolanaTransactionExecutor(connector, connection) {
|
|
|
152
176
|
else {
|
|
153
177
|
throw new Error('Solana transaction must have either instructions or serialized data');
|
|
154
178
|
}
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
179
|
+
// Build VersionedTransaction from relay instructions path.
|
|
180
|
+
if (!versionedTransaction) {
|
|
181
|
+
if (!transactionMessage) {
|
|
182
|
+
throw new Error('Failed to build Solana transaction message');
|
|
183
|
+
}
|
|
184
|
+
console.log('Compiling transaction...');
|
|
185
|
+
const compiledTransaction = compileTransaction(transactionMessage);
|
|
186
|
+
const base64WireTransaction = getBase64EncodedWireTransaction(compiledTransaction);
|
|
187
|
+
const transactionBytes = Buffer.from(base64WireTransaction, 'base64');
|
|
188
|
+
console.log('Transaction bytes length:', transactionBytes.length);
|
|
189
|
+
versionedTransaction = VersionedTransaction.deserialize(transactionBytes);
|
|
190
|
+
console.log('[SolanaTx] Built relay v0 tx:', {
|
|
191
|
+
recentBlockhash: versionedTransaction.message.recentBlockhash,
|
|
192
|
+
signaturesCount: versionedTransaction.signatures.length,
|
|
193
|
+
staticAccounts: versionedTransaction.message.staticAccountKeys.length,
|
|
194
|
+
addressTableLookups: versionedTransaction.message.addressTableLookups.length,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
let signatureString;
|
|
198
|
+
// Prefer wallet-adapter broadcast path (critical for wallets like MetaMask Solana).
|
|
199
|
+
if (connection.connection) {
|
|
200
|
+
try {
|
|
201
|
+
console.log('Sending transaction via wallet adapter...');
|
|
202
|
+
signatureString = await connector.sendTransaction(versionedTransaction, connection.connection);
|
|
203
|
+
console.log('Transaction sent via wallet adapter:', signatureString);
|
|
204
|
+
// MetaMask Solana can sometimes return a signature but not propagate/broadcast.
|
|
205
|
+
// If the signature remains unknown briefly, re-broadcast via signed raw transaction.
|
|
206
|
+
let seenByRpc = false;
|
|
207
|
+
for (let i = 0; i < 3; i++) {
|
|
208
|
+
const statusResp = await rpc
|
|
209
|
+
.getSignatureStatuses([signatureString], { searchTransactionHistory: true })
|
|
210
|
+
.send();
|
|
211
|
+
const status = statusResp.value?.[0];
|
|
212
|
+
console.log('[SolanaTx] Post-adapter visibility check:', { attempt: i + 1, status: status ?? null });
|
|
213
|
+
if (status) {
|
|
214
|
+
seenByRpc = true;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
218
|
+
}
|
|
219
|
+
if (!seenByRpc) {
|
|
220
|
+
console.warn('[SolanaTx] Adapter returned signature not found on RPC. Re-broadcasting via signed RPC path.');
|
|
221
|
+
signatureString = await sendSignedViaRpc(versionedTransaction);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (adapterSendError) {
|
|
225
|
+
console.warn('Wallet adapter sendTransaction failed, falling back to sign+RPC send:', adapterSendError);
|
|
226
|
+
signatureString = await sendSignedViaRpc(versionedTransaction);
|
|
227
|
+
}
|
|
195
228
|
}
|
|
196
229
|
else {
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
|
|
230
|
+
// Fallback path when adapter connection is unavailable.
|
|
231
|
+
signatureString = await sendSignedViaRpc(versionedTransaction);
|
|
232
|
+
}
|
|
233
|
+
// Immediate visibility check: if null for long time, tx likely not propagated to this RPC yet.
|
|
234
|
+
try {
|
|
235
|
+
const immediateStatus = await rpc
|
|
236
|
+
.getSignatureStatuses([signatureString], { searchTransactionHistory: true })
|
|
237
|
+
.send();
|
|
238
|
+
console.log('[SolanaTx] Immediate signature status:', immediateStatus.value?.[0] ?? null);
|
|
239
|
+
}
|
|
240
|
+
catch (statusErr) {
|
|
241
|
+
console.warn('[SolanaTx] Immediate signature status check failed:', statusErr);
|
|
242
|
+
}
|
|
243
|
+
// Wait for confirmation by polling signature status from RPC.
|
|
244
|
+
// This avoids false positives from single-shot checks.
|
|
245
|
+
console.log('Waiting for confirmation...');
|
|
246
|
+
const confirmationDeadline = Date.now() + 90_000;
|
|
247
|
+
let result = { value: { err: 'timeout' } };
|
|
248
|
+
let pollAttempt = 0;
|
|
249
|
+
while (Date.now() < confirmationDeadline) {
|
|
250
|
+
pollAttempt += 1;
|
|
251
|
+
const statusResp = await rpc
|
|
252
|
+
.getSignatureStatuses([signatureString], { searchTransactionHistory: true })
|
|
253
|
+
.send();
|
|
254
|
+
const status = statusResp.value?.[0];
|
|
255
|
+
console.log('[SolanaTx] Confirmation poll:', {
|
|
256
|
+
attempt: pollAttempt,
|
|
257
|
+
status: status ?? null,
|
|
258
|
+
});
|
|
259
|
+
if (status?.err) {
|
|
260
|
+
result = { value: { err: status.err } };
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
if (status?.confirmationStatus === 'confirmed' || status?.confirmationStatus === 'finalized') {
|
|
264
|
+
result = { value: { err: null } };
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
205
268
|
}
|
|
206
269
|
// Check for errors
|
|
207
270
|
if (result.value.err) {
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { BridgeTransaction } from '@silentswap/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Tron wallet connector interface
|
|
4
|
+
* Compatible with Tron wallet adapters (e.g., TronLink, etc.)
|
|
5
|
+
* Tron mainnet is EVM-compatible; relay may return EVM-style tx (to, value, data).
|
|
6
|
+
*/
|
|
7
|
+
export interface TronWalletConnector {
|
|
8
|
+
/** Send a transaction (EVM-style: to, value, data) and return tx hash */
|
|
9
|
+
sendTransaction: (tx: BridgeTransaction) => Promise<string>;
|
|
10
|
+
getAccounts: () => Promise<string[]>;
|
|
11
|
+
currentAccount?: string | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Tron connection interface
|
|
15
|
+
* Kept for consistency with Solana/Bitcoin pattern; may not be used.
|
|
16
|
+
*/
|
|
17
|
+
export interface TronConnection {
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Tron transaction executor type
|
|
21
|
+
* Similar to BitcoinTransactionExecutor but for Tron (EVM-style or native).
|
|
22
|
+
*/
|
|
23
|
+
export type TronTransactionExecutor = (tx: BridgeTransaction) => Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Create a Tron transaction executor.
|
|
26
|
+
* Handles Tron transactions from relay.link bridge quotes (EVM-style to/value/data).
|
|
27
|
+
*
|
|
28
|
+
* @param connector - Tron wallet connector
|
|
29
|
+
* @param _connection - Tron connection (optional, for consistency)
|
|
30
|
+
* @returns Tron transaction executor function
|
|
31
|
+
*/
|
|
32
|
+
export declare function createTronTransactionExecutor(connector: TronWalletConnector, _connection?: TronConnection): TronTransactionExecutor;
|
|
33
|
+
/**
|
|
34
|
+
* Helper to convert relay.link Tron step data to BridgeTransaction.
|
|
35
|
+
* Relay may return EVM-style fields (chainId, to, value, data) for Tron.
|
|
36
|
+
*/
|
|
37
|
+
export declare function convertRelayTronStepToTransaction(stepData: {
|
|
38
|
+
chainId?: number;
|
|
39
|
+
to?: string;
|
|
40
|
+
value?: string;
|
|
41
|
+
data?: string;
|
|
42
|
+
gas?: string;
|
|
43
|
+
}, chainId?: number): BridgeTransaction;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { N_RELAY_CHAIN_ID_TRON } from '@silentswap/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Create a Tron transaction executor.
|
|
4
|
+
* Handles Tron transactions from relay.link bridge quotes (EVM-style to/value/data).
|
|
5
|
+
*
|
|
6
|
+
* @param connector - Tron wallet connector
|
|
7
|
+
* @param _connection - Tron connection (optional, for consistency)
|
|
8
|
+
* @returns Tron transaction executor function
|
|
9
|
+
*/
|
|
10
|
+
export function createTronTransactionExecutor(connector, _connection) {
|
|
11
|
+
return async (tx) => {
|
|
12
|
+
if (!connector.currentAccount) {
|
|
13
|
+
const accounts = await connector.getAccounts();
|
|
14
|
+
if (!accounts || accounts.length === 0) {
|
|
15
|
+
throw new Error('Tron wallet not connected');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const txHash = await connector.sendTransaction(tx);
|
|
19
|
+
if (!txHash || typeof txHash !== 'string' || txHash.trim().length === 0) {
|
|
20
|
+
throw new Error('Tron transaction was not broadcast successfully. The wallet returned an empty transaction ID.');
|
|
21
|
+
}
|
|
22
|
+
return txHash;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Helper to convert relay.link Tron step data to BridgeTransaction.
|
|
27
|
+
* Relay may return EVM-style fields (chainId, to, value, data) for Tron.
|
|
28
|
+
*/
|
|
29
|
+
export function convertRelayTronStepToTransaction(stepData, chainId = N_RELAY_CHAIN_ID_TRON) {
|
|
30
|
+
if (!stepData.to || stepData.data === undefined) {
|
|
31
|
+
throw new Error('Tron transaction step must have to and data fields');
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
chainId,
|
|
35
|
+
to: stepData.to,
|
|
36
|
+
value: stepData.value ?? '0',
|
|
37
|
+
data: stepData.data,
|
|
38
|
+
gasLimit: stepData.gas,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -32,6 +32,8 @@ export interface UseQuoteCalculationOptions {
|
|
|
32
32
|
setDestinations: (updater: Destination[] | ((prev: Destination[]) => Destination[])) => void;
|
|
33
33
|
/** Pro user ID for volume tracking (sent with quote request) */
|
|
34
34
|
proId?: string;
|
|
35
|
+
/** Optional: force a single bridge provider for testing. */
|
|
36
|
+
forceBridgeProvider?: 'relay' | 'debridge';
|
|
35
37
|
}
|
|
36
38
|
export interface UseQuoteCalculationReturn {
|
|
37
39
|
/** Calculate quote and return result */
|
|
@@ -51,4 +53,4 @@ export interface UseQuoteCalculationReturn {
|
|
|
51
53
|
* - Quote request construction and fetching
|
|
52
54
|
* - Destination amount updates
|
|
53
55
|
*/
|
|
54
|
-
export declare function useQuoteCalculation({ address, evmAddress, wallet, depositorAddress, getQuote, getPrice, setDestinations, proId, }: UseQuoteCalculationOptions): UseQuoteCalculationReturn;
|
|
56
|
+
export declare function useQuoteCalculation({ address, evmAddress, wallet, depositorAddress, getQuote, getPrice, setDestinations, proId, forceBridgeProvider, }: UseQuoteCalculationOptions): UseQuoteCalculationReturn;
|
|
@@ -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, }) {
|
|
16
|
+
export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddress, getQuote, getPrice, setDestinations, proId, 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) => {
|
|
@@ -87,7 +87,7 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
87
87
|
decimals: assetInfo.decimals,
|
|
88
88
|
precision: assetInfo.precision,
|
|
89
89
|
});
|
|
90
|
-
const solveResult = await solveOptimalUsdcAmount(N_RELAY_CHAIN_ID_SOLANA, originCurrency, sourceAmountInUnitsForQuote, solanaAddress, undefined, X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress));
|
|
90
|
+
const solveResult = await solveOptimalUsdcAmount(N_RELAY_CHAIN_ID_SOLANA, originCurrency, sourceAmountInUnitsForQuote, solanaAddress, undefined, X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress), forceBridgeProvider);
|
|
91
91
|
if (abortController.signal.aborted) {
|
|
92
92
|
setLoadingAmounts(false);
|
|
93
93
|
return null;
|
|
@@ -121,7 +121,8 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
121
121
|
// to stay within the source balance (matches Svelte's relay_solve_uusdc_amount)
|
|
122
122
|
const solveResult = await solveOptimalUsdcAmount(N_RELAY_CHAIN_ID_BITCOIN, SBTC_ADDR_BITCOIN_NATIVE, sourceAmountInUnitsForQuote, bitcoinAddress, // Bitcoin address for relay 'user' parameter
|
|
123
123
|
undefined, // depositCalldata - will use phony
|
|
124
|
-
X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress)
|
|
124
|
+
X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress), // EVM address for deposit calldata & recipient
|
|
125
|
+
forceBridgeProvider);
|
|
125
126
|
if (abortController.signal.aborted) {
|
|
126
127
|
setLoadingAmounts(false);
|
|
127
128
|
return null;
|
|
@@ -143,7 +144,8 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
143
144
|
const sourceAmountBN = BigNumber(debouncedSourceAmount);
|
|
144
145
|
const sourceAmountInUnits = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
145
146
|
const solveResult = await solveOptimalUsdcAmount(srcChainId, srcToken, sourceAmountInUnits, address, undefined, // depositCalldata
|
|
146
|
-
X_MAX_IMPACT_PERCENT, depositorAddress
|
|
147
|
+
X_MAX_IMPACT_PERCENT, depositorAddress, // Required depositor address
|
|
148
|
+
undefined, forceBridgeProvider);
|
|
147
149
|
if (abortController.signal.aborted) {
|
|
148
150
|
setLoadingAmounts(false);
|
|
149
151
|
return null;
|
|
@@ -64,6 +64,8 @@ export interface useSilentQuoteOptions {
|
|
|
64
64
|
setDestinations: (updater: Destination[] | ((prev: Destination[]) => Destination[])) => void;
|
|
65
65
|
/** Pro user ID for volume tracking (sent with quote request, matching Svelte's AppState.proId) */
|
|
66
66
|
proId?: string;
|
|
67
|
+
/** Optional: force a single bridge provider for testing. */
|
|
68
|
+
forceBridgeProvider?: 'relay' | 'debridge';
|
|
67
69
|
}
|
|
68
70
|
/**
|
|
69
71
|
* Return type for useSilentQuote hook
|
|
@@ -99,4 +101,4 @@ export interface ExecuteSwapParams {
|
|
|
99
101
|
/** Optional integrator ID for tracking */
|
|
100
102
|
integratorId?: string;
|
|
101
103
|
}
|
|
102
|
-
export declare function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading, walletError, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, proId, }: useSilentQuoteOptions): useSilentQuoteReturn;
|
|
104
|
+
export declare function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading, walletError, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, proId, forceBridgeProvider, }: useSilentQuoteOptions): useSilentQuoteReturn;
|
|
@@ -6,7 +6,7 @@ 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, wallet, walletLoading = false, walletError = null, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, proId, }) {
|
|
9
|
+
export function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading = false, walletError = null, generateWallet, requestWalletConnect, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, proId, forceBridgeProvider, }) {
|
|
10
10
|
const [isLoading, setIsLoading] = useState(false);
|
|
11
11
|
const [currentStep, setCurrentStep] = useState('');
|
|
12
12
|
const [quote, setQuote] = useState(null);
|
|
@@ -86,6 +86,7 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
86
86
|
getPrice,
|
|
87
87
|
setDestinations,
|
|
88
88
|
proId,
|
|
89
|
+
forceBridgeProvider,
|
|
89
90
|
});
|
|
90
91
|
/**
|
|
91
92
|
* Execute the complete swap flow
|
package/dist/hooks/useQuote.js
CHANGED
|
@@ -320,9 +320,9 @@ export function useQuote({ address, maxImpactPercent = X_MAX_IMPACT_PERCENT, for
|
|
|
320
320
|
if (direction === 'egress') {
|
|
321
321
|
return null; // Skip DeBridge for egress, will use Relay.link only
|
|
322
322
|
}
|
|
323
|
-
// Skip DeBridge for
|
|
324
|
-
if (
|
|
325
|
-
return null; // Skip DeBridge for
|
|
323
|
+
// Skip DeBridge for Bitcoin only
|
|
324
|
+
if (isBitcoinAsset(assetCaip19)) {
|
|
325
|
+
return null; // Skip DeBridge for Bitcoin, will use Relay.link only
|
|
326
326
|
}
|
|
327
327
|
// For reverse calculation ingress: use srcChainTokenInAmount: 'auto' and specify dstChainTokenOutAmount
|
|
328
328
|
const debridgeParams = {
|
|
@@ -330,6 +330,8 @@ export function useQuote({ address, maxImpactPercent = X_MAX_IMPACT_PERCENT, for
|
|
|
330
330
|
srcChainTokenIn: tokenAddress === ZERO_ADDRESS ? ZERO_ADDRESS : tokenAddress,
|
|
331
331
|
dstChainId: NI_CHAIN_ID_AVALANCHE,
|
|
332
332
|
dstChainTokenOut: S0X_ADDR_USDC_AVALANCHE,
|
|
333
|
+
prependOperatingExpenses: true,
|
|
334
|
+
additionalTakerRewardBps: 0,
|
|
333
335
|
};
|
|
334
336
|
if (isReverseCalculation && direction === 'ingress' && targetAmount) {
|
|
335
337
|
// For reverse ingress: specify destination amount, let DeBridge calculate source
|
|
@@ -349,6 +351,15 @@ export function useQuote({ address, maxImpactPercent = X_MAX_IMPACT_PERCENT, for
|
|
|
349
351
|
debridgeParams.srcChainTokenInAmount = tokenAmount;
|
|
350
352
|
debridgeParams.dstChainTokenOutAmount = 'auto';
|
|
351
353
|
}
|
|
354
|
+
// Solana source requires Solana-format authority fields and estimate disabled.
|
|
355
|
+
if (isSolanaChain) {
|
|
356
|
+
debridgeParams.enableEstimate = false;
|
|
357
|
+
debridgeParams.account = normalizedAddress;
|
|
358
|
+
debridgeParams.srcChainOrderAuthorityAddress = normalizedAddress;
|
|
359
|
+
debridgeParams.srcChainRefundAddress = normalizedAddress;
|
|
360
|
+
debridgeParams.dstChainTokenOutRecipient = EVM_PHONY_ADDRESS;
|
|
361
|
+
debridgeParams.dstChainOrderAuthorityAddress = EVM_PHONY_ADDRESS;
|
|
362
|
+
}
|
|
352
363
|
const quote = await fetchDebridgeOrder(debridgeParams, signal);
|
|
353
364
|
return quote;
|
|
354
365
|
}
|
|
@@ -3,6 +3,7 @@ import { erc20Abi } from 'viem';
|
|
|
3
3
|
import { executeRelayBridge, executeDebridgeBridge, getBridgeStatus, createTransactionExecutor, createChainSwitcher, ensureChain, waitForTransactionConfirmation, parseTransactionRequestForViem, createPublicClientWithRpc, getChainById, } from '@silentswap/sdk';
|
|
4
4
|
import { createSolanaTransactionExecutor } from './silent/solana-transaction.js';
|
|
5
5
|
import { createBitcoinTransactionExecutor, convertRelayBitcoinStepToTransaction } from './silent/bitcoin-transaction.js';
|
|
6
|
+
import { N_DEBRIDGE_CHAIN_ID_SOLANA } from '@silentswap/sdk';
|
|
6
7
|
import { N_RELAY_CHAIN_ID_BITCOIN } from '@silentswap/sdk';
|
|
7
8
|
/**
|
|
8
9
|
* React hook for executing transactions
|
|
@@ -105,8 +106,8 @@ export function useTransaction({ walletClient, connector, solanaConnector, solan
|
|
|
105
106
|
return false;
|
|
106
107
|
});
|
|
107
108
|
const hasBitcoinTransactions = hasBitcoinInTxs || hasBitcoinInRoute;
|
|
108
|
-
// Check if quote contains Solana transactions
|
|
109
|
-
const hasSolanaTransactions = quote.txs.some((tx) => tx.instructions !== undefined);
|
|
109
|
+
// Check if quote contains Solana transactions (relay instructions or deBridge serialized tx)
|
|
110
|
+
const hasSolanaTransactions = quote.txs.some((tx) => tx.instructions !== undefined || tx.chainId === N_DEBRIDGE_CHAIN_ID_SOLANA);
|
|
110
111
|
if (hasBitcoinTransactions) {
|
|
111
112
|
// Bitcoin transactions require Bitcoin connector
|
|
112
113
|
if (!bitcoinConnector) {
|
|
@@ -218,8 +219,10 @@ export function useTransaction({ walletClient, connector, solanaConnector, solan
|
|
|
218
219
|
onStatus?.(step);
|
|
219
220
|
});
|
|
220
221
|
case 'debridge':
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
return await executeDebridgeBridge(quote, executeTx, switchChain, (step) => {
|
|
223
|
+
setCurrentStep(step);
|
|
224
|
+
onStatus?.(step);
|
|
225
|
+
});
|
|
223
226
|
default:
|
|
224
227
|
throw new Error(`Unsupported bridge provider: ${quote.provider}`);
|
|
225
228
|
}
|
|
@@ -421,7 +424,7 @@ export function useTransaction({ walletClient, connector, solanaConnector, solan
|
|
|
421
424
|
catch (err) {
|
|
422
425
|
const error = err instanceof Error ? err : new Error('Failed to get bridge status');
|
|
423
426
|
setError(error);
|
|
424
|
-
|
|
427
|
+
throw error;
|
|
425
428
|
}
|
|
426
429
|
finally {
|
|
427
430
|
setIsLoading(false);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isTronAssetCaip19(caip19: string): boolean;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silentswap/react",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.92",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@bigmi/core": "^0.6.5",
|
|
26
26
|
"@ensdomains/ensjs": "^4.2.0",
|
|
27
|
-
"@silentswap/sdk": "0.0.
|
|
28
|
-
"@silentswap/ui-kit": "0.0.
|
|
27
|
+
"@silentswap/sdk": "0.0.92",
|
|
28
|
+
"@silentswap/ui-kit": "0.0.92",
|
|
29
29
|
"@solana/codecs-strings": "^5.1.0",
|
|
30
30
|
"@solana/kit": "^5.1.0",
|
|
31
31
|
"@solana/rpc": "^5.1.0",
|