@shogun-sdk/swap 0.1.0
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 +274 -0
- package/dist/esm/client/SwapClient.js +351 -0
- package/dist/esm/client/SwapClient.js.map +1 -0
- package/dist/esm/examples/usage.js +239 -0
- package/dist/esm/examples/usage.js.map +1 -0
- package/dist/esm/index.js +11 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types/index.js +5 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/utils/index.js +60 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/dist/types/client/SwapClient.d.ts +159 -0
- package/dist/types/client/SwapClient.d.ts.map +1 -0
- package/dist/types/examples/usage.d.ts +17 -0
- package/dist/types/examples/usage.d.ts.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types/index.d.ts +34 -0
- package/dist/types/types/index.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +27 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/package.json +58 -0
- package/src/client/SwapClient.ts +490 -0
- package/src/examples/usage.ts +261 -0
- package/src/index.ts +12 -0
- package/src/types/index.ts +36 -0
- package/src/utils/index.ts +77 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage examples for SwapClient
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { SwapClient, type SwapClientConfig, type UnifiedQuoteParams } from '../client/SwapClient.js';
|
|
6
|
+
import { ChainID } from '@shogun-sdk/intents-sdk';
|
|
7
|
+
|
|
8
|
+
// Example configuration with enhanced options
|
|
9
|
+
const config: SwapClientConfig = {
|
|
10
|
+
apiKey: 'your-api-key-here',
|
|
11
|
+
apiUrl: 'https://api.shogun.network',
|
|
12
|
+
timeout: 30000, // 30 seconds
|
|
13
|
+
maxRetries: 3, // Retry failed requests up to 3 times
|
|
14
|
+
retryDelay: 1000, // Wait 1 second between retries
|
|
15
|
+
debug: true, // Enable debug logging
|
|
16
|
+
preferIntentsSdk: true, // Try intents-sdk first
|
|
17
|
+
headers: {
|
|
18
|
+
'User-Agent': 'MyApp/1.0.0'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Create the client
|
|
23
|
+
const swapClient = new SwapClient(config);
|
|
24
|
+
|
|
25
|
+
// Example 1: Cross-chain swap quote
|
|
26
|
+
export async function getCrossChainQuote() {
|
|
27
|
+
const params: UnifiedQuoteParams = {
|
|
28
|
+
sourceChainId: ChainID.Arbitrum,
|
|
29
|
+
destChainId: ChainID.Arbitrum,
|
|
30
|
+
tokenIn: '0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C', // USDC on Ethereum
|
|
31
|
+
tokenOut: '0x1234567890123456789012345678901234567890', // Some token on Arbitrum
|
|
32
|
+
amount: BigInt('1000000'), // 1 USDC (6 decimals)
|
|
33
|
+
senderAddress: '0x1234567890123456789012345678901234567890',
|
|
34
|
+
destinationAddress: '0x1234567890123456789012345678901234567890',
|
|
35
|
+
slippageBps: 50, // 0.5% slippage
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const quote = await swapClient.getQuote(params);
|
|
40
|
+
console.log('Cross-chain quote:', quote);
|
|
41
|
+
return quote;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Failed to get cross-chain quote:', error);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Example 2: Single-chain swap quote
|
|
49
|
+
export async function getSingleChainQuote() {
|
|
50
|
+
try {
|
|
51
|
+
const quote = await swapClient.getSingleChainQuote(
|
|
52
|
+
ChainID.Arbitrum,
|
|
53
|
+
'0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C', // USDC
|
|
54
|
+
'0x1234567890123456789012345678901234567890', // Some other token
|
|
55
|
+
BigInt('1000000'), // 1 USDC
|
|
56
|
+
50 // 0.5% slippage
|
|
57
|
+
);
|
|
58
|
+
console.log('Single-chain quote:', quote);
|
|
59
|
+
return quote;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Failed to get single-chain quote:', error);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Example 3: Solana swap with Jito tip
|
|
67
|
+
export async function getSolanaSwapQuote() {
|
|
68
|
+
const params: UnifiedQuoteParams = {
|
|
69
|
+
sourceChainId: ChainID.Solana,
|
|
70
|
+
destChainId: ChainID.Solana,
|
|
71
|
+
tokenIn: 'So11111111111111111111111111111111111111112', // SOL
|
|
72
|
+
tokenOut: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v', // USDC
|
|
73
|
+
amount: BigInt('1000000000'), // 1 SOL (9 decimals)
|
|
74
|
+
senderAddress: 'YourSolanaWalletAddress',
|
|
75
|
+
destinationAddress: 'YourSolanaWalletAddress',
|
|
76
|
+
slippageBps: 100, // 1% slippage
|
|
77
|
+
jitoTip: 1000000, // 0.001 SOL tip
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const quote = await swapClient.getQuote(params);
|
|
82
|
+
console.log('Solana swap quote:', quote);
|
|
83
|
+
return quote;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error('Failed to get Solana swap quote:', error);
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Example 4: Using with AbortSignal for timeout control
|
|
91
|
+
export async function getQuoteWithTimeout() {
|
|
92
|
+
const controller = new AbortController();
|
|
93
|
+
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout
|
|
94
|
+
|
|
95
|
+
const params: UnifiedQuoteParams = {
|
|
96
|
+
sourceChainId: ChainID.Arbitrum,
|
|
97
|
+
destChainId: ChainID.Base,
|
|
98
|
+
tokenIn: '0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C',
|
|
99
|
+
tokenOut: '0x1234567890123456789012345678901234567890',
|
|
100
|
+
amount: BigInt('1000000'),
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const quote = await swapClient.getQuote(params, controller.signal);
|
|
105
|
+
clearTimeout(timeoutId);
|
|
106
|
+
console.log('Quote with timeout:', quote);
|
|
107
|
+
return quote;
|
|
108
|
+
} catch (error: any) {
|
|
109
|
+
clearTimeout(timeoutId);
|
|
110
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
111
|
+
console.error('Quote request timed out');
|
|
112
|
+
} else {
|
|
113
|
+
console.error('Failed to get quote:', error);
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Example 5: Error handling and fallback behavior
|
|
120
|
+
export async function getQuoteWithErrorHandling() {
|
|
121
|
+
const params: UnifiedQuoteParams = {
|
|
122
|
+
sourceChainId: ChainID.Arbitrum,
|
|
123
|
+
destChainId: ChainID.Arbitrum,
|
|
124
|
+
tokenIn: '0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C',
|
|
125
|
+
tokenOut: '0x1234567890123456789012345678901234567890',
|
|
126
|
+
amount: BigInt('1000000'),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const quote = await swapClient.getQuote(params);
|
|
131
|
+
|
|
132
|
+
if (quote.error) {
|
|
133
|
+
console.warn('Quote returned with error:', quote.error);
|
|
134
|
+
// Handle the error case
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Check if we got a valid quote
|
|
139
|
+
if (quote.amountOut > 0n) {
|
|
140
|
+
console.log('Valid quote received from:', quote.source);
|
|
141
|
+
console.log('Expected output:', quote.amountOut.toString());
|
|
142
|
+
console.log('Price impact:', quote.priceImpact, '%');
|
|
143
|
+
return quote;
|
|
144
|
+
} else {
|
|
145
|
+
console.warn('Invalid quote received');
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('Failed to get quote:', error);
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Example 6: Multiple quotes comparison
|
|
155
|
+
export async function getMultipleQuotesComparison() {
|
|
156
|
+
const baseParams: UnifiedQuoteParams = {
|
|
157
|
+
sourceChainId: ChainID.Arbitrum ,
|
|
158
|
+
destChainId: ChainID.Arbitrum,
|
|
159
|
+
tokenIn: '0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C',
|
|
160
|
+
tokenOut: '0x1234567890123456789012345678901234567890',
|
|
161
|
+
amount: BigInt('1000000'),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Create multiple quote variations
|
|
165
|
+
const quoteParams = [
|
|
166
|
+
{ ...baseParams, slippageBps: 50 }, // 0.5% slippage
|
|
167
|
+
{ ...baseParams, slippageBps: 100 }, // 1% slippage
|
|
168
|
+
{ ...baseParams, slippageBps: 200 }, // 2% slippage
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
const quotes = await swapClient.getMultipleQuotes(quoteParams);
|
|
173
|
+
console.log('Multiple quotes received:', quotes.length);
|
|
174
|
+
|
|
175
|
+
// Find the best quote
|
|
176
|
+
const bestQuote = await swapClient.getBestQuote(quoteParams);
|
|
177
|
+
if (bestQuote) {
|
|
178
|
+
console.log('Best quote output:', bestQuote.amountOut.toString());
|
|
179
|
+
console.log('Best quote source:', bestQuote.source);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return quotes;
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error('Failed to get multiple quotes:', error);
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Example 7: Token pair validation
|
|
190
|
+
export async function validateTokenPair() {
|
|
191
|
+
const chainId = ChainID.Arbitrum;
|
|
192
|
+
const tokenIn = '0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C'; // USDC
|
|
193
|
+
const tokenOut = '0x1234567890123456789012345678901234567890'; // Some token
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
const isSupported = await swapClient.isTokenPairSupported(chainId, tokenIn, tokenOut);
|
|
197
|
+
console.log('Token pair supported:', isSupported);
|
|
198
|
+
|
|
199
|
+
if (isSupported) {
|
|
200
|
+
// Get supported tokens for the chain
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return isSupported;
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error('Failed to validate token pair:', error);
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Example 8: Gas estimation
|
|
211
|
+
export async function estimateSwapGas() {
|
|
212
|
+
const chainId = ChainID.Arbitrum;
|
|
213
|
+
const tokenIn = '0xA0b86a33E6441b8c4C8C0C4C0C4C0C4C0C4C0C4C';
|
|
214
|
+
const tokenOut = '0x1234567890123456789012345678901234567890';
|
|
215
|
+
const amount = BigInt('1000000');
|
|
216
|
+
const userAddress = '0x1234567890123456789012345678901234567890';
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
const gasEstimate = await swapClient.estimateGas(chainId, tokenIn, tokenOut, amount, userAddress);
|
|
220
|
+
|
|
221
|
+
if (gasEstimate) {
|
|
222
|
+
console.log('Gas estimate:', gasEstimate.gasEstimate.toString());
|
|
223
|
+
console.log('Gas price:', gasEstimate.gasPrice.toString());
|
|
224
|
+
console.log('Total gas cost:', (gasEstimate.gasEstimate * gasEstimate.gasPrice).toString());
|
|
225
|
+
} else {
|
|
226
|
+
console.log('Gas estimation not available for this chain');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return gasEstimate;
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error('Failed to estimate gas:', error);
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Example 9: Dynamic configuration updates
|
|
237
|
+
export async function updateClientConfiguration() {
|
|
238
|
+
try {
|
|
239
|
+
// Get current configuration
|
|
240
|
+
const currentConfig = swapClient.getConfig();
|
|
241
|
+
console.log('Current config:', currentConfig);
|
|
242
|
+
|
|
243
|
+
// Update configuration
|
|
244
|
+
swapClient.updateConfig({
|
|
245
|
+
debug: false, // Disable debug logging
|
|
246
|
+
maxRetries: 5, // Increase retry attempts
|
|
247
|
+
timeout: 60000, // Increase timeout to 60 seconds
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
console.log('Configuration updated successfully');
|
|
251
|
+
|
|
252
|
+
// Verify the update
|
|
253
|
+
const updatedConfig = swapClient.getConfig();
|
|
254
|
+
console.log('Updated config:', updatedConfig);
|
|
255
|
+
|
|
256
|
+
return updatedConfig;
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error('Failed to update configuration:', error);
|
|
259
|
+
throw error;
|
|
260
|
+
}
|
|
261
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @shogun-sdk/swap
|
|
3
|
+
*
|
|
4
|
+
* Shogun Network Swap utilities and helpers
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export * from './types/index.js';
|
|
8
|
+
export * from './utils/index.js';
|
|
9
|
+
export * from './client/SwapClient.js';
|
|
10
|
+
|
|
11
|
+
// Re-export ChainID for convenience
|
|
12
|
+
export { ChainID } from '@shogun-sdk/intents-sdk';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for swap operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface SwapParams {
|
|
6
|
+
/** Input token address */
|
|
7
|
+
tokenIn: string;
|
|
8
|
+
/** Output token address */
|
|
9
|
+
tokenOut: string;
|
|
10
|
+
/** Amount of input tokens */
|
|
11
|
+
amountIn: bigint;
|
|
12
|
+
/** Minimum amount of output tokens expected */
|
|
13
|
+
amountOutMin: bigint;
|
|
14
|
+
/** Recipient address */
|
|
15
|
+
to: string;
|
|
16
|
+
/** Transaction deadline (unix timestamp) */
|
|
17
|
+
deadline: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SwapQuote {
|
|
21
|
+
/** Expected output amount */
|
|
22
|
+
amountOut: bigint;
|
|
23
|
+
/** Price impact percentage (0-100) */
|
|
24
|
+
priceImpact: number;
|
|
25
|
+
/** Gas estimate */
|
|
26
|
+
gasEstimate?: bigint;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SwapResult {
|
|
30
|
+
/** Transaction hash */
|
|
31
|
+
transactionHash: string;
|
|
32
|
+
/** Actual amount received */
|
|
33
|
+
amountOut: bigint;
|
|
34
|
+
/** Gas used */
|
|
35
|
+
gasUsed?: bigint;
|
|
36
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for swap operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { SwapParams } from '../types/index.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Calculate price impact for a swap
|
|
9
|
+
* @param amountIn Input amount
|
|
10
|
+
* @param amountOut Expected output amount
|
|
11
|
+
* @param tokenInPrice Price of input token in USD
|
|
12
|
+
* @param tokenOutPrice Price of output token in USD
|
|
13
|
+
* @returns Price impact as percentage
|
|
14
|
+
*/
|
|
15
|
+
export function calculatePriceImpact(
|
|
16
|
+
amountIn: bigint,
|
|
17
|
+
amountOut: bigint,
|
|
18
|
+
tokenInPrice: number,
|
|
19
|
+
tokenOutPrice: number
|
|
20
|
+
): number {
|
|
21
|
+
const inputValue = Number(amountIn) * tokenInPrice;
|
|
22
|
+
const outputValue = Number(amountOut) * tokenOutPrice;
|
|
23
|
+
|
|
24
|
+
if (inputValue === 0) return 0;
|
|
25
|
+
|
|
26
|
+
return Math.abs((inputValue - outputValue) / inputValue) * 100;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Validate swap parameters
|
|
31
|
+
* @param params Swap parameters to validate
|
|
32
|
+
* @throws Error if parameters are invalid
|
|
33
|
+
*/
|
|
34
|
+
export function validateSwapParams(params: SwapParams): void {
|
|
35
|
+
if (!params.tokenIn || !params.tokenOut) {
|
|
36
|
+
throw new Error('Token addresses are required');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (params.tokenIn === params.tokenOut) {
|
|
40
|
+
throw new Error('Input and output tokens cannot be the same');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (params.amountIn <= 0n) {
|
|
44
|
+
throw new Error('Input amount must be greater than 0');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (params.amountOutMin < 0n) {
|
|
48
|
+
throw new Error('Minimum output amount cannot be negative');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!params.to) {
|
|
52
|
+
throw new Error('Recipient address is required');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (params.deadline <= Math.floor(Date.now() / 1000)) {
|
|
56
|
+
throw new Error('Deadline must be in the future');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Format token amount for display
|
|
62
|
+
* @param amount Token amount in smallest units
|
|
63
|
+
* @param decimals Token decimals
|
|
64
|
+
* @returns Formatted string
|
|
65
|
+
*/
|
|
66
|
+
export function formatTokenAmount(amount: bigint, decimals: number): string {
|
|
67
|
+
const divisor = BigInt(10 ** decimals);
|
|
68
|
+
const whole = amount / divisor;
|
|
69
|
+
const remainder = amount % divisor;
|
|
70
|
+
|
|
71
|
+
if (remainder === 0n) {
|
|
72
|
+
return whole.toString();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const fractional = remainder.toString().padStart(decimals, '0').replace(/0+$/, '');
|
|
76
|
+
return `${whole}.${fractional}`;
|
|
77
|
+
}
|