@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.
@@ -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
+ }