@silentswap/react 0.0.89 → 0.0.91
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.
|
@@ -58,6 +58,28 @@ export function createBitcoinTransactionExecutor(connector, _connection) {
|
|
|
58
58
|
// Send signed PSBT (wallet returns base64)
|
|
59
59
|
const txHash = await connector.sendPsbt(signedPsbt);
|
|
60
60
|
console.log('Bitcoin transaction sent:', txHash);
|
|
61
|
+
// Validate broadcast result — some wallets (e.g. Keplr) resolve even
|
|
62
|
+
// when the mempool rejects the tx (e.g. insufficient fee / RBF error).
|
|
63
|
+
// Without this check the code would continue to bridge monitoring and
|
|
64
|
+
// show "Waiting for bridge" indefinitely.
|
|
65
|
+
if (!txHash || typeof txHash !== 'string' || txHash.trim().length === 0) {
|
|
66
|
+
throw new Error('Bitcoin transaction was not broadcast successfully. The wallet returned an empty transaction ID. Please try again.');
|
|
67
|
+
}
|
|
68
|
+
// Brief delay then verify the transaction is actually in the mempool
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
70
|
+
try {
|
|
71
|
+
const res = await fetch(`https://mempool.space/api/tx/${txHash}`);
|
|
72
|
+
if (!res.ok) {
|
|
73
|
+
throw new Error('not found');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Transaction not found — likely rejected by the mempool
|
|
78
|
+
// (e.g. RBF feerate too low, dust output, etc.)
|
|
79
|
+
throw new Error(`Bitcoin transaction ${txHash} was not accepted by the network. ` +
|
|
80
|
+
'This usually means the fee rate is too low or there is a conflicting unconfirmed transaction. ' +
|
|
81
|
+
'Please wait for the previous transaction to confirm and try again.');
|
|
82
|
+
}
|
|
61
83
|
return txHash;
|
|
62
84
|
}
|
|
63
85
|
catch (error) {
|
|
@@ -241,17 +241,22 @@ export function useBridgeExecution(walletClient, connector, solanaConnector, sol
|
|
|
241
241
|
}
|
|
242
242
|
// Get relay origin asset parameters
|
|
243
243
|
const { originChainId, originCurrency } = getRelayOriginAssetFromCaip19(sourceAsset);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
console.log('[SilentSwap:SolanaBridge] Start', {
|
|
245
|
+
sourceAsset,
|
|
246
|
+
sourceAmount,
|
|
247
|
+
usdcAmount,
|
|
248
|
+
solanaSenderAddress,
|
|
249
|
+
evmSignerAddress,
|
|
250
|
+
originChainId,
|
|
251
|
+
originCurrency,
|
|
252
|
+
depositorAddress,
|
|
253
|
+
hasDepositParams: !!depositParams,
|
|
254
|
+
});
|
|
248
255
|
if (!usdcAmount) {
|
|
249
256
|
throw new Error('USDC amount is required for Solana bridge execution. ' +
|
|
250
257
|
'It should be provided from the initial solveOptimalUsdcAmount call in handleGetQuote. ' +
|
|
251
258
|
'This matches Svelte behavior where solve_uusdc_amount is called once before order creation.');
|
|
252
259
|
}
|
|
253
|
-
// Use the provided usdcAmount directly (matches Svelte behavior)
|
|
254
|
-
// In Svelte: zg_amount_src_usdc is used directly without re-solving
|
|
255
260
|
const bridgeUsdcAmount = usdcAmount;
|
|
256
261
|
setCurrentStep('Fetching bridge quote');
|
|
257
262
|
onStatus?.('Fetching bridge quote');
|
|
@@ -292,35 +297,56 @@ export function useBridgeExecution(walletClient, connector, solanaConnector, sol
|
|
|
292
297
|
console.warn('DepositParams not provided, using phony calldata for bridge quote');
|
|
293
298
|
depositCalldataForExecution = createPhonyDepositCalldata(evmSignerAddress);
|
|
294
299
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
recipient: depositorAddress, // EVM depositor address (matches Svelte line 1308: recipient: S0X_ADDR_DEPOSITOR)
|
|
306
|
-
tradeType: 'EXACT_OUTPUT', // CRITICAL: Must use EXACT_OUTPUT for execution (matches Svelte line 1309)
|
|
307
|
-
txsGasLimit: 600_000, // Matches Svelte line 1310
|
|
300
|
+
const relayQuoteRequest = {
|
|
301
|
+
user: solanaSenderAddress,
|
|
302
|
+
originChainId,
|
|
303
|
+
originCurrency,
|
|
304
|
+
destinationChainId: NI_CHAIN_ID_AVALANCHE,
|
|
305
|
+
destinationCurrency: S0X_ADDR_USDC_AVALANCHE,
|
|
306
|
+
amount: bridgeUsdcAmount,
|
|
307
|
+
recipient: depositorAddress,
|
|
308
|
+
tradeType: 'EXACT_OUTPUT',
|
|
309
|
+
txsGasLimit: 600_000,
|
|
308
310
|
txs: [
|
|
309
311
|
{
|
|
310
|
-
to: S0X_ADDR_USDC_AVALANCHE,
|
|
311
|
-
value: '0',
|
|
312
|
-
data: approveUsdcCalldata,
|
|
312
|
+
to: S0X_ADDR_USDC_AVALANCHE,
|
|
313
|
+
value: '0',
|
|
314
|
+
data: approveUsdcCalldata,
|
|
313
315
|
},
|
|
314
316
|
{
|
|
315
|
-
to: depositorAddress,
|
|
316
|
-
value: '0',
|
|
317
|
-
data: depositCalldataForExecution,
|
|
317
|
+
to: depositorAddress,
|
|
318
|
+
value: '0',
|
|
319
|
+
data: depositCalldataForExecution,
|
|
318
320
|
},
|
|
319
321
|
],
|
|
322
|
+
};
|
|
323
|
+
console.log('[SilentSwap:SolanaBridge] Relay quote request (EXACT_OUTPUT)', {
|
|
324
|
+
user: relayQuoteRequest.user,
|
|
325
|
+
originChainId: relayQuoteRequest.originChainId,
|
|
326
|
+
originCurrency: relayQuoteRequest.originCurrency,
|
|
327
|
+
destinationChainId: relayQuoteRequest.destinationChainId,
|
|
328
|
+
amount: relayQuoteRequest.amount,
|
|
329
|
+
recipient: relayQuoteRequest.recipient,
|
|
330
|
+
tradeType: relayQuoteRequest.tradeType,
|
|
331
|
+
txsCount: relayQuoteRequest.txs.length,
|
|
332
|
+
depositCalldataLength: depositCalldataForExecution.length,
|
|
320
333
|
});
|
|
321
|
-
|
|
334
|
+
const relayQuote = await fetchRelayQuote(relayQuoteRequest);
|
|
335
|
+
console.log('[SilentSwap:SolanaBridge] Relay quote response', {
|
|
336
|
+
currencyIn: relayQuote.details?.currencyIn ? {
|
|
337
|
+
amount: relayQuote.details.currencyIn.amount,
|
|
338
|
+
amountUsd: relayQuote.details.currencyIn.amountUsd,
|
|
339
|
+
} : 'N/A',
|
|
340
|
+
currencyOut: relayQuote.details?.currencyOut ? {
|
|
341
|
+
amount: relayQuote.details.currencyOut.amount,
|
|
342
|
+
amountUsd: relayQuote.details.currencyOut.amountUsd,
|
|
343
|
+
} : 'N/A',
|
|
344
|
+
totalImpact: relayQuote.details?.totalImpact,
|
|
345
|
+
stepsCount: relayQuote.steps?.length,
|
|
346
|
+
stepIds: relayQuote.steps?.map((s) => s.id),
|
|
347
|
+
});
|
|
348
|
+
// Check price impact
|
|
322
349
|
const impactPercent = Number(relayQuote.details.totalImpact.percent);
|
|
323
|
-
// TODO: check negative impact
|
|
324
350
|
if (impactPercent > X_MAX_IMPACT_PERCENT) {
|
|
325
351
|
throw new Error(`Price impact across bridge too high: ${impactPercent.toFixed(2)}%`);
|
|
326
352
|
}
|
|
@@ -337,7 +363,14 @@ export function useBridgeExecution(walletClient, connector, solanaConnector, sol
|
|
|
337
363
|
throw new Error('No steps in relay quote response');
|
|
338
364
|
}
|
|
339
365
|
// Execute each step from relay.link
|
|
340
|
-
for (
|
|
366
|
+
for (let stepIdx = 0; stepIdx < relayQuote.steps.length; stepIdx++) {
|
|
367
|
+
const step = relayQuote.steps[stepIdx];
|
|
368
|
+
console.log(`[SilentSwap:SolanaBridge] Step ${stepIdx + 1}/${relayQuote.steps.length}`, {
|
|
369
|
+
id: step.id,
|
|
370
|
+
kind: step.kind,
|
|
371
|
+
itemsCount: step.items?.length,
|
|
372
|
+
requestId: step.requestId,
|
|
373
|
+
});
|
|
341
374
|
if (step.kind !== 'transaction') {
|
|
342
375
|
throw new Error(`Unsupported relay step kind: ${step.kind}`);
|
|
343
376
|
}
|
|
@@ -348,20 +381,34 @@ export function useBridgeExecution(walletClient, connector, solanaConnector, sol
|
|
|
348
381
|
const itemData = item.data;
|
|
349
382
|
// Solana transaction
|
|
350
383
|
if ('instructions' in itemData) {
|
|
351
|
-
|
|
384
|
+
const stepLabel = step.id === 'approve'
|
|
352
385
|
? 'Requesting approval...'
|
|
353
386
|
: step.id === 'deposit'
|
|
354
387
|
? 'Requesting deposit...'
|
|
355
|
-
: 'Requesting bridge...'
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
388
|
+
: 'Requesting bridge...';
|
|
389
|
+
setCurrentStep(stepLabel);
|
|
390
|
+
onStatus?.(stepLabel);
|
|
391
|
+
console.log(`[SilentSwap:SolanaBridge] Executing Solana tx: ${step.id}`, {
|
|
392
|
+
instructionsCount: itemData.instructions?.length,
|
|
393
|
+
feePayer: solanaSenderAddress,
|
|
394
|
+
});
|
|
361
395
|
// Convert relay step to BridgeTransaction
|
|
362
396
|
const solanaTx = convertRelaySolanaStepToTransaction(itemData, solanaSenderAddress, N_RELAY_CHAIN_ID_SOLANA);
|
|
363
397
|
// Execute Solana transaction
|
|
364
|
-
|
|
398
|
+
try {
|
|
399
|
+
await solanaExecutor(solanaTx);
|
|
400
|
+
console.log(`[SilentSwap:SolanaBridge] Step ${step.id} succeeded`);
|
|
401
|
+
}
|
|
402
|
+
catch (txError) {
|
|
403
|
+
console.error(`[SilentSwap:SolanaBridge] Step ${step.id} FAILED`, {
|
|
404
|
+
error: txError instanceof Error ? txError.message : String(txError),
|
|
405
|
+
stack: txError instanceof Error ? txError.stack : undefined,
|
|
406
|
+
});
|
|
407
|
+
throw txError;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
console.warn(`[SilentSwap:SolanaBridge] Step ${step.id} has no instructions, skipping`);
|
|
365
412
|
}
|
|
366
413
|
}
|
|
367
414
|
// Find request ID for status monitoring
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
-
import { isSolanaAsset, isBitcoinAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, getAssetByCaip19, solveOptimalUsdcAmount,
|
|
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';
|
|
3
3
|
import { getAddress } from 'viem';
|
|
4
4
|
import { BigNumber } from 'bignumber.js';
|
|
5
5
|
/**
|
|
@@ -34,6 +34,15 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
34
34
|
let sourceAmountInUnitsForQuote;
|
|
35
35
|
let bridgeProviderResult = 'none';
|
|
36
36
|
let allowanceTargetResult = undefined;
|
|
37
|
+
console.log('[SilentSwap:QuoteCalc] Starting quote calculation', {
|
|
38
|
+
sourceAsset: debouncedSourceAsset,
|
|
39
|
+
sourceAmount: debouncedSourceAmount,
|
|
40
|
+
isSourceUsdcAvalanche,
|
|
41
|
+
isSourceSolana,
|
|
42
|
+
isSourceBitcoin,
|
|
43
|
+
destinationsCount: destinations.length,
|
|
44
|
+
splits,
|
|
45
|
+
});
|
|
37
46
|
if (isSourceUsdcAvalanche) {
|
|
38
47
|
const assetInfo = getAssetByCaip19(S_CAIP19_USDC_AVALANCHE);
|
|
39
48
|
if (!assetInfo)
|
|
@@ -41,31 +50,26 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
41
50
|
const sourceAmountBN = BigNumber(debouncedSourceAmount);
|
|
42
51
|
sourceAmountInUnitsForQuote = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
43
52
|
usdcAmountOut = sourceAmountInUnitsForQuote;
|
|
53
|
+
console.log('[SilentSwap:QuoteCalc] Direct USDC deposit', {
|
|
54
|
+
sourceAmountInUnits: sourceAmountInUnitsForQuote,
|
|
55
|
+
usdcAmountOut,
|
|
56
|
+
});
|
|
44
57
|
}
|
|
45
58
|
else if (isSourceSolana) {
|
|
46
|
-
// Solana assets - use relay.link only (not deBridge)
|
|
47
59
|
const assetInfo = getAssetByCaip19(debouncedSourceAsset);
|
|
48
60
|
if (!assetInfo)
|
|
49
61
|
throw new Error(`Solana asset not found`);
|
|
50
62
|
const sourceAmountBN = BigNumber(debouncedSourceAmount);
|
|
51
63
|
sourceAmountInUnitsForQuote = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
52
|
-
const sourceAmountInUnits = sourceAmountInUnitsForQuote;
|
|
53
|
-
// Parse Solana CAIP-19 to get chain ID and token address
|
|
54
64
|
const solanaParsed = parseSolanaCaip19(debouncedSourceAsset);
|
|
55
65
|
if (!solanaParsed)
|
|
56
66
|
throw new Error(`Invalid Solana CAIP-19 format: ${debouncedSourceAsset}`);
|
|
57
|
-
// Determine origin currency: system program for native SOL, token address for SPL tokens
|
|
58
|
-
// This matches relay_origin_asset() from silentswap-v2-ui/src/services/relay-link.ts
|
|
59
67
|
const originCurrency = isSolanaNativeToken(debouncedSourceAsset)
|
|
60
68
|
? SB58_ADDR_SOL_PROGRAM_SYSTEM
|
|
61
69
|
: solanaParsed.tokenAddress ||
|
|
62
70
|
(() => {
|
|
63
71
|
throw new Error(`Missing token address for Solana asset: ${debouncedSourceAsset}`);
|
|
64
72
|
})();
|
|
65
|
-
// For Solana swaps, we need:
|
|
66
|
-
// - Solana address for the 'user' parameter in relay quote (matches Svelte line 121: user: s_addr_sender)
|
|
67
|
-
// - EVM address for the 'recipient' parameter (matches Svelte line 122: recipient: s0x_signer)
|
|
68
|
-
// - EVM address for deposit calldata (matches Svelte line 156: signer: s0x_signer)
|
|
69
73
|
if (!evmAddress) {
|
|
70
74
|
throw new Error('EVM address required for Solana swaps (needed for deposit calldata and recipient)');
|
|
71
75
|
}
|
|
@@ -73,71 +77,58 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
73
77
|
if (!solanaAddress) {
|
|
74
78
|
throw new Error('Solana address required for Solana swaps');
|
|
75
79
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}, abortController.signal);
|
|
80
|
+
console.log('[SilentSwap:QuoteCalc] Solana → solveOptimalUsdcAmount', {
|
|
81
|
+
chainId: N_RELAY_CHAIN_ID_SOLANA,
|
|
82
|
+
originCurrency,
|
|
83
|
+
sourceAmountInUnits: sourceAmountInUnitsForQuote,
|
|
84
|
+
solanaAddress,
|
|
85
|
+
evmAddress,
|
|
86
|
+
depositorAddress,
|
|
87
|
+
decimals: assetInfo.decimals,
|
|
88
|
+
precision: assetInfo.precision,
|
|
89
|
+
});
|
|
90
|
+
const solveResult = await solveOptimalUsdcAmount(N_RELAY_CHAIN_ID_SOLANA, originCurrency, sourceAmountInUnitsForQuote, solanaAddress, undefined, X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress));
|
|
88
91
|
if (abortController.signal.aborted) {
|
|
89
92
|
setLoadingAmounts(false);
|
|
90
93
|
return null;
|
|
91
94
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
usdcAmountOut = solveResult.usdcAmountOut.toString();
|
|
96
|
+
bridgeProviderResult = solveResult.provider;
|
|
97
|
+
allowanceTargetResult = solveResult.allowanceTarget;
|
|
98
|
+
console.log('[SilentSwap:QuoteCalc] Solana solve result', {
|
|
99
|
+
usdcAmountOut,
|
|
100
|
+
provider: bridgeProviderResult,
|
|
101
|
+
allowanceTarget: allowanceTargetResult,
|
|
102
|
+
});
|
|
97
103
|
}
|
|
98
104
|
else if (isSourceBitcoin) {
|
|
99
|
-
// Bitcoin assets -
|
|
105
|
+
// Bitcoin assets - use solveOptimalUsdcAmount for iterative EXACT_OUTPUT fitting
|
|
106
|
+
// (same issue as Solana: naive EXACT_INPUT amount causes simulation revert
|
|
107
|
+
// when used with EXACT_OUTPUT during execution due to slippage buffer)
|
|
100
108
|
const assetInfo = getAssetByCaip19(debouncedSourceAsset);
|
|
101
109
|
if (!assetInfo)
|
|
102
110
|
throw new Error(`Bitcoin asset not found`);
|
|
103
111
|
const sourceAmountBN = BigNumber(debouncedSourceAmount);
|
|
104
112
|
sourceAmountInUnitsForQuote = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
105
|
-
const sourceAmountInUnits = sourceAmountInUnitsForQuote;
|
|
106
|
-
// For Bitcoin swaps, we need:
|
|
107
|
-
// - Bitcoin address for the 'user' parameter in relay quote
|
|
108
|
-
// - EVM address for the 'recipient' parameter
|
|
109
|
-
// - EVM address for deposit calldata
|
|
110
113
|
if (!evmAddress) {
|
|
111
114
|
throw new Error('EVM address required for Bitcoin swaps (needed for deposit calldata and recipient)');
|
|
112
115
|
}
|
|
113
|
-
// Bitcoin address should be a string that doesn't start with 0x
|
|
114
|
-
// For now, we'll use the address parameter if it's not an EVM address
|
|
115
116
|
const bitcoinAddress = typeof address === 'string' && !address.startsWith('0x') ? address : null;
|
|
116
117
|
if (!bitcoinAddress) {
|
|
117
118
|
throw new Error('Bitcoin address required for Bitcoin swaps');
|
|
118
119
|
}
|
|
119
|
-
//
|
|
120
|
-
//
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
destinationChainId: NI_CHAIN_ID_AVALANCHE,
|
|
125
|
-
originCurrency: SBTC_ADDR_BITCOIN_NATIVE, // Bitcoin native token (BTC) - relay.link requires this specific address
|
|
126
|
-
destinationCurrency: S0X_ADDR_USDC_AVALANCHE,
|
|
127
|
-
amount: sourceAmountInUnits,
|
|
128
|
-
tradeType: 'EXACT_INPUT',
|
|
129
|
-
referrer: 'silentswap',
|
|
130
|
-
recipient: getAddress(evmAddress), // EVM address for recipient
|
|
131
|
-
}, abortController.signal);
|
|
120
|
+
// Use solveOptimalUsdcAmount which iteratively fits EXACT_OUTPUT amount
|
|
121
|
+
// to stay within the source balance (matches Svelte's relay_solve_uusdc_amount)
|
|
122
|
+
const solveResult = await solveOptimalUsdcAmount(N_RELAY_CHAIN_ID_BITCOIN, SBTC_ADDR_BITCOIN_NATIVE, sourceAmountInUnitsForQuote, bitcoinAddress, // Bitcoin address for relay 'user' parameter
|
|
123
|
+
undefined, // depositCalldata - will use phony
|
|
124
|
+
X_MAX_IMPACT_PERCENT, depositorAddress, getAddress(evmAddress));
|
|
132
125
|
if (abortController.signal.aborted) {
|
|
133
126
|
setLoadingAmounts(false);
|
|
134
127
|
return null;
|
|
135
128
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
allowanceTargetResult = undefined; // Bitcoin doesn't need allowance
|
|
140
|
-
// sourceAmountInUnitsForQuote already set above for Bitcoin
|
|
129
|
+
usdcAmountOut = solveResult.usdcAmountOut.toString();
|
|
130
|
+
bridgeProviderResult = solveResult.provider;
|
|
131
|
+
allowanceTargetResult = solveResult.allowanceTarget;
|
|
141
132
|
}
|
|
142
133
|
else {
|
|
143
134
|
// EVM assets
|
|
@@ -196,21 +196,32 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
196
196
|
setIsSwapping(true);
|
|
197
197
|
setCurrentStep('Fetching quote...');
|
|
198
198
|
onStatus?.('Fetching quote...');
|
|
199
|
+
console.log('[SilentSwap:ExecuteSwap] Starting executeSwap', {
|
|
200
|
+
sourceAsset,
|
|
201
|
+
sourceAmount,
|
|
202
|
+
destinationsCount: destinations.length,
|
|
203
|
+
splits,
|
|
204
|
+
senderContactId,
|
|
205
|
+
integratorId,
|
|
206
|
+
});
|
|
199
207
|
const quoteResult = await calculateQuote(sourceAsset, sourceAmount, destinations, splits);
|
|
200
208
|
if (!quoteResult) {
|
|
201
|
-
// Ensure loadingAmounts is reset if handleGetQuote failed
|
|
202
209
|
throw new Error('Failed to get quote');
|
|
203
210
|
}
|
|
204
211
|
const { quote: quoteResponse, usdcAmount: effectiveUsdcAmount, sourceAmountInUnits, facilitatorGroup: passedFacilitatorGroup, bridgeProvider: effectiveProvider, allowanceTarget: effectiveAllowanceTarget, } = quoteResult;
|
|
212
|
+
console.log('[SilentSwap:ExecuteSwap] Quote result', {
|
|
213
|
+
usdcAmount: effectiveUsdcAmount,
|
|
214
|
+
sourceAmountInUnits,
|
|
215
|
+
provider: effectiveProvider,
|
|
216
|
+
allowanceTarget: effectiveAllowanceTarget,
|
|
217
|
+
authorizationsCount: quoteResponse.authorizations?.length,
|
|
218
|
+
});
|
|
205
219
|
setCurrentStep('Executing swap...');
|
|
206
220
|
onStatus?.('Executing swap...');
|
|
207
|
-
// Use the exact source amount in units from the quote result so order and deposit
|
|
208
|
-
// always match what was requested (avoids rounding/precision mismatch)
|
|
209
221
|
// Determine provider for bridge swap
|
|
210
222
|
const isDirectDeposit = sourceAsset === S_CAIP19_USDC_AVALANCHE;
|
|
211
223
|
let providerForSwap = undefined;
|
|
212
224
|
if (effectiveUsdcAmount && !isDirectDeposit) {
|
|
213
|
-
// When usdcAmount is provided and not direct deposit, we're doing a bridge swap and MUST have a provider
|
|
214
225
|
if (effectiveProvider === 'relay' || effectiveProvider === 'debridge') {
|
|
215
226
|
providerForSwap = effectiveProvider;
|
|
216
227
|
}
|
|
@@ -243,9 +254,15 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
243
254
|
const evmSignerAddress = getAddress(evmAddress); // Use user's wallet address, not facilitator group's viewer EVM signer
|
|
244
255
|
// Handle Solana swaps
|
|
245
256
|
if (isSourceSolana) {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
257
|
+
console.log('[SilentSwap:ExecuteSwap] Entering Solana swap path', {
|
|
258
|
+
sourceAsset,
|
|
259
|
+
sourceAmountInUnits,
|
|
260
|
+
usdcAmount: effectiveUsdcAmount,
|
|
261
|
+
evmSignerAddress,
|
|
262
|
+
viewingAuth,
|
|
263
|
+
provider: providerForSwap,
|
|
264
|
+
});
|
|
265
|
+
const result = await executeSolanaSwap(quoteResponse, sourceAsset, sourceAmountInUnits, effectiveUsdcAmount, senderContactId, solanaConnector, evmSignerAddress, viewingAuth, createOrder, executeSolanaBridge, resolvedGroup, integratorId);
|
|
249
266
|
setOrderId(result.orderId);
|
|
250
267
|
setViewingAuth(result.viewingAuth);
|
|
251
268
|
return result;
|
|
@@ -398,11 +415,20 @@ viewingAuth, createOrder, executeSolanaBridge, facilitatorGroup, integratorId) {
|
|
|
398
415
|
if (!solanaSenderAddress) {
|
|
399
416
|
throw new Error('Failed to get Solana sender address');
|
|
400
417
|
}
|
|
418
|
+
console.log('[SilentSwap:SolanaSwap] Creating order', {
|
|
419
|
+
sourceAsset,
|
|
420
|
+
sourceAmount,
|
|
421
|
+
sourceAmountBigInt: `${BigInt(sourceAmount)}`,
|
|
422
|
+
senderContactId,
|
|
423
|
+
solanaSenderAddress,
|
|
424
|
+
evmSignerAddress,
|
|
425
|
+
usdcAmount,
|
|
426
|
+
authorizationsCount: quoteResponse.authorizations?.length,
|
|
427
|
+
});
|
|
401
428
|
// Create order with empty authorizations (Solana doesn't use EIP-3009)
|
|
402
|
-
// Pass resolved facilitator group (matches Svelte behavior)
|
|
403
429
|
const orderResponse = await createOrder(quoteResponse, quoteResponse.authorizations.map((auth) => ({
|
|
404
430
|
...auth,
|
|
405
|
-
signature: '0x',
|
|
431
|
+
signature: '0x',
|
|
406
432
|
})), {
|
|
407
433
|
sourceAsset: {
|
|
408
434
|
caip19: sourceAsset,
|
|
@@ -413,18 +439,31 @@ viewingAuth, createOrder, executeSolanaBridge, facilitatorGroup, integratorId) {
|
|
|
413
439
|
},
|
|
414
440
|
...(integratorId && { integratorId }),
|
|
415
441
|
}, facilitatorGroup);
|
|
442
|
+
console.log('[SilentSwap:SolanaSwap] Order created', {
|
|
443
|
+
orderId: orderResponse.response?.orderId,
|
|
444
|
+
hasTransaction: !!orderResponse.transaction,
|
|
445
|
+
hasMetadata: !!orderResponse.transaction?.metadata,
|
|
446
|
+
hasParams: !!orderResponse.transaction?.metadata?.params,
|
|
447
|
+
});
|
|
416
448
|
// Get deposit parameters from order
|
|
417
449
|
const depositParams = orderResponse.transaction.metadata?.params;
|
|
418
450
|
if (!depositParams) {
|
|
419
451
|
throw new Error('Missing deposit parameters in order response');
|
|
420
452
|
}
|
|
453
|
+
console.log('[SilentSwap:SolanaSwap] Executing bridge', {
|
|
454
|
+
sourceAsset,
|
|
455
|
+
sourceAmount,
|
|
456
|
+
usdcAmount,
|
|
457
|
+
solanaSenderAddress,
|
|
458
|
+
evmSignerAddress,
|
|
459
|
+
depositParamsKeys: Object.keys(depositParams),
|
|
460
|
+
});
|
|
421
461
|
// Execute bridge transaction
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
depositParams);
|
|
462
|
+
const bridgeResult = await executeSolanaBridge(sourceAsset, sourceAmount, usdcAmount, solanaSenderAddress, evmSignerAddress, depositParams);
|
|
463
|
+
console.log('[SilentSwap:SolanaSwap] Bridge result', {
|
|
464
|
+
depositTxHash: bridgeResult.depositTxHash,
|
|
465
|
+
provider: bridgeResult.provider,
|
|
466
|
+
});
|
|
428
467
|
const resultOrderId = orderResponse.response.orderId;
|
|
429
468
|
// Note: setOrderId is not available in this function scope,
|
|
430
469
|
// but the orderId will be set by the calling executeSwap function
|
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.91",
|
|
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.91",
|
|
28
|
+
"@silentswap/ui-kit": "0.0.91",
|
|
29
29
|
"@solana/codecs-strings": "^5.1.0",
|
|
30
30
|
"@solana/kit": "^5.1.0",
|
|
31
31
|
"@solana/rpc": "^5.1.0",
|