@silentswap/vue 0.0.41
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/README.md +134 -0
- package/dist/composables/getQuote.d.ts +44 -0
- package/dist/composables/getQuote.js +405 -0
- package/dist/composables/getSilentSwapAuth.d.ts +12 -0
- package/dist/composables/getSilentSwapAuth.js +23 -0
- package/dist/composables/getSilentSwapClient.d.ts +14 -0
- package/dist/composables/getSilentSwapClient.js +16 -0
- package/dist/composables/getSilentSwapOrders.d.ts +20 -0
- package/dist/composables/getSilentSwapOrders.js +73 -0
- package/dist/composables/getTransaction.d.ts +26 -0
- package/dist/composables/getTransaction.js +82 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +5 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# @silentswap/vue
|
|
2
|
+
|
|
3
|
+
Vue 3 composables for integrating with SilentSwap SDK.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @silentswap/vue
|
|
9
|
+
# or
|
|
10
|
+
bun add @silentswap/vue
|
|
11
|
+
# or
|
|
12
|
+
yarn add @silentswap/vue
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
### getSilentSwapClient
|
|
18
|
+
|
|
19
|
+
Create and manage a SilentSwap client instance:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { getSilentSwapClient } from '@silentswap/vue';
|
|
23
|
+
|
|
24
|
+
const { client } = getSilentSwapClient({
|
|
25
|
+
config: {
|
|
26
|
+
baseUrl: 'https://api.silentswap.com',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### getSilentSwapAuth
|
|
32
|
+
|
|
33
|
+
Handle authentication utilities:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { getSilentSwapAuth } from '@silentswap/vue';
|
|
37
|
+
|
|
38
|
+
const {
|
|
39
|
+
createSignInMessage,
|
|
40
|
+
createEip712DocForOrder,
|
|
41
|
+
createEip712DocForWalletGeneration,
|
|
42
|
+
} = getSilentSwapAuth();
|
|
43
|
+
|
|
44
|
+
// Create a sign-in message
|
|
45
|
+
const message = createSignInMessage('0x...', 'nonce123', 'app.silentswap.com');
|
|
46
|
+
|
|
47
|
+
// Create EIP-712 document for order
|
|
48
|
+
const orderDoc = createEip712DocForOrder(quoteResponse);
|
|
49
|
+
|
|
50
|
+
// Create EIP-712 document for wallet generation
|
|
51
|
+
const walletDoc = createEip712DocForWalletGeneration('scope', 'token');
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### getSilentSwapOrders
|
|
55
|
+
|
|
56
|
+
Manage orders and related operations with reactive state:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { getSilentSwapOrders } from '@silentswap/vue';
|
|
60
|
+
|
|
61
|
+
const { client } = getSilentSwapClient({ config: yourConfig });
|
|
62
|
+
|
|
63
|
+
const {
|
|
64
|
+
isLoading,
|
|
65
|
+
error,
|
|
66
|
+
getNonce,
|
|
67
|
+
authenticate,
|
|
68
|
+
getQuote,
|
|
69
|
+
createOrder,
|
|
70
|
+
} = getSilentSwapOrders({ client });
|
|
71
|
+
|
|
72
|
+
// Get nonce for authentication
|
|
73
|
+
const nonce = await getNonce('0x...');
|
|
74
|
+
|
|
75
|
+
// Authenticate user
|
|
76
|
+
const authResult = await authenticate({
|
|
77
|
+
address: '0x...',
|
|
78
|
+
signature: '0x...',
|
|
79
|
+
message: '...',
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Get a quote
|
|
83
|
+
const quote = await getQuote({
|
|
84
|
+
sellToken: '0x...',
|
|
85
|
+
buyToken: '0x...',
|
|
86
|
+
sellAmount: '1000000000000000000',
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Create an order
|
|
90
|
+
const order = await createOrder({
|
|
91
|
+
quoteId: quote.quoteId,
|
|
92
|
+
signature: '0x...',
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API Reference
|
|
97
|
+
|
|
98
|
+
### getSilentSwapClient
|
|
99
|
+
|
|
100
|
+
#### Parameters
|
|
101
|
+
|
|
102
|
+
- `config: SilentSwapClientConfig` - Configuration for the SilentSwap client
|
|
103
|
+
|
|
104
|
+
#### Returns
|
|
105
|
+
|
|
106
|
+
- `client: SilentSwapClient` - The SilentSwap client instance
|
|
107
|
+
|
|
108
|
+
### getSilentSwapAuth
|
|
109
|
+
|
|
110
|
+
#### Returns
|
|
111
|
+
|
|
112
|
+
- `createSignInMessage(address, nonce, domain?)` - Create a sign-in message
|
|
113
|
+
- `createEip712DocForOrder(quoteResponse)` - Create EIP-712 typed data for order
|
|
114
|
+
- `createEip712DocForWalletGeneration(scope, token)` - Create EIP-712 typed data for wallet generation
|
|
115
|
+
|
|
116
|
+
### getSilentSwapOrders
|
|
117
|
+
|
|
118
|
+
#### Parameters
|
|
119
|
+
|
|
120
|
+
- `client: SilentSwapClient` - The SilentSwap client instance
|
|
121
|
+
|
|
122
|
+
#### Returns
|
|
123
|
+
|
|
124
|
+
- `isLoading: boolean` - Reactive loading state
|
|
125
|
+
- `error: Error | null` - Reactive error state
|
|
126
|
+
- `getNonce(address)` - Get nonce for authentication
|
|
127
|
+
- `authenticate(auth)` - Authenticate user
|
|
128
|
+
- `getQuote(quote)` - Get a quote
|
|
129
|
+
- `createOrder(order)` - Create an order
|
|
130
|
+
|
|
131
|
+
## Requirements
|
|
132
|
+
|
|
133
|
+
- Vue 3.0+
|
|
134
|
+
- TypeScript (recommended)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import type { Hex } from 'viem';
|
|
3
|
+
import type { BridgeProvider, RelayQuoteResponse, DeBridgeOrderResponse, SolveUsdcResult, EstimateSample, Estimate, BridgeQuoteResult } from '@silentswap/sdk';
|
|
4
|
+
export interface GetQuoteOptions {
|
|
5
|
+
/** User's EVM address */
|
|
6
|
+
address?: `0x${string}`;
|
|
7
|
+
/** Depositor address for bridge operations (required for solveUsdcAmount) */
|
|
8
|
+
depositorAddress: Hex;
|
|
9
|
+
/** Maximum price impact percentage allowed (default from SDK constants) */
|
|
10
|
+
maxImpactPercent?: number;
|
|
11
|
+
/** Timeout for quote requests in milliseconds (default: 30000) */
|
|
12
|
+
quoteTimeout?: number;
|
|
13
|
+
}
|
|
14
|
+
export type { RelayQuoteResponse, DeBridgeOrderResponse, SolveUsdcResult, EstimateSample, Estimate, BridgeQuoteResult, } from '@silentswap/sdk';
|
|
15
|
+
export type SolveResult = SolveUsdcResult;
|
|
16
|
+
/**
|
|
17
|
+
* Estimate result with quote details
|
|
18
|
+
*/
|
|
19
|
+
export interface EstimateResult {
|
|
20
|
+
/** Estimate data with samples */
|
|
21
|
+
estimate: Estimate;
|
|
22
|
+
/** Amount of gas needed on source chain */
|
|
23
|
+
gasAmount: bigint;
|
|
24
|
+
/** Raw response from provider */
|
|
25
|
+
response: RelayQuoteResponse | DeBridgeOrderResponse;
|
|
26
|
+
/** Bridge provider used */
|
|
27
|
+
provider: BridgeProvider;
|
|
28
|
+
/** Calculated input amount for reverse calculation (output-to-input) */
|
|
29
|
+
calculatedInputAmount?: number;
|
|
30
|
+
}
|
|
31
|
+
export interface GetQuoteReturn {
|
|
32
|
+
isLoading: Readonly<ReturnType<typeof ref<boolean>>>;
|
|
33
|
+
error: Readonly<ReturnType<typeof ref<Error | null>>>;
|
|
34
|
+
ingressEstimates: Readonly<ReturnType<typeof ref<Record<string, Estimate>>>>;
|
|
35
|
+
egressEstimates: Readonly<ReturnType<typeof ref<Record<string, Estimate>>>>;
|
|
36
|
+
getQuote: (srcChainId: number, srcToken: string, srcAmount: string, dstChainId: number, dstToken: string) => Promise<BridgeQuoteResult>;
|
|
37
|
+
solveUsdcAmount: (srcChainId: number, srcToken: string, srcAmount: string, depositCalldata?: string) => Promise<SolveResult>;
|
|
38
|
+
estimateLive: (direction: 'ingress' | 'egress', assetCaip19: string, chainId: number | string, tokenAddress: string, amount: number, usdPrice: number, externalSignal?: AbortSignal, recipientAddress?: string, isReverseCalculation?: boolean, targetAmount?: number) => Promise<EstimateResult>;
|
|
39
|
+
interpolateSamples: (samples: EstimateSample[], usdValue: number, marginHi?: number) => number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Vue composable for getting optimized bridge quotes from multiple providers
|
|
43
|
+
*/
|
|
44
|
+
export declare function getQuote({ address, depositorAddress, maxImpactPercent, quoteTimeout, }: GetQuoteOptions): GetQuoteReturn;
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import { ref, computed, onUnmounted } from 'vue';
|
|
2
|
+
import BigNumber from 'bignumber.js';
|
|
3
|
+
import { NI_CHAIN_ID_AVALANCHE, S0X_ADDR_USDC_AVALANCHE, S_CAIP19_USDC_AVALANCHE, X_MAX_IMPACT_PERCENT, solveOptimalUsdcAmount, 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, } from '@silentswap/sdk';
|
|
4
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
5
|
+
const EVM_PHONY_ADDRESS_FALLBACK = '0x1111111111111111111111111111111111111111';
|
|
6
|
+
/**
|
|
7
|
+
* Vue composable for getting optimized bridge quotes from multiple providers
|
|
8
|
+
*/
|
|
9
|
+
export function getQuote({ address, depositorAddress, maxImpactPercent = X_MAX_IMPACT_PERCENT, quoteTimeout = 30000, }) {
|
|
10
|
+
const isLoading = ref(false);
|
|
11
|
+
const error = ref(null);
|
|
12
|
+
// Estimates cache
|
|
13
|
+
const ingressEstimates = ref({});
|
|
14
|
+
const egressEstimates = ref({});
|
|
15
|
+
// Normalize address - handle both EVM (hex) and Solana (base58) addresses
|
|
16
|
+
const normalizedAddress = computed(() => address ? normalizeAddress(address) : null);
|
|
17
|
+
// Abort controller for cancelling requests
|
|
18
|
+
const abortControllerRef = ref(null);
|
|
19
|
+
// Cleanup on unmount
|
|
20
|
+
onUnmounted(() => {
|
|
21
|
+
if (abortControllerRef.value) {
|
|
22
|
+
abortControllerRef.value.abort();
|
|
23
|
+
abortControllerRef.value = null;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Cancel any ongoing requests and create a new abort controller
|
|
28
|
+
*/
|
|
29
|
+
const createNewAbortController = () => {
|
|
30
|
+
// Cancel previous request if any
|
|
31
|
+
if (abortControllerRef.value) {
|
|
32
|
+
abortControllerRef.value.abort();
|
|
33
|
+
}
|
|
34
|
+
// Create new abort controller
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
abortControllerRef.value = controller;
|
|
37
|
+
return controller;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Get quote for cross-chain swap
|
|
41
|
+
*/
|
|
42
|
+
const getQuoteFn = async (srcChainId, srcToken, srcAmount, dstChainId, dstToken) => {
|
|
43
|
+
if (!normalizedAddress.value) {
|
|
44
|
+
throw new Error('Address required for bridge quote operations');
|
|
45
|
+
}
|
|
46
|
+
isLoading.value = true;
|
|
47
|
+
error.value = null;
|
|
48
|
+
try {
|
|
49
|
+
// Normalize addresses
|
|
50
|
+
const srcTokenNorm = srcToken === '0x0' || srcToken === '0x0000000000000000000000000000000000000000'
|
|
51
|
+
? ZERO_ADDRESS
|
|
52
|
+
: srcToken;
|
|
53
|
+
const dstTokenNorm = dstToken === '0x0' || dstToken === '0x0000000000000000000000000000000000000000'
|
|
54
|
+
? ZERO_ADDRESS
|
|
55
|
+
: dstToken;
|
|
56
|
+
// Create abort controller for timeout
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
const timeoutId = setTimeout(() => controller.abort(), quoteTimeout);
|
|
59
|
+
try {
|
|
60
|
+
// Use shared quote fetching function
|
|
61
|
+
const result = await sdkGetBridgeQuote(srcChainId, srcTokenNorm, srcAmount, dstChainId, dstTokenNorm, normalizedAddress.value, controller.signal);
|
|
62
|
+
clearTimeout(timeoutId);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
clearTimeout(timeoutId);
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const errorInstance = err instanceof Error ? err : new Error('Failed to get quote');
|
|
72
|
+
error.value = errorInstance;
|
|
73
|
+
throw errorInstance;
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
isLoading.value = false;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Solve for optimal USDC amount
|
|
81
|
+
*/
|
|
82
|
+
const solveUsdcAmountFn = async (srcChainId, srcToken, srcAmount, depositCalldata) => {
|
|
83
|
+
isLoading.value = true;
|
|
84
|
+
error.value = null;
|
|
85
|
+
try {
|
|
86
|
+
if (!normalizedAddress.value) {
|
|
87
|
+
throw new Error('Address required for solving USDC amount');
|
|
88
|
+
}
|
|
89
|
+
const result = await solveOptimalUsdcAmount(srcChainId, srcToken, srcAmount, normalizedAddress.value, depositCalldata, maxImpactPercent, depositorAddress);
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
const errorInstance = err instanceof Error ? err : new Error('Failed to solve USDC amount');
|
|
94
|
+
error.value = errorInstance;
|
|
95
|
+
throw errorInstance;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
isLoading.value = false;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Get live estimate for a given asset and direction
|
|
103
|
+
*/
|
|
104
|
+
const estimateLiveFn = async (direction, assetCaip19, chainId, tokenAddress, amount, usdPrice, externalSignal, recipientAddress, isReverseCalculation, targetAmount) => {
|
|
105
|
+
// Determine if this is a Solana chain by checking the asset CAIP-19
|
|
106
|
+
const isSolanaChain = isSolanaAsset(assetCaip19);
|
|
107
|
+
let numericChainId;
|
|
108
|
+
if (isSolanaChain) {
|
|
109
|
+
numericChainId = 0; // Placeholder, will be set per provider
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
if (typeof chainId === 'string') {
|
|
113
|
+
const parsed = parseInt(chainId, 10);
|
|
114
|
+
if (isNaN(parsed)) {
|
|
115
|
+
throw new Error(`Invalid chain ID: ${chainId}`);
|
|
116
|
+
}
|
|
117
|
+
numericChainId = parsed;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
numericChainId = chainId;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (!normalizedAddress.value) {
|
|
124
|
+
throw new Error('Address required');
|
|
125
|
+
}
|
|
126
|
+
// Use external signal if provided, otherwise create new abort controller
|
|
127
|
+
let signal;
|
|
128
|
+
if (externalSignal) {
|
|
129
|
+
signal = externalSignal;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
const controller = createNewAbortController();
|
|
133
|
+
signal = controller.signal;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
// Special case for USDC on Avalanche
|
|
137
|
+
const checkChainId = isSolanaChain ? 0 : numericChainId;
|
|
138
|
+
if (checkChainId === NI_CHAIN_ID_AVALANCHE &&
|
|
139
|
+
tokenAddress.toLowerCase() === S0X_ADDR_USDC_AVALANCHE.toLowerCase()) {
|
|
140
|
+
const estimate = {
|
|
141
|
+
gasFee: 0,
|
|
142
|
+
samples: [
|
|
143
|
+
{
|
|
144
|
+
baseline: Infinity,
|
|
145
|
+
retention: 1,
|
|
146
|
+
source: 'none',
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
if (direction === 'ingress') {
|
|
151
|
+
ingressEstimates.value[assetCaip19] = estimate;
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
egressEstimates.value[assetCaip19] = estimate;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
estimate,
|
|
158
|
+
gasAmount: BigInt(BigNumber(300_000).times(2).shiftedBy(9).toFixed(0)),
|
|
159
|
+
response: {},
|
|
160
|
+
provider: 'relay',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
// Get asset info to determine correct decimals
|
|
164
|
+
const assetInfo = getAssetByCaip19(assetCaip19);
|
|
165
|
+
if (!assetInfo) {
|
|
166
|
+
throw new Error(`Asset not found: ${assetCaip19}`);
|
|
167
|
+
}
|
|
168
|
+
// Calculate amount in token units
|
|
169
|
+
const decimalsToUse = (direction === 'egress' && !isReverseCalculation)
|
|
170
|
+
? 6 // USDC has 6 decimals (for normal egress)
|
|
171
|
+
: assetInfo.decimals; // Use asset decimals (for ingress or reverse egress)
|
|
172
|
+
const tokenAmount = BigNumber(amount).shiftedBy(decimalsToUse).toFixed(0);
|
|
173
|
+
// Determine user address based on direction and chain
|
|
174
|
+
let userAddress;
|
|
175
|
+
if (direction === 'ingress') {
|
|
176
|
+
if (isSolanaChain) {
|
|
177
|
+
userAddress = normalizedAddress.value && !normalizedAddress.value.startsWith('0x')
|
|
178
|
+
? normalizedAddress.value
|
|
179
|
+
: SB58_ADDR_SOL_PROGRAM_SYSTEM;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
userAddress = normalizedAddress.value && normalizedAddress.value.startsWith('0x')
|
|
183
|
+
? normalizedAddress.value
|
|
184
|
+
: EVM_PHONY_ADDRESS_FALLBACK;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
userAddress = normalizedAddress.value && normalizedAddress.value.startsWith('0x')
|
|
189
|
+
? normalizedAddress.value
|
|
190
|
+
: EVM_PHONY_ADDRESS_FALLBACK;
|
|
191
|
+
}
|
|
192
|
+
// For Solana, use different chain IDs for different providers
|
|
193
|
+
const relayChainId = isSolanaChain ? N_RELAY_CHAIN_ID_SOLANA : numericChainId;
|
|
194
|
+
const debridgeChainId = isSolanaChain ? N_DEBRIDGE_CHAIN_ID_SOLANA : numericChainId;
|
|
195
|
+
// Fetch quotes from both providers
|
|
196
|
+
const [relayResult, debridgeResult] = await Promise.allSettled([
|
|
197
|
+
(async () => {
|
|
198
|
+
try {
|
|
199
|
+
const tradeType = isReverseCalculation ? 'EXACT_OUTPUT' : 'EXACT_INPUT';
|
|
200
|
+
let quoteAmount = tokenAmount;
|
|
201
|
+
if (isReverseCalculation && direction === 'ingress' && targetAmount) {
|
|
202
|
+
const usdcAsset = getAssetByCaip19(S_CAIP19_USDC_AVALANCHE);
|
|
203
|
+
if (usdcAsset) {
|
|
204
|
+
quoteAmount = BigNumber(targetAmount).shiftedBy(usdcAsset.decimals).toFixed(0);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
throw new Error('USDC asset not found');
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else if (isReverseCalculation && direction === 'egress' && targetAmount) {
|
|
211
|
+
quoteAmount = tokenAmount;
|
|
212
|
+
}
|
|
213
|
+
const quote = await fetchRelayQuote({
|
|
214
|
+
user: userAddress,
|
|
215
|
+
referrer: 'silentswap',
|
|
216
|
+
tradeType,
|
|
217
|
+
...(direction === 'ingress'
|
|
218
|
+
? {
|
|
219
|
+
originChainId: relayChainId,
|
|
220
|
+
destinationChainId: NI_CHAIN_ID_AVALANCHE,
|
|
221
|
+
originCurrency: tokenAddress === ZERO_ADDRESS ? ZERO_ADDRESS : tokenAddress,
|
|
222
|
+
destinationCurrency: S0X_ADDR_USDC_AVALANCHE,
|
|
223
|
+
...(isReverseCalculation && tradeType === 'EXACT_OUTPUT'
|
|
224
|
+
? { amount: quoteAmount }
|
|
225
|
+
: { amount: tokenAmount }),
|
|
226
|
+
...(isSolanaChain
|
|
227
|
+
? { recipient: EVM_PHONY_ADDRESS_FALLBACK }
|
|
228
|
+
: {}),
|
|
229
|
+
}
|
|
230
|
+
: {
|
|
231
|
+
originChainId: NI_CHAIN_ID_AVALANCHE,
|
|
232
|
+
originCurrency: S0X_ADDR_USDC_AVALANCHE,
|
|
233
|
+
destinationChainId: relayChainId,
|
|
234
|
+
destinationCurrency: tokenAddress === ZERO_ADDRESS ? ZERO_ADDRESS : tokenAddress,
|
|
235
|
+
...(isReverseCalculation && tradeType === 'EXACT_OUTPUT'
|
|
236
|
+
? { amount: quoteAmount }
|
|
237
|
+
: { amount: tokenAmount }),
|
|
238
|
+
...(isSolanaChain
|
|
239
|
+
? {
|
|
240
|
+
user: S0X_ADDR_EVM_RELAY_LINK_DEAD,
|
|
241
|
+
recipient: recipientAddress || SB58_ADDR_SOL_RELAY_LINK_RECIPIENT,
|
|
242
|
+
}
|
|
243
|
+
: {}),
|
|
244
|
+
}),
|
|
245
|
+
}, signal);
|
|
246
|
+
return quote;
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
if (err instanceof Error && err.name !== 'AbortError') {
|
|
250
|
+
console.warn('Relay quote failed:', err);
|
|
251
|
+
}
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
})(),
|
|
255
|
+
(async () => {
|
|
256
|
+
try {
|
|
257
|
+
if (direction === 'egress') {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
const debridgeParams = {
|
|
261
|
+
srcChainId: debridgeChainId,
|
|
262
|
+
srcChainTokenIn: tokenAddress === ZERO_ADDRESS ? ZERO_ADDRESS : tokenAddress,
|
|
263
|
+
dstChainId: NI_CHAIN_ID_AVALANCHE,
|
|
264
|
+
dstChainTokenOut: S0X_ADDR_USDC_AVALANCHE,
|
|
265
|
+
};
|
|
266
|
+
if (isReverseCalculation && direction === 'ingress' && targetAmount) {
|
|
267
|
+
const usdcAsset = getAssetByCaip19(S_CAIP19_USDC_AVALANCHE);
|
|
268
|
+
if (usdcAsset) {
|
|
269
|
+
debridgeParams.srcChainTokenInAmount = 'auto';
|
|
270
|
+
debridgeParams.dstChainTokenOutAmount = BigNumber(targetAmount)
|
|
271
|
+
.shiftedBy(usdcAsset.decimals)
|
|
272
|
+
.toFixed(0);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
throw new Error('USDC asset not found');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
debridgeParams.srcChainTokenInAmount = tokenAmount;
|
|
280
|
+
debridgeParams.dstChainTokenOutAmount = 'auto';
|
|
281
|
+
}
|
|
282
|
+
const quote = await fetchDebridgeOrder(debridgeParams, signal);
|
|
283
|
+
return quote;
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
if (err instanceof Error && err.name !== 'AbortError') {
|
|
287
|
+
console.warn('DeBridge quote failed:', err);
|
|
288
|
+
}
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
})(),
|
|
292
|
+
]);
|
|
293
|
+
const relayQuote = relayResult.status === 'fulfilled' ? relayResult.value : null;
|
|
294
|
+
const debridgeQuote = debridgeResult.status === 'fulfilled' ? debridgeResult.value : null;
|
|
295
|
+
if (!relayQuote && !debridgeQuote) {
|
|
296
|
+
throw new AggregateError([
|
|
297
|
+
relayResult.status === 'rejected' ? relayResult.reason : null,
|
|
298
|
+
debridgeResult.status === 'rejected' ? debridgeResult.reason : null,
|
|
299
|
+
].filter(Boolean), 'All quote providers failed');
|
|
300
|
+
}
|
|
301
|
+
// Calculate retention rates
|
|
302
|
+
let retentionRelay = 0;
|
|
303
|
+
let retentionDebridge = 0;
|
|
304
|
+
let gasAmountRelay = 0n;
|
|
305
|
+
let gasAmountDebridge = 0n;
|
|
306
|
+
let gasFeeUsd = 0;
|
|
307
|
+
let calculatedInputAmount = undefined;
|
|
308
|
+
if (relayQuote) {
|
|
309
|
+
if (isReverseCalculation && direction === 'ingress') {
|
|
310
|
+
calculatedInputAmount = Number(relayQuote.details.currencyIn.amount);
|
|
311
|
+
if (!calculatedInputAmount) {
|
|
312
|
+
const calculatedInputAmountUsd = Number(relayQuote.details.currencyIn.amountUsd || 0);
|
|
313
|
+
if (calculatedInputAmountUsd > 0 && usdPrice > 0) {
|
|
314
|
+
calculatedInputAmount = calculatedInputAmountUsd / usdPrice;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
retentionRelay = BigNumber(relayQuote.details.currencyOut.amountUsd)
|
|
318
|
+
.div(relayQuote.details.currencyIn.amountUsd)
|
|
319
|
+
.toNumber();
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
retentionRelay = BigNumber(relayQuote.details.currencyOut.amountUsd)
|
|
323
|
+
.div(relayQuote.details.currencyIn.amountUsd)
|
|
324
|
+
.toNumber();
|
|
325
|
+
}
|
|
326
|
+
gasFeeUsd = Number(relayQuote.fees.relayerGas.amountUsd || '0');
|
|
327
|
+
gasAmountRelay = BigInt((BigInt(relayQuote.fees.gas.amount || 0) * 15n) / 10n);
|
|
328
|
+
}
|
|
329
|
+
if (debridgeQuote) {
|
|
330
|
+
if (isReverseCalculation && direction === 'ingress') {
|
|
331
|
+
calculatedInputAmount = Number(debridgeQuote.estimation.srcChainTokenIn.amount);
|
|
332
|
+
if (!calculatedInputAmount) {
|
|
333
|
+
const calculatedInputAmountUsd = Number(debridgeQuote.estimation.srcChainTokenIn.approximateUsdValue || 0);
|
|
334
|
+
if (calculatedInputAmountUsd > 0 && usdPrice > 0) {
|
|
335
|
+
calculatedInputAmount = calculatedInputAmountUsd / usdPrice;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
retentionDebridge = BigNumber(debridgeQuote.estimation.dstChainTokenOut.approximateUsdValue)
|
|
339
|
+
.div(debridgeQuote.estimation.srcChainTokenIn.approximateUsdValue)
|
|
340
|
+
.toNumber();
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
retentionDebridge = BigNumber(debridgeQuote.estimation.dstChainTokenOut.approximateUsdValue)
|
|
344
|
+
.div(debridgeQuote.estimation.srcChainTokenIn.approximateUsdValue)
|
|
345
|
+
.toNumber();
|
|
346
|
+
}
|
|
347
|
+
gasFeeUsd =
|
|
348
|
+
debridgeQuote.estimation.costDetails?.reduce((sum, detail) => sum + Number(detail.payload?.feeApproximateUsdValue || 0), 0) || 0;
|
|
349
|
+
gasAmountDebridge = BigInt((BigInt(debridgeQuote.estimatedTransactionFee?.total || 0) * 15n) / 10n);
|
|
350
|
+
}
|
|
351
|
+
// Determine best source
|
|
352
|
+
const retention = Math.max(retentionRelay, retentionDebridge);
|
|
353
|
+
const source = retentionRelay >= retentionDebridge ? 'relay' : 'debridge';
|
|
354
|
+
const usdValue = BigNumber(usdPrice).times(amount).toNumber();
|
|
355
|
+
// Create sample
|
|
356
|
+
const sample = {
|
|
357
|
+
baseline: usdValue,
|
|
358
|
+
retention,
|
|
359
|
+
source,
|
|
360
|
+
};
|
|
361
|
+
// Update estimates cache
|
|
362
|
+
const estimatesCache = direction === 'ingress' ? ingressEstimates.value : egressEstimates.value;
|
|
363
|
+
const existingEstimate = estimatesCache[assetCaip19];
|
|
364
|
+
// Filter out samples within $5 of this price
|
|
365
|
+
const filteredSamples = (existingEstimate?.samples || []).filter((s) => !(s.baseline >= sample.baseline - 5 && s.baseline <= sample.baseline + 5));
|
|
366
|
+
// Add new sample and sort
|
|
367
|
+
const samples = [...filteredSamples, sample].sort((a, b) => a.baseline - b.baseline);
|
|
368
|
+
const estimate = {
|
|
369
|
+
gasFee: direction === 'ingress' ? 0 : gasFeeUsd,
|
|
370
|
+
samples,
|
|
371
|
+
};
|
|
372
|
+
estimatesCache[assetCaip19] = estimate;
|
|
373
|
+
return {
|
|
374
|
+
estimate,
|
|
375
|
+
gasAmount: source === 'relay' ? gasAmountRelay : gasAmountDebridge,
|
|
376
|
+
response: (source === 'relay' ? relayQuote : debridgeQuote),
|
|
377
|
+
provider: source,
|
|
378
|
+
calculatedInputAmount,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
383
|
+
throw err;
|
|
384
|
+
}
|
|
385
|
+
const errorInstance = err instanceof Error ? err : new Error('Failed to get live estimate');
|
|
386
|
+
throw errorInstance;
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
/**
|
|
390
|
+
* Interpolate retention rate from samples
|
|
391
|
+
*/
|
|
392
|
+
const interpolateSamplesFn = (samples, usdValue, marginHi = Infinity) => {
|
|
393
|
+
return sdkInterpolateSamples(samples, usdValue, marginHi);
|
|
394
|
+
};
|
|
395
|
+
return {
|
|
396
|
+
isLoading: computed(() => isLoading.value),
|
|
397
|
+
error: computed(() => error.value),
|
|
398
|
+
ingressEstimates: computed(() => ingressEstimates.value),
|
|
399
|
+
egressEstimates: computed(() => egressEstimates.value),
|
|
400
|
+
getQuote: getQuoteFn,
|
|
401
|
+
solveUsdcAmount: solveUsdcAmountFn,
|
|
402
|
+
estimateLive: estimateLiveFn,
|
|
403
|
+
interpolateSamples: interpolateSamplesFn,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createEip712DocForOrder, createEip712DocForWalletGeneration, type QuoteResponse } from '@silentswap/sdk';
|
|
2
|
+
export interface GetSilentSwapAuthReturn {
|
|
3
|
+
createSignInMessage: (address: `0x${string}`, nonce: string, domain?: string) => string;
|
|
4
|
+
createEip712DocForOrder: (quoteResponse: QuoteResponse) => ReturnType<typeof createEip712DocForOrder>;
|
|
5
|
+
createEip712DocForWalletGeneration: (scope: string, token: string) => ReturnType<typeof createEip712DocForWalletGeneration>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Vue composable for SilentSwap authentication utilities
|
|
9
|
+
*
|
|
10
|
+
* @returns Object with authentication utility functions
|
|
11
|
+
*/
|
|
12
|
+
export declare function getSilentSwapAuth(): GetSilentSwapAuthReturn;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createSignInMessage, createEip712DocForOrder, createEip712DocForWalletGeneration, } from '@silentswap/sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Vue composable for SilentSwap authentication utilities
|
|
4
|
+
*
|
|
5
|
+
* @returns Object with authentication utility functions
|
|
6
|
+
*/
|
|
7
|
+
export function getSilentSwapAuth() {
|
|
8
|
+
const createSignInMessageFn = (address, nonce, domain) => {
|
|
9
|
+
const signInMessage = createSignInMessage(address, nonce, domain);
|
|
10
|
+
return signInMessage.message;
|
|
11
|
+
};
|
|
12
|
+
const createEip712DocForOrderFn = (quoteResponse) => {
|
|
13
|
+
return createEip712DocForOrder(quoteResponse);
|
|
14
|
+
};
|
|
15
|
+
const createEip712DocForWalletGenerationFn = (scope, token) => {
|
|
16
|
+
return createEip712DocForWalletGeneration(scope, token);
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
createSignInMessage: createSignInMessageFn,
|
|
20
|
+
createEip712DocForOrder: createEip712DocForOrderFn,
|
|
21
|
+
createEip712DocForWalletGeneration: createEip712DocForWalletGenerationFn,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type SilentSwapClient, type SilentSwapClientConfig } from '@silentswap/sdk';
|
|
2
|
+
export interface GetSilentSwapClientOptions {
|
|
3
|
+
config: SilentSwapClientConfig;
|
|
4
|
+
}
|
|
5
|
+
export interface GetSilentSwapClientReturn {
|
|
6
|
+
client: SilentSwapClient;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Vue composable for creating and managing a SilentSwap client instance
|
|
10
|
+
*
|
|
11
|
+
* @param options - Configuration options for the client
|
|
12
|
+
* @returns Object containing the SilentSwap client instance
|
|
13
|
+
*/
|
|
14
|
+
export declare function getSilentSwapClient({ config, }: GetSilentSwapClientOptions): GetSilentSwapClientReturn;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { computed } from 'vue';
|
|
2
|
+
import { createSilentSwapClient, } from '@silentswap/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Vue composable for creating and managing a SilentSwap client instance
|
|
5
|
+
*
|
|
6
|
+
* @param options - Configuration options for the client
|
|
7
|
+
* @returns Object containing the SilentSwap client instance
|
|
8
|
+
*/
|
|
9
|
+
export function getSilentSwapClient({ config, }) {
|
|
10
|
+
const client = computed(() => {
|
|
11
|
+
return createSilentSwapClient(config);
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
client: client.value,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import type { SilentSwapClient, AuthRequest, AuthResponse, NonceResponse, OrderRequest, OrderResponse, QuoteRequest, QuoteResponse } from '@silentswap/sdk';
|
|
3
|
+
export interface GetSilentSwapOrdersOptions {
|
|
4
|
+
client: SilentSwapClient;
|
|
5
|
+
}
|
|
6
|
+
export interface GetSilentSwapOrdersReturn {
|
|
7
|
+
isLoading: Readonly<ReturnType<typeof ref<boolean>>>;
|
|
8
|
+
error: Readonly<ReturnType<typeof ref<Error | null>>>;
|
|
9
|
+
getNonce: (address: `0x${string}`) => Promise<NonceResponse | null>;
|
|
10
|
+
authenticate: (auth: AuthRequest) => Promise<AuthResponse | null>;
|
|
11
|
+
getQuote: (quote: QuoteRequest) => Promise<QuoteResponse | null>;
|
|
12
|
+
createOrder: (order: OrderRequest) => Promise<OrderResponse | null>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Vue composable for managing SilentSwap orders and related operations
|
|
16
|
+
*
|
|
17
|
+
* @param options - Options containing the SilentSwap client
|
|
18
|
+
* @returns Object with order management methods and state
|
|
19
|
+
*/
|
|
20
|
+
export declare function getSilentSwapOrders({ client, }: GetSilentSwapOrdersOptions): GetSilentSwapOrdersReturn;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ref, computed } from 'vue';
|
|
2
|
+
/**
|
|
3
|
+
* Vue composable for managing SilentSwap orders and related operations
|
|
4
|
+
*
|
|
5
|
+
* @param options - Options containing the SilentSwap client
|
|
6
|
+
* @returns Object with order management methods and state
|
|
7
|
+
*/
|
|
8
|
+
export function getSilentSwapOrders({ client, }) {
|
|
9
|
+
const isLoading = ref(false);
|
|
10
|
+
const error = ref(null);
|
|
11
|
+
const handleAsyncOperation = async (operation, errorMessage) => {
|
|
12
|
+
isLoading.value = true;
|
|
13
|
+
error.value = null;
|
|
14
|
+
try {
|
|
15
|
+
const result = await operation();
|
|
16
|
+
return result ?? null;
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const errorInstance = err instanceof Error ? err : new Error(errorMessage);
|
|
20
|
+
error.value = errorInstance;
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
isLoading.value = false;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const getNonce = async (address) => {
|
|
28
|
+
return handleAsyncOperation(async () => {
|
|
29
|
+
const [error, response] = await client.nonce(address);
|
|
30
|
+
if (error) {
|
|
31
|
+
throw new Error(`Failed to get nonce: ${error.error}`);
|
|
32
|
+
}
|
|
33
|
+
return response;
|
|
34
|
+
}, 'Failed to fetch nonce');
|
|
35
|
+
};
|
|
36
|
+
const authenticate = async (auth) => {
|
|
37
|
+
return handleAsyncOperation(async () => {
|
|
38
|
+
const [error, response] = await client.authenticate(auth);
|
|
39
|
+
if (error) {
|
|
40
|
+
throw new Error(`Authentication failed: ${error.error}`);
|
|
41
|
+
}
|
|
42
|
+
return response;
|
|
43
|
+
}, 'Authentication failed');
|
|
44
|
+
};
|
|
45
|
+
const getQuote = async (quote) => {
|
|
46
|
+
return handleAsyncOperation(async () => {
|
|
47
|
+
const [error, response] = await client.quote(quote);
|
|
48
|
+
if (error) {
|
|
49
|
+
throw new Error(`Failed to get quote: ${error.error}`);
|
|
50
|
+
}
|
|
51
|
+
return response;
|
|
52
|
+
}, 'Failed to fetch quote');
|
|
53
|
+
};
|
|
54
|
+
const createOrder = async (order) => {
|
|
55
|
+
return handleAsyncOperation(async () => {
|
|
56
|
+
const [error, response] = await client.order(order);
|
|
57
|
+
if (error) {
|
|
58
|
+
throw new Error(`Failed to create order: ${error.error}`);
|
|
59
|
+
}
|
|
60
|
+
return response;
|
|
61
|
+
}, 'Failed to create order');
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
// State
|
|
65
|
+
isLoading: computed(() => isLoading.value),
|
|
66
|
+
error: computed(() => error.value),
|
|
67
|
+
// Methods
|
|
68
|
+
getNonce,
|
|
69
|
+
authenticate,
|
|
70
|
+
getQuote,
|
|
71
|
+
createOrder,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import type { WalletClient } from 'viem';
|
|
3
|
+
import type { Connector } from 'wagmi';
|
|
4
|
+
import type { BridgeProvider, BridgeQuote, BridgeStatus } from '@silentswap/sdk';
|
|
5
|
+
export interface GetTransactionOptions {
|
|
6
|
+
/** User's EVM address */
|
|
7
|
+
address: `0x${string}`;
|
|
8
|
+
/** Wallet client for signing operations */
|
|
9
|
+
walletClient?: WalletClient;
|
|
10
|
+
/** Wagmi connector */
|
|
11
|
+
connector?: Connector;
|
|
12
|
+
}
|
|
13
|
+
export interface GetTransactionReturn {
|
|
14
|
+
isLoading: Readonly<ReturnType<typeof ref<boolean>>>;
|
|
15
|
+
currentStep: Readonly<ReturnType<typeof ref<string>>>;
|
|
16
|
+
error: Readonly<ReturnType<typeof ref<Error | null>>>;
|
|
17
|
+
executeTransaction: (quote: BridgeQuote) => Promise<BridgeStatus | null>;
|
|
18
|
+
getStatus: (requestId: string, provider: BridgeProvider) => Promise<BridgeStatus | null>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Vue composable for executing bridge transactions
|
|
22
|
+
*
|
|
23
|
+
* This composable provides transaction execution for bridge quotes from any provider.
|
|
24
|
+
* It handles chain switching and transaction sending automatically.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getTransaction({ address, walletClient, connector, }: GetTransactionOptions): GetTransactionReturn;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ref, computed } from 'vue';
|
|
2
|
+
import { executeRelayBridge, executeDebridgeBridge, getBridgeStatus, createTransactionExecutor, createChainSwitcher, } from '@silentswap/sdk';
|
|
3
|
+
/**
|
|
4
|
+
* Vue composable for executing bridge transactions
|
|
5
|
+
*
|
|
6
|
+
* This composable provides transaction execution for bridge quotes from any provider.
|
|
7
|
+
* It handles chain switching and transaction sending automatically.
|
|
8
|
+
*/
|
|
9
|
+
export function getTransaction({ address, walletClient, connector, }) {
|
|
10
|
+
const isLoading = ref(false);
|
|
11
|
+
const currentStep = ref('');
|
|
12
|
+
const error = ref(null);
|
|
13
|
+
/**
|
|
14
|
+
* Execute a bridge transaction
|
|
15
|
+
*/
|
|
16
|
+
const executeTransaction = async (quote) => {
|
|
17
|
+
if (!walletClient) {
|
|
18
|
+
throw new Error('Wallet client required for bridge execution');
|
|
19
|
+
}
|
|
20
|
+
if (!connector) {
|
|
21
|
+
throw new Error('Connector required for bridge execution');
|
|
22
|
+
}
|
|
23
|
+
isLoading.value = true;
|
|
24
|
+
error.value = null;
|
|
25
|
+
currentStep.value = '';
|
|
26
|
+
try {
|
|
27
|
+
// Create wrapper functions using shared utilities
|
|
28
|
+
const executeTransaction = createTransactionExecutor(walletClient, connector);
|
|
29
|
+
const switchChain = createChainSwitcher(walletClient, connector);
|
|
30
|
+
// Execute based on provider
|
|
31
|
+
switch (quote.provider) {
|
|
32
|
+
case 'relay':
|
|
33
|
+
return await executeRelayBridge(quote, executeTransaction, switchChain, (step) => {
|
|
34
|
+
currentStep.value = step;
|
|
35
|
+
});
|
|
36
|
+
case 'debridge':
|
|
37
|
+
return await executeDebridgeBridge(quote, executeTransaction, switchChain, (step) => {
|
|
38
|
+
currentStep.value = step;
|
|
39
|
+
});
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unsupported bridge provider: ${quote.provider}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
const errorInstance = err instanceof Error ? err : new Error('Bridge execution failed');
|
|
46
|
+
error.value = errorInstance;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
isLoading.value = false;
|
|
51
|
+
currentStep.value = '';
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Get bridge status for a request
|
|
56
|
+
*/
|
|
57
|
+
const getStatus = async (requestId, provider) => {
|
|
58
|
+
isLoading.value = true;
|
|
59
|
+
currentStep.value = 'Checking bridge status';
|
|
60
|
+
error.value = null;
|
|
61
|
+
try {
|
|
62
|
+
// Use shared status function
|
|
63
|
+
return await getBridgeStatus(requestId, provider);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const errorInstance = err instanceof Error ? err : new Error('Failed to get bridge status');
|
|
67
|
+
error.value = errorInstance;
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
isLoading.value = false;
|
|
72
|
+
currentStep.value = '';
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
isLoading: computed(() => isLoading.value),
|
|
77
|
+
currentStep: computed(() => currentStep.value),
|
|
78
|
+
error: computed(() => error.value),
|
|
79
|
+
executeTransaction,
|
|
80
|
+
getStatus,
|
|
81
|
+
};
|
|
82
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { getSilentSwapClient } from './composables/getSilentSwapClient.js';
|
|
2
|
+
export { getSilentSwapOrders } from './composables/getSilentSwapOrders.js';
|
|
3
|
+
export { getSilentSwapAuth } from './composables/getSilentSwapAuth.js';
|
|
4
|
+
export { getQuote } from './composables/getQuote.js';
|
|
5
|
+
export { getTransaction } from './composables/getTransaction.js';
|
|
6
|
+
export type { SilentSwapClientConfig } from '@silentswap/sdk';
|
|
7
|
+
export type { GetQuoteOptions, GetQuoteReturn, BridgeQuoteResult, EstimateResult, EstimateSample, Estimate, SolveResult, } from './composables/getQuote.js';
|
|
8
|
+
export type { GetTransactionOptions, GetTransactionReturn, } from './composables/getTransaction.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { getSilentSwapClient } from './composables/getSilentSwapClient.js';
|
|
2
|
+
export { getSilentSwapOrders } from './composables/getSilentSwapOrders.js';
|
|
3
|
+
export { getSilentSwapAuth } from './composables/getSilentSwapAuth.js';
|
|
4
|
+
export { getQuote } from './composables/getQuote.js';
|
|
5
|
+
export { getTransaction } from './composables/getTransaction.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@silentswap/vue",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.41",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"clean": "rm -rf dist",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"lint": "eslint src --ext .ts",
|
|
16
|
+
"lint:fix": "eslint src --ext .ts --fix"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"vue": ">=3.0.0",
|
|
20
|
+
"viem": "2.43.3",
|
|
21
|
+
"wagmi": "3.1.3"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@silentswap/sdk": "workspace:*",
|
|
25
|
+
"bignumber.js": "9.3.1"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@eslint/js": "9.38.0",
|
|
29
|
+
"@stylistic/eslint-plugin": "5.5.0",
|
|
30
|
+
"@tsconfig/node24": "24.0.1",
|
|
31
|
+
"@types/node": "24.9.1",
|
|
32
|
+
"@types/web": "0.0.283",
|
|
33
|
+
"@typescript-eslint/parser": "8.46.2",
|
|
34
|
+
"eslint": "9.38.0",
|
|
35
|
+
"eslint-import-resolver-typescript": "4.4.4",
|
|
36
|
+
"eslint-plugin-import-x": "4.16.1",
|
|
37
|
+
"typescript": "5.9.3",
|
|
38
|
+
"typescript-eslint": "8.46.2",
|
|
39
|
+
"vue": "3.4.0"
|
|
40
|
+
}
|
|
41
|
+
}
|