@silentswap/react 0.0.52 → 0.0.55
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/BalancesContext.d.ts +2 -0
- package/dist/contexts/BalancesContext.js +106 -6
- package/dist/contexts/SilentSwapContext.d.ts +6 -1
- package/dist/contexts/SilentSwapContext.js +40 -14
- package/dist/hooks/silent/useBridgeExecution.d.ts +5 -1
- package/dist/hooks/silent/useBridgeExecution.js +203 -23
- package/dist/hooks/silent/useQuoteCalculation.js +135 -33
- package/dist/hooks/silent/useSilentQuote.d.ts +10 -1
- package/dist/hooks/silent/useSilentQuote.js +134 -8
- package/dist/hooks/useOrderEstimates.js +14 -6
- package/dist/hooks/useQuote.js +5 -1
- package/dist/hooks/useSwap.js +7 -1
- package/dist/hooks/useTransaction.d.ts +6 -1
- package/dist/hooks/useTransaction.js +105 -2
- package/dist/hooks/useTransactionAddress.d.ts +3 -2
- package/dist/hooks/useTransactionAddress.js +8 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +4 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useCallback, useState } from 'react';
|
|
2
|
-
import { isSolanaAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, getAssetByCaip19, solveOptimalUsdcAmount, N_RELAY_CHAIN_ID_SOLANA, SB58_ADDR_SOL_PROGRAM_SYSTEM, isSolanaNativeToken, parseSolanaCaip19, EVM_PHONY_ADDRESS, isValidSolanaAddress, getAddressFromCaip10, S0X_ADDR_USDC_AVALANCHE, isEvmNativeToken, caip19FungibleEvmToken, FacilitatorKeyType, createHdFacilitatorGroupFromEntropy, PublicKeyArgGroups, SB58_CHAIN_ID_SOLANA_MAINNET, caip19SplToken, DeliveryMethod, X_MAX_IMPACT_PERCENT, } from '@silentswap/sdk';
|
|
2
|
+
import { isSolanaAsset, isBitcoinAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, getAssetByCaip19, solveOptimalUsdcAmount, fetchRelayQuote, 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, isEvmNativeToken, caip19FungibleEvmToken, FacilitatorKeyType, createHdFacilitatorGroupFromEntropy, PublicKeyArgGroups, SB58_CHAIN_ID_SOLANA_MAINNET, caip19SplToken, DeliveryMethod, X_MAX_IMPACT_PERCENT, NI_CHAIN_ID_AVALANCHE, SBTC_ADDR_BITCOIN_NATIVE, } from '@silentswap/sdk';
|
|
3
3
|
import { getAddress } from 'viem';
|
|
4
4
|
import { BigNumber } from 'bignumber.js';
|
|
5
5
|
/**
|
|
@@ -28,6 +28,7 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
28
28
|
}
|
|
29
29
|
const isSourceUsdcAvalanche = debouncedSourceAsset === S_CAIP19_USDC_AVALANCHE;
|
|
30
30
|
const isSourceSolana = isSolanaAsset(debouncedSourceAsset);
|
|
31
|
+
const isSourceBitcoin = isBitcoinAsset(debouncedSourceAsset);
|
|
31
32
|
let usdcAmountOut;
|
|
32
33
|
let bridgeProviderResult = 'none';
|
|
33
34
|
let allowanceTargetResult = undefined;
|
|
@@ -39,8 +40,7 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
39
40
|
usdcAmountOut = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
40
41
|
}
|
|
41
42
|
else if (isSourceSolana) {
|
|
42
|
-
// Solana assets -
|
|
43
|
-
// solveOptimalUsdcAmount will compare both providers and choose the best rate
|
|
43
|
+
// Solana assets - use relay.link only (not deBridge)
|
|
44
44
|
const assetInfo = getAssetByCaip19(debouncedSourceAsset);
|
|
45
45
|
if (!assetInfo)
|
|
46
46
|
throw new Error(`Solana asset not found`);
|
|
@@ -69,21 +69,68 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
69
69
|
if (!solanaAddress) {
|
|
70
70
|
throw new Error('Solana address required for Solana swaps');
|
|
71
71
|
}
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
// Use relay.link only for Solana (not deBridge)
|
|
73
|
+
const relayQuote = await fetchRelayQuote({
|
|
74
|
+
user: solanaAddress, // Solana address for user parameter
|
|
75
|
+
originChainId: N_RELAY_CHAIN_ID_SOLANA,
|
|
76
|
+
destinationChainId: NI_CHAIN_ID_AVALANCHE,
|
|
77
|
+
originCurrency: originCurrency, // Base58 Solana address (system program or SPL token)
|
|
78
|
+
destinationCurrency: S0X_ADDR_USDC_AVALANCHE,
|
|
79
|
+
amount: sourceAmountInUnits,
|
|
80
|
+
tradeType: 'EXACT_INPUT',
|
|
81
|
+
referrer: 'silentswap',
|
|
82
|
+
recipient: getAddress(evmAddress), // EVM address for recipient
|
|
83
|
+
}, abortController.signal);
|
|
79
84
|
if (abortController.signal.aborted) {
|
|
80
85
|
setLoadingAmounts(false);
|
|
81
86
|
return null;
|
|
82
87
|
}
|
|
83
|
-
//
|
|
84
|
-
usdcAmountOut =
|
|
85
|
-
bridgeProviderResult =
|
|
86
|
-
allowanceTargetResult =
|
|
88
|
+
// Extract USDC amount from relay quote
|
|
89
|
+
usdcAmountOut = relayQuote.details.currencyOut.amount;
|
|
90
|
+
bridgeProviderResult = 'relay'; // Solana uses relay only
|
|
91
|
+
allowanceTargetResult = undefined; // Relay doesn't need allowance target
|
|
92
|
+
}
|
|
93
|
+
else if (isSourceBitcoin) {
|
|
94
|
+
// Bitcoin assets - only relay.link supports Bitcoin
|
|
95
|
+
const assetInfo = getAssetByCaip19(debouncedSourceAsset);
|
|
96
|
+
if (!assetInfo)
|
|
97
|
+
throw new Error(`Bitcoin asset not found`);
|
|
98
|
+
const sourceAmountBN = BigNumber(debouncedSourceAmount);
|
|
99
|
+
const sourceAmountInUnits = sourceAmountBN.shiftedBy(assetInfo.decimals).toFixed(0);
|
|
100
|
+
// For Bitcoin swaps, we need:
|
|
101
|
+
// - Bitcoin address for the 'user' parameter in relay quote
|
|
102
|
+
// - EVM address for the 'recipient' parameter
|
|
103
|
+
// - EVM address for deposit calldata
|
|
104
|
+
if (!evmAddress) {
|
|
105
|
+
throw new Error('EVM address required for Bitcoin swaps (needed for deposit calldata and recipient)');
|
|
106
|
+
}
|
|
107
|
+
// Bitcoin address should be a string that doesn't start with 0x
|
|
108
|
+
// For now, we'll use the address parameter if it's not an EVM address
|
|
109
|
+
const bitcoinAddress = typeof address === 'string' && !address.startsWith('0x') ? address : null;
|
|
110
|
+
if (!bitcoinAddress) {
|
|
111
|
+
throw new Error('Bitcoin address required for Bitcoin swaps');
|
|
112
|
+
}
|
|
113
|
+
// Bitcoin only supports relay, not deBridge
|
|
114
|
+
// Use relay.link directly (not solveOptimalUsdcAmount which compares both providers)
|
|
115
|
+
const relayQuote = await fetchRelayQuote({
|
|
116
|
+
user: bitcoinAddress, // Bitcoin address for user parameter
|
|
117
|
+
originChainId: N_RELAY_CHAIN_ID_BITCOIN,
|
|
118
|
+
destinationChainId: NI_CHAIN_ID_AVALANCHE,
|
|
119
|
+
originCurrency: SBTC_ADDR_BITCOIN_NATIVE, // Bitcoin native token (BTC) - relay.link requires this specific address
|
|
120
|
+
destinationCurrency: S0X_ADDR_USDC_AVALANCHE,
|
|
121
|
+
amount: sourceAmountInUnits,
|
|
122
|
+
tradeType: 'EXACT_INPUT',
|
|
123
|
+
referrer: 'silentswap',
|
|
124
|
+
recipient: getAddress(evmAddress), // EVM address for recipient
|
|
125
|
+
}, abortController.signal);
|
|
126
|
+
if (abortController.signal.aborted) {
|
|
127
|
+
setLoadingAmounts(false);
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
// Extract USDC amount from relay quote
|
|
131
|
+
usdcAmountOut = relayQuote.details.currencyOut.amount;
|
|
132
|
+
bridgeProviderResult = 'relay'; // Bitcoin only supports relay
|
|
133
|
+
allowanceTargetResult = undefined; // Bitcoin doesn't need allowance
|
|
87
134
|
}
|
|
88
135
|
else {
|
|
89
136
|
// EVM assets
|
|
@@ -136,8 +183,9 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
136
183
|
});
|
|
137
184
|
const outputs = destinations.map((dest, idx) => {
|
|
138
185
|
const isDestSolana = isSolanaAsset(dest.asset);
|
|
186
|
+
const isDestBitcoin = isBitcoinAsset(dest.asset);
|
|
139
187
|
let asset;
|
|
140
|
-
let recipientAddress; // Changed from `0x${string}` to string to support Solana addresses
|
|
188
|
+
let recipientAddress; // Changed from `0x${string}` to string to support Solana and Bitcoin addresses
|
|
141
189
|
if (isDestSolana) {
|
|
142
190
|
// Solana destination
|
|
143
191
|
const destParsed = parseSolanaCaip19(dest.asset);
|
|
@@ -172,33 +220,78 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
172
220
|
throw new Error(`Solana destination ${idx} requires a recipient address in the contact field`);
|
|
173
221
|
}
|
|
174
222
|
}
|
|
223
|
+
else if (isDestBitcoin) {
|
|
224
|
+
// Bitcoin destination
|
|
225
|
+
// Bitcoin assets use the asset CAIP-19 as-is (native Bitcoin only supported currently)
|
|
226
|
+
asset = dest.asset;
|
|
227
|
+
// Extract Bitcoin address from contact field
|
|
228
|
+
// CRITICAL: Must be a valid Bitcoin address (bc1, 1, or 3 prefix)
|
|
229
|
+
if (dest.contact) {
|
|
230
|
+
// Check if contact is in CAIP10 format
|
|
231
|
+
if (dest.contact.startsWith('caip10:bip122:')) {
|
|
232
|
+
recipientAddress = getAddressFromCaip10(dest.contact);
|
|
233
|
+
// Validate it's actually a Bitcoin address
|
|
234
|
+
if (!isValidBitcoinAddress(recipientAddress)) {
|
|
235
|
+
throw new Error(`Invalid Bitcoin address extracted from CAIP10: ${dest.contact} -> ${recipientAddress}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Check if contact is a valid Bitcoin address format
|
|
240
|
+
if (isValidBitcoinAddress(dest.contact)) {
|
|
241
|
+
recipientAddress = dest.contact;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
throw new Error(`Invalid Bitcoin recipient address for destination ${idx}: ${dest.contact}. Expected Bitcoin address (bc1, 1, or 3 prefix) or caip10:bip122:*: format.`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
throw new Error(`Bitcoin destination ${idx} requires a recipient address in the contact field`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
175
252
|
else {
|
|
176
253
|
// EVM destination
|
|
177
254
|
const destParsed = parseEvmCaip19(dest.asset);
|
|
178
|
-
if (!destParsed)
|
|
179
|
-
throw new Error(`
|
|
255
|
+
if (!destParsed) {
|
|
256
|
+
throw new Error(`Failed to parse EVM destination CAIP-19: ${dest.asset}. Expected EVM asset format (eip155:chainId/erc20:address or eip155:chainId/slip44:cointype).`);
|
|
257
|
+
}
|
|
180
258
|
const isNative = isEvmNativeToken(dest.asset);
|
|
181
259
|
const destChainId = destParsed.chainId;
|
|
182
260
|
asset = isNative
|
|
183
261
|
? dest.asset
|
|
184
262
|
: caip19FungibleEvmToken(destChainId, destParsed.tokenAddress);
|
|
263
|
+
// Extract EVM address from contact field
|
|
264
|
+
// CRITICAL: Must be a valid EVM address (0x prefix)
|
|
185
265
|
if (dest.contact) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
266
|
+
// Check if contact is in CAIP10 format
|
|
267
|
+
if (dest.contact.startsWith('caip10:eip155:')) {
|
|
268
|
+
recipientAddress = getAddressFromCaip10(dest.contact);
|
|
269
|
+
// Validate it's actually an EVM address
|
|
270
|
+
if (!isValidEvmAddress(recipientAddress)) {
|
|
271
|
+
throw new Error(`Invalid EVM address extracted from CAIP10: ${dest.contact} -> ${recipientAddress}`);
|
|
190
272
|
}
|
|
191
|
-
|
|
192
|
-
|
|
273
|
+
// Normalize to checksummed format
|
|
274
|
+
try {
|
|
275
|
+
recipientAddress = getAddress(recipientAddress);
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
throw new Error(`Invalid EVM address checksum for destination ${idx}: ${recipientAddress}. ${error instanceof Error ? error.message : String(error)}`);
|
|
193
279
|
}
|
|
194
280
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
281
|
+
else {
|
|
282
|
+
// Check if contact is a valid EVM address format
|
|
283
|
+
if (isValidEvmAddress(dest.contact)) {
|
|
284
|
+
// Normalize to checksummed format
|
|
285
|
+
try {
|
|
286
|
+
recipientAddress = getAddress(dest.contact);
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
throw new Error(`Invalid EVM address checksum for destination ${idx}: ${dest.contact}. ${error instanceof Error ? error.message : String(error)}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
throw new Error(`Invalid EVM recipient address for destination ${idx}: ${dest.contact}. Expected 0x-prefixed EVM address or caip10:eip155:*: format.`);
|
|
294
|
+
}
|
|
202
295
|
}
|
|
203
296
|
}
|
|
204
297
|
else {
|
|
@@ -209,12 +302,21 @@ export function useQuoteCalculation({ address, evmAddress, wallet, depositorAddr
|
|
|
209
302
|
// The value field in the quote request should be USDC micro units, not the destination asset amount
|
|
210
303
|
// This matches how Svelte calculates a_amounts_out and uses it as value in the quote request
|
|
211
304
|
const outputValue = splitUsdcAmounts[idx];
|
|
212
|
-
// Final validation: Ensure
|
|
305
|
+
// Final validation: Ensure addresses match their chain type
|
|
213
306
|
if (isDestSolana && !isValidSolanaAddress(recipientAddress)) {
|
|
214
307
|
throw new Error(`Invalid recipient address type for Solana destination ${idx}: ${recipientAddress}. Expected base58 Solana address.`);
|
|
215
308
|
}
|
|
216
|
-
else if (
|
|
217
|
-
|
|
309
|
+
else if (isDestBitcoin) {
|
|
310
|
+
// Validate Bitcoin address format
|
|
311
|
+
if (!isValidBitcoinAddress(recipientAddress)) {
|
|
312
|
+
throw new Error(`Invalid recipient address type for Bitcoin destination ${idx}: ${recipientAddress}. Expected Bitcoin address (bc1, 1, or 3 prefix).`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
else if (!isDestSolana && !isDestBitcoin) {
|
|
316
|
+
// Validate EVM address format
|
|
317
|
+
if (!isValidEvmAddress(recipientAddress)) {
|
|
318
|
+
throw new Error(`Invalid recipient address type for EVM destination ${idx}: ${recipientAddress}. Expected 0x-prefixed EVM address.`);
|
|
319
|
+
}
|
|
218
320
|
}
|
|
219
321
|
return {
|
|
220
322
|
method: DeliveryMethod.SNIP,
|
|
@@ -2,6 +2,7 @@ import type { SilentSwapClient, QuoteResponse, AssetInfo } from '@silentswap/sdk
|
|
|
2
2
|
import type { WalletClient } from 'viem';
|
|
3
3
|
import type { Connector } from 'wagmi';
|
|
4
4
|
import type { SolanaWalletConnector, SolanaConnection } from './solana-transaction.js';
|
|
5
|
+
import type { BitcoinWalletConnector, BitcoinConnection } from './bitcoin-transaction.js';
|
|
5
6
|
import { type SwapTransaction } from '../useTransaction.js';
|
|
6
7
|
import type { SilentSwapWallet } from './useWallet.js';
|
|
7
8
|
export type { SwapTransaction };
|
|
@@ -40,6 +41,10 @@ export interface useSilentQuoteOptions {
|
|
|
40
41
|
wallet: SilentSwapWallet | null;
|
|
41
42
|
/** Whether wallet is currently being generated (to prevent swap execution before wallet is ready) */
|
|
42
43
|
walletLoading?: boolean;
|
|
44
|
+
/** Wallet generation error (if previous generation failed) */
|
|
45
|
+
walletError?: Error | null;
|
|
46
|
+
/** Function to generate wallet (for retry on swap execution) */
|
|
47
|
+
generateWallet?: () => Promise<void>;
|
|
43
48
|
/** Facilitator group for the swap, or a function that resolves it */
|
|
44
49
|
/** Status update callback */
|
|
45
50
|
onStatus?: (status: string) => void;
|
|
@@ -49,6 +54,10 @@ export interface useSilentQuoteOptions {
|
|
|
49
54
|
solanaConnection?: SolanaConnection;
|
|
50
55
|
/** Solana RPC URL (optional, will create connection if not provided) */
|
|
51
56
|
solanaRpcUrl?: string;
|
|
57
|
+
/** Bitcoin wallet connector (required for Bitcoin swaps) */
|
|
58
|
+
bitcoinConnector?: BitcoinWalletConnector;
|
|
59
|
+
/** Bitcoin connection (optional, for consistency) */
|
|
60
|
+
bitcoinConnection?: BitcoinConnection;
|
|
52
61
|
/** Get price function */
|
|
53
62
|
getPrice: (asset: AssetInfo) => Promise<number>;
|
|
54
63
|
setDestinations: (updater: Destination[] | ((prev: Destination[]) => Destination[])) => void;
|
|
@@ -87,4 +96,4 @@ export interface ExecuteSwapParams {
|
|
|
87
96
|
/** Optional integrator ID for tracking */
|
|
88
97
|
integratorId?: string;
|
|
89
98
|
}
|
|
90
|
-
export declare function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, getPrice, setDestinations, }: useSilentQuoteOptions): useSilentQuoteReturn;
|
|
99
|
+
export declare function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading, walletError, generateWallet, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, }: useSilentQuoteOptions): useSilentQuoteReturn;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useCallback, useMemo, useState } from 'react';
|
|
2
|
-
import { hexToBase58, isSolanaAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, NI_CHAIN_ID_AVALANCHE, getAssetByCaip19, } from '@silentswap/sdk';
|
|
1
|
+
import { useCallback, useMemo, useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { hexToBase58, isSolanaAsset, isBitcoinAsset, parseEvmCaip19, S_CAIP19_USDC_AVALANCHE, NI_CHAIN_ID_AVALANCHE, getAssetByCaip19, } from '@silentswap/sdk';
|
|
3
3
|
import { getAddress } from 'viem';
|
|
4
4
|
import { BigNumber } from 'bignumber.js';
|
|
5
5
|
import { useQuoteFetching } from './useQuoteFetching.js';
|
|
@@ -7,7 +7,7 @@ import { useOrderSigning } from './useOrderSigning.js';
|
|
|
7
7
|
import { useBridgeExecution } from './useBridgeExecution.js';
|
|
8
8
|
import { useTransaction } from '../useTransaction.js';
|
|
9
9
|
import { useQuoteCalculation } from './useQuoteCalculation.js';
|
|
10
|
-
export function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading = false, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, getPrice, setDestinations, }) {
|
|
10
|
+
export function useSilentQuote({ client, address, evmAddress, solAddress, walletClient, connector, wallet, walletLoading = false, walletError = null, generateWallet, onStatus, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, getPrice, setDestinations, }) {
|
|
11
11
|
const [isLoading, setIsLoading] = useState(false);
|
|
12
12
|
const [currentStep, setCurrentStep] = useState('');
|
|
13
13
|
const [quote, setQuote] = useState(null);
|
|
@@ -15,6 +15,18 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
15
15
|
const [orderId, setOrderId] = useState(null);
|
|
16
16
|
const [viewingAuth, setViewingAuth] = useState(null);
|
|
17
17
|
const [isSwapping, setIsSwapping] = useState(false);
|
|
18
|
+
// Use refs to track current wallet state (to avoid stale closure values)
|
|
19
|
+
const walletRef = useRef(wallet);
|
|
20
|
+
const walletLoadingRef = useRef(walletLoading);
|
|
21
|
+
const walletErrorRef = useRef(walletError);
|
|
22
|
+
const generateWalletRef = useRef(generateWallet);
|
|
23
|
+
// Update refs when wallet state changes
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
walletRef.current = wallet;
|
|
26
|
+
walletLoadingRef.current = walletLoading;
|
|
27
|
+
walletErrorRef.current = walletError;
|
|
28
|
+
generateWalletRef.current = generateWallet;
|
|
29
|
+
}, [wallet, walletLoading, walletError, generateWallet]);
|
|
18
30
|
// Normalize address - only normalize EVM addresses
|
|
19
31
|
// Note: For Solana swaps, we still need an EVM address for facilitator operations
|
|
20
32
|
// The address parameter should be EVM for facilitator operations, but can be Solana for quote requests
|
|
@@ -42,7 +54,7 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
42
54
|
// Initialize specialized hooks
|
|
43
55
|
const { getQuote: getQuoteInternal } = useQuoteFetching(client, rawAddress, setIsLoading, setCurrentStep, setError, onStatus);
|
|
44
56
|
const { signAuthorizations, createOrder } = useOrderSigning(walletClient, connector, client, setCurrentStep, onStatus);
|
|
45
|
-
const { executeSolanaBridge, executeEvmBridge } = useBridgeExecution(walletClient, connector, solanaConnector, solanaConnection, solanaRpcUrl, setCurrentStep, depositorAddress, onStatus);
|
|
57
|
+
const { executeSolanaBridge, executeBitcoinBridge, executeEvmBridge } = useBridgeExecution(walletClient, connector, solanaConnector, solanaConnection, solanaRpcUrl, setCurrentStep, depositorAddress, onStatus, bitcoinConnector, bitcoinConnection);
|
|
46
58
|
const { executeSwapTransaction, approveTokenSpending } = useTransaction({
|
|
47
59
|
address: normalizedAddress || '0x0000000000000000000000000000000000000000',
|
|
48
60
|
walletClient,
|
|
@@ -93,9 +105,49 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
93
105
|
if (!walletClient) {
|
|
94
106
|
throw new Error('Wallet client required for swap execution');
|
|
95
107
|
}
|
|
96
|
-
// Check if wallet
|
|
97
|
-
if (
|
|
98
|
-
|
|
108
|
+
// Check if wallet generation previously failed - retry if so
|
|
109
|
+
if (!walletRef.current && walletErrorRef.current && generateWalletRef.current && !walletLoadingRef.current) {
|
|
110
|
+
setCurrentStep('Retrying wallet generation...');
|
|
111
|
+
onStatus?.('Retrying wallet generation...');
|
|
112
|
+
try {
|
|
113
|
+
await generateWalletRef.current();
|
|
114
|
+
// Wait for wallet to be ready after retry (with timeout)
|
|
115
|
+
const maxWaitTime = 30000; // 30 seconds
|
|
116
|
+
const checkInterval = 100; // Check every 100ms
|
|
117
|
+
const startTime = Date.now();
|
|
118
|
+
while (!walletRef.current && Date.now() - startTime < maxWaitTime) {
|
|
119
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
120
|
+
}
|
|
121
|
+
// If wallet is still not ready after retry, throw error
|
|
122
|
+
if (!walletRef.current) {
|
|
123
|
+
throw new Error('Wallet generation retry completed but wallet is still not available. Please try again.');
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
const error = err instanceof Error ? err : new Error('Failed to generate wallet');
|
|
128
|
+
throw new Error(`Wallet generation failed: ${error.message}. Please try again or ensure wallet is connected and authenticated.`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Wait for wallet to be ready if it's being generated
|
|
132
|
+
// Use refs to check current state (avoid stale closure values)
|
|
133
|
+
if (!walletRef.current && walletLoadingRef.current) {
|
|
134
|
+
setCurrentStep('Waiting for wallet generation...');
|
|
135
|
+
onStatus?.('Waiting for wallet generation...');
|
|
136
|
+
// Wait for wallet generation to complete (with timeout)
|
|
137
|
+
const maxWaitTime = 30000; // 30 seconds
|
|
138
|
+
const checkInterval = 100; // Check every 100ms
|
|
139
|
+
const startTime = Date.now();
|
|
140
|
+
while (!walletRef.current && walletLoadingRef.current && Date.now() - startTime < maxWaitTime) {
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, checkInterval));
|
|
142
|
+
}
|
|
143
|
+
// If wallet is still not ready after waiting, throw error
|
|
144
|
+
if (!walletRef.current) {
|
|
145
|
+
throw new Error('Wallet is being generated. Please wait for wallet generation to complete before executing swap.');
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Final check: wallet must exist for swap execution
|
|
149
|
+
if (!walletRef.current) {
|
|
150
|
+
throw new Error('Wallet is required for swap execution. Please ensure wallet is connected and authenticated.');
|
|
99
151
|
}
|
|
100
152
|
setIsLoading(true);
|
|
101
153
|
setError(null);
|
|
@@ -140,8 +192,9 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
140
192
|
}
|
|
141
193
|
// Check swap type
|
|
142
194
|
const isSourceSolana = isSolanaAsset(sourceAsset);
|
|
195
|
+
const isSourceBitcoin = isBitcoinAsset(sourceAsset);
|
|
143
196
|
const isDepositingDirectly = sourceAsset === S_CAIP19_USDC_AVALANCHE;
|
|
144
|
-
const isSourceEvm = !isSourceSolana && !isDepositingDirectly && sourceAsset.startsWith('eip155:');
|
|
197
|
+
const isSourceEvm = !isSourceSolana && !isSourceBitcoin && !isDepositingDirectly && sourceAsset.startsWith('eip155:');
|
|
145
198
|
// Generate viewing authorization
|
|
146
199
|
const viewer = await resolvedGroup.viewer();
|
|
147
200
|
const evmSigner = await viewer.evmSigner();
|
|
@@ -163,6 +216,15 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
163
216
|
setViewingAuth(result.viewingAuth);
|
|
164
217
|
return result;
|
|
165
218
|
}
|
|
219
|
+
// Handle Bitcoin swaps
|
|
220
|
+
if (isSourceBitcoin) {
|
|
221
|
+
const result = await executeBitcoinSwap(quoteResponse, sourceAsset, sourceAmountInUnits, effectiveUsdcAmount, senderContactId, bitcoinConnector, evmSignerAddress, // Use EVM signer address, not normalizedAddress
|
|
222
|
+
viewingAuth, createOrder, executeBitcoinBridge, resolvedGroup, // Pass resolved group for order creation
|
|
223
|
+
integratorId);
|
|
224
|
+
setOrderId(result.orderId);
|
|
225
|
+
setViewingAuth(result.viewingAuth);
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
166
228
|
// Sign authorizations (for EVM swaps)
|
|
167
229
|
const signedAuths = await signAuthorizations(quoteResponse.authorizations, isDepositingDirectly);
|
|
168
230
|
// Create order with resolved facilitator group
|
|
@@ -233,7 +295,10 @@ export function useSilentQuote({ client, address, evmAddress, solAddress, wallet
|
|
|
233
295
|
evmAddress,
|
|
234
296
|
walletClient,
|
|
235
297
|
walletLoading,
|
|
298
|
+
walletError,
|
|
299
|
+
generateWallet,
|
|
236
300
|
solanaConnector,
|
|
301
|
+
bitcoinConnector,
|
|
237
302
|
signAuthorizations,
|
|
238
303
|
createOrder,
|
|
239
304
|
approveTokenSpending,
|
|
@@ -331,6 +396,67 @@ viewingAuth, createOrder, executeSolanaBridge, facilitatorGroup, integratorId) {
|
|
|
331
396
|
},
|
|
332
397
|
};
|
|
333
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Execute Bitcoin swap flow
|
|
401
|
+
*
|
|
402
|
+
* Handles the complete flow for Bitcoin-based swaps:
|
|
403
|
+
* 1. Validates Bitcoin connection
|
|
404
|
+
* 2. Creates order (with empty authorizations for Bitcoin)
|
|
405
|
+
* 3. Executes bridge transaction
|
|
406
|
+
* 4. Returns swap result
|
|
407
|
+
*/
|
|
408
|
+
async function executeBitcoinSwap(quoteResponse, sourceAsset, sourceAmount, usdcAmount, senderContactId, bitcoinConnector, evmSignerAddress, // EVM signer address (matches Svelte's s0x_signer)
|
|
409
|
+
viewingAuth, createOrder, executeBitcoinBridge, facilitatorGroup, integratorId) {
|
|
410
|
+
if (!bitcoinConnector) {
|
|
411
|
+
throw new Error('Bitcoin connector required for Bitcoin swaps');
|
|
412
|
+
}
|
|
413
|
+
// Get Bitcoin sender address
|
|
414
|
+
const accounts = await bitcoinConnector.getAccounts();
|
|
415
|
+
const bitcoinSenderAddress = bitcoinConnector.currentAccount || accounts[0] || '';
|
|
416
|
+
if (!bitcoinSenderAddress) {
|
|
417
|
+
throw new Error('Failed to get Bitcoin sender address');
|
|
418
|
+
}
|
|
419
|
+
// Create order with empty authorizations (Bitcoin doesn't use EIP-3009)
|
|
420
|
+
// Pass resolved facilitator group (matches Svelte behavior)
|
|
421
|
+
const orderResponse = await createOrder(quoteResponse, quoteResponse.authorizations.map((auth) => ({
|
|
422
|
+
...auth,
|
|
423
|
+
signature: '0x', // No EIP-3009 deposit for Bitcoin
|
|
424
|
+
})), {
|
|
425
|
+
sourceAsset: {
|
|
426
|
+
caip19: sourceAsset,
|
|
427
|
+
amount: `${BigInt(sourceAmount)}`,
|
|
428
|
+
},
|
|
429
|
+
sourceSender: {
|
|
430
|
+
contactId: senderContactId,
|
|
431
|
+
},
|
|
432
|
+
...(integratorId && { integratorId }),
|
|
433
|
+
}, facilitatorGroup);
|
|
434
|
+
// Get deposit parameters from order
|
|
435
|
+
const depositParams = orderResponse.transaction.metadata?.params;
|
|
436
|
+
if (!depositParams) {
|
|
437
|
+
throw new Error('Missing deposit parameters in order response');
|
|
438
|
+
}
|
|
439
|
+
// Execute bridge transaction
|
|
440
|
+
// Use EVM signer address for deposit calldata (matches Svelte's s0x_signer)
|
|
441
|
+
// Pass depositParams so executeBitcoinBridge can encode the actual deposit calldata
|
|
442
|
+
// Use usdcAmount from solveOptimalUsdcAmount (matches Svelte: zg_amount_src_usdc is passed directly)
|
|
443
|
+
const bridgeResult = await executeBitcoinBridge(sourceAsset, sourceAmount, usdcAmount, // Use amount from solveOptimalUsdcAmount (matches Svelte line 1028)
|
|
444
|
+
bitcoinSenderAddress, evmSignerAddress, // Use EVM signer address, not normalizedAddress
|
|
445
|
+
depositParams);
|
|
446
|
+
const resultOrderId = orderResponse.response.orderId;
|
|
447
|
+
// Note: setOrderId is not available in this function scope,
|
|
448
|
+
// but the orderId will be set by the calling executeSwap function
|
|
449
|
+
return {
|
|
450
|
+
orderId: resultOrderId,
|
|
451
|
+
viewingAuth,
|
|
452
|
+
depositTransaction: {
|
|
453
|
+
hash: bridgeResult.depositTxHash,
|
|
454
|
+
chainId: NI_CHAIN_ID_AVALANCHE,
|
|
455
|
+
status: 'confirmed',
|
|
456
|
+
confirmations: 1,
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
}
|
|
334
460
|
/**
|
|
335
461
|
* Execute EVM swap flow
|
|
336
462
|
*
|
|
@@ -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, EVM_PHONY_ADDRESS, SB58_ADDR_SOL_PROGRAM_SYSTEM, CALCULATION_DIRECTION_INPUT_TO_OUTPUT, CALCULATION_DIRECTION_OUTPUT_TO_INPUT, } from '@silentswap/sdk';
|
|
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, } from '@silentswap/sdk';
|
|
4
4
|
import { useQuote } from './useQuote.js';
|
|
5
5
|
/**
|
|
6
6
|
* Hook for fetching both ingress and egress estimates in parallel
|
|
@@ -27,6 +27,11 @@ export function useOrderEstimates({ evmAddress, solAddress, sourceAsset, maxImpa
|
|
|
27
27
|
if (sourceAsset.caip19.includes('solana')) {
|
|
28
28
|
return solAddress || SB58_ADDR_SOL_PROGRAM_SYSTEM;
|
|
29
29
|
}
|
|
30
|
+
else if (sourceAsset.caip19.includes('bip122')) {
|
|
31
|
+
// Bitcoin source - Bitcoin address not available in this hook, return undefined
|
|
32
|
+
// Note: Bitcoin addresses would need to be passed as a parameter to this hook
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
30
35
|
else {
|
|
31
36
|
return evmAddress || EVM_PHONY_ADDRESS;
|
|
32
37
|
}
|
|
@@ -114,7 +119,8 @@ export function useOrderEstimates({ evmAddress, solAddress, sourceAsset, maxImpa
|
|
|
114
119
|
// Parse source asset to get chain ID and token address from CAIP-19
|
|
115
120
|
console.log('[OrderEstimates] Step 3: Parsing source asset CAIP-19');
|
|
116
121
|
const isSourceSolana = isSolanaAsset(sourceAsset.caip19);
|
|
117
|
-
const
|
|
122
|
+
const isSourceBitcoin = isBitcoinAsset(sourceAsset.caip19);
|
|
123
|
+
const sourceEvmParsed = !isSourceSolana && !isSourceBitcoin ? parseEvmCaip19(sourceAsset.caip19) : null;
|
|
118
124
|
const sourceSolanaParsed = isSourceSolana ? parseSolanaCaip19(sourceAsset.caip19) : null;
|
|
119
125
|
const sourceChainId = sourceEvmParsed?.chainId ?? sourceSolanaParsed?.chainId ?? 0;
|
|
120
126
|
const sourceTokenAddress = isEvmNativeToken(sourceAsset.caip19)
|
|
@@ -122,7 +128,7 @@ export function useOrderEstimates({ evmAddress, solAddress, sourceAsset, maxImpa
|
|
|
122
128
|
: isSolanaNativeToken(sourceAsset.caip19)
|
|
123
129
|
? '11111111111111111111111111111111'
|
|
124
130
|
: (sourceEvmParsed?.tokenAddress ?? sourceSolanaParsed?.tokenAddress ?? '');
|
|
125
|
-
console.log('[OrderEstimates] Step 3: Source asset parsed', { sourceChainId, sourceTokenAddress, isSourceSolana });
|
|
131
|
+
console.log('[OrderEstimates] Step 3: Source asset parsed', { sourceChainId, sourceTokenAddress, isSourceSolana, isSourceBitcoin });
|
|
126
132
|
// For reverse calculation, calculate total output USD value first
|
|
127
133
|
let totalOutputUsd = 0;
|
|
128
134
|
let calculatedInputAmount = undefined;
|
|
@@ -173,7 +179,8 @@ export function useOrderEstimates({ evmAddress, solAddress, sourceAsset, maxImpa
|
|
|
173
179
|
Promise.all(destinationAssets.map((destAsset, idx) => {
|
|
174
180
|
// Parse destination asset to get chain ID and token address from CAIP-19
|
|
175
181
|
const isDestSolana = isSolanaAsset(destAsset.caip19);
|
|
176
|
-
const
|
|
182
|
+
const isDestBitcoin = isBitcoinAsset(destAsset.caip19);
|
|
183
|
+
const destEvmParsed = !isDestSolana && !isDestBitcoin ? parseEvmCaip19(destAsset.caip19) : null;
|
|
177
184
|
const destSolanaParsed = isDestSolana ? parseSolanaCaip19(destAsset.caip19) : null;
|
|
178
185
|
const destChainId = destEvmParsed?.chainId ?? destSolanaParsed?.chainId ?? 0;
|
|
179
186
|
const destTokenAddress = isEvmNativeToken(destAsset.caip19)
|
|
@@ -182,8 +189,9 @@ export function useOrderEstimates({ evmAddress, solAddress, sourceAsset, maxImpa
|
|
|
182
189
|
? '11111111111111111111111111111111'
|
|
183
190
|
: (destEvmParsed?.tokenAddress ?? destSolanaParsed?.tokenAddress ?? '');
|
|
184
191
|
// Determine recipient address based on destination chain
|
|
185
|
-
// For Solana destinations, use Solana address; for EVM, use EVM address
|
|
186
|
-
|
|
192
|
+
// For Solana destinations, use Solana address; for Bitcoin, use empty string (Bitcoin address not available in this hook); for EVM, use EVM address
|
|
193
|
+
// Note: Bitcoin addresses would need to be passed as a parameter to this hook if Bitcoin destinations are used
|
|
194
|
+
const recipientAddress = isDestSolana ? solAddress : isDestBitcoin ? '' : evmAddress;
|
|
187
195
|
// For reverse calculation, use output amount directly with EXACT_OUTPUT
|
|
188
196
|
if (calculationDirection === CALCULATION_DIRECTION_OUTPUT_TO_INPUT && outputAmounts && outputAmounts[idx]) {
|
|
189
197
|
const outputAmount = parseFloat(outputAmounts[idx]);
|
package/dist/hooks/useQuote.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import BigNumber from 'bignumber.js';
|
|
3
|
-
import { NI_CHAIN_ID_AVALANCHE, S0X_ADDR_USDC_AVALANCHE, S_CAIP19_USDC_AVALANCHE, X_MAX_IMPACT_PERCENT, getBridgeQuote as sdkGetBridgeQuote, interpolateSamples as sdkInterpolateSamples, fetchRelayQuote, fetchDebridgeOrder, normalizeAddress, getAssetByCaip19, N_DEBRIDGE_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_SOLANA, SB58_ADDR_SOL_PROGRAM_SYSTEM, S0X_ADDR_EVM_RELAY_LINK_DEAD, SB58_ADDR_SOL_RELAY_LINK_RECIPIENT, isSolanaAsset, EVM_PHONY_ADDRESS, } from '@silentswap/sdk';
|
|
3
|
+
import { NI_CHAIN_ID_AVALANCHE, S0X_ADDR_USDC_AVALANCHE, S_CAIP19_USDC_AVALANCHE, X_MAX_IMPACT_PERCENT, getBridgeQuote as sdkGetBridgeQuote, interpolateSamples as sdkInterpolateSamples, fetchRelayQuote, fetchDebridgeOrder, normalizeAddress, getAssetByCaip19, N_DEBRIDGE_CHAIN_ID_SOLANA, N_RELAY_CHAIN_ID_SOLANA, SB58_ADDR_SOL_PROGRAM_SYSTEM, S0X_ADDR_EVM_RELAY_LINK_DEAD, SB58_ADDR_SOL_RELAY_LINK_RECIPIENT, isSolanaAsset, isBitcoinAsset, EVM_PHONY_ADDRESS, } from '@silentswap/sdk';
|
|
4
4
|
// Constants for estimateLive
|
|
5
5
|
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
6
6
|
/**
|
|
@@ -316,6 +316,10 @@ export function useQuote({ address, maxImpactPercent = X_MAX_IMPACT_PERCENT } =
|
|
|
316
316
|
if (direction === 'egress') {
|
|
317
317
|
return null; // Skip DeBridge for egress, will use Relay.link only
|
|
318
318
|
}
|
|
319
|
+
// Skip DeBridge for Solana and Bitcoin - use relay only
|
|
320
|
+
if (isSolanaChain || isBitcoinAsset(assetCaip19)) {
|
|
321
|
+
return null; // Skip DeBridge for Solana and Bitcoin, will use Relay.link only
|
|
322
|
+
}
|
|
319
323
|
// For reverse calculation ingress: use srcChainTokenInAmount: 'auto' and specify dstChainTokenOutAmount
|
|
320
324
|
const debridgeParams = {
|
|
321
325
|
srcChainId: debridgeChainId,
|
package/dist/hooks/useSwap.js
CHANGED
|
@@ -13,7 +13,7 @@ export const DEFAULT_OUTPUT_ASSET = 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C3
|
|
|
13
13
|
export const getSourceAssetCaip19 = (tokenIn) => {
|
|
14
14
|
return tokenIn?.caip19 || DEFAULT_SOURCE_ASSET;
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
const useSwapStore = create()(persist((set, get) => ({
|
|
17
17
|
// Regular swap state
|
|
18
18
|
isAutoSlippage: true,
|
|
19
19
|
tokenIn: getAssetByCaip19(DEFAULT_SOURCE_ASSET) ?? null,
|
|
@@ -283,3 +283,9 @@ export const useSwap = create()(persist((set, get) => ({
|
|
|
283
283
|
};
|
|
284
284
|
},
|
|
285
285
|
}));
|
|
286
|
+
// Cache server snapshot for SSR compatibility
|
|
287
|
+
// This prevents the "getServerSnapshot should be cached" error in Next.js
|
|
288
|
+
if (typeof window === 'undefined') {
|
|
289
|
+
useSwapStore.getState(); // Cache the snapshot on server
|
|
290
|
+
}
|
|
291
|
+
export const useSwap = useSwapStore;
|
|
@@ -2,6 +2,7 @@ import type { Hex, WalletClient } from 'viem';
|
|
|
2
2
|
import type { Connector } from 'wagmi';
|
|
3
3
|
import type { BridgeProvider, BridgeQuote, BridgeStatus, OrderResponse } from '@silentswap/sdk';
|
|
4
4
|
import type { SolanaWalletConnector, SolanaConnection } from './silent/solana-transaction.js';
|
|
5
|
+
import type { BitcoinWalletConnector, BitcoinConnection } from './silent/bitcoin-transaction.js';
|
|
5
6
|
export interface useTransactionOptions {
|
|
6
7
|
/** User's EVM address */
|
|
7
8
|
address: `0x${string}`;
|
|
@@ -15,6 +16,10 @@ export interface useTransactionOptions {
|
|
|
15
16
|
solanaConnection?: SolanaConnection;
|
|
16
17
|
/** Solana RPC URL (optional, will create connection if not provided) */
|
|
17
18
|
solanaRpcUrl?: string;
|
|
19
|
+
/** Bitcoin wallet connector (required for Bitcoin transactions) */
|
|
20
|
+
bitcoinConnector?: BitcoinWalletConnector;
|
|
21
|
+
/** Bitcoin connection (optional, for consistency with Solana pattern) */
|
|
22
|
+
bitcoinConnection?: BitcoinConnection;
|
|
18
23
|
/** Optional callback to set current step (for external state management) */
|
|
19
24
|
setCurrentStep?: (step: string) => void;
|
|
20
25
|
/** Optional status update callback */
|
|
@@ -116,4 +121,4 @@ export interface useTransactionReturn {
|
|
|
116
121
|
* }
|
|
117
122
|
* ```
|
|
118
123
|
*/
|
|
119
|
-
export declare function useTransaction({ walletClient, connector, solanaConnector, solanaConnection, solanaRpcUrl, setCurrentStep: externalSetCurrentStep, onStatus: externalOnStatus, }: useTransactionOptions): useTransactionReturn;
|
|
124
|
+
export declare function useTransaction({ walletClient, connector, solanaConnector, solanaConnection, solanaRpcUrl, bitcoinConnector, bitcoinConnection, setCurrentStep: externalSetCurrentStep, onStatus: externalOnStatus, }: useTransactionOptions): useTransactionReturn;
|