@jimmygu/sfa-sdk-test 1.0.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/LICENSE +22 -0
- package/README.md +1003 -0
- package/dist/index.d.mts +1043 -0
- package/dist/index.d.ts +1043 -0
- package/dist/index.js +8171 -0
- package/dist/index.mjs +8127 -0
- package/package.json +79 -0
package/README.md
ADDED
|
@@ -0,0 +1,1003 @@
|
|
|
1
|
+
# StableFlow AI SDK - TypeScript
|
|
2
|
+
|
|
3
|
+
A powerful TypeScript SDK for seamless cross-chain token swaps. Built with type safety in mind, this SDK enables developers to easily integrate cross-chain swapping functionality into their applications with minimal setup.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js >= 16
|
|
8
|
+
- npm / yarn / pnpm
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Using npm
|
|
14
|
+
npm install stableflow-ai-sdk
|
|
15
|
+
|
|
16
|
+
# Using yarn
|
|
17
|
+
yarn add stableflow-ai-sdk
|
|
18
|
+
|
|
19
|
+
# Using pnpm
|
|
20
|
+
pnpm add stableflow-ai-sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { OpenAPI, SFA, tokens, EVMWallet, setRpcUrls } from 'stableflow-ai-sdk';
|
|
27
|
+
import { ethers } from 'ethers';
|
|
28
|
+
|
|
29
|
+
// Initialize the API client
|
|
30
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
31
|
+
OpenAPI.TOKEN = "your-JSON-Web-Token";
|
|
32
|
+
|
|
33
|
+
// (Optional) Configure custom RPC endpoints
|
|
34
|
+
setRpcUrls({
|
|
35
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
36
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Get wallet instance (example with EVM)
|
|
40
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
41
|
+
const signer = await provider.getSigner();
|
|
42
|
+
const wallet = new EVMWallet(provider, signer);
|
|
43
|
+
|
|
44
|
+
// Get token configurations
|
|
45
|
+
const fromToken = tokens.find(t => t.chainName === 'Ethereum' && t.symbol === 'USDT');
|
|
46
|
+
const toToken = tokens.find(t => t.chainName === 'Arbitrum' && t.symbol === 'USDT');
|
|
47
|
+
|
|
48
|
+
// Get quotes from all bridge services
|
|
49
|
+
const quotes = await SFA.getAllQuote({
|
|
50
|
+
dry: false,
|
|
51
|
+
minInputAmount: "0.1",
|
|
52
|
+
prices: {},
|
|
53
|
+
fromToken: fromToken!,
|
|
54
|
+
toToken: toToken!,
|
|
55
|
+
wallet: wallet,
|
|
56
|
+
recipient: '0x...', // recipient address
|
|
57
|
+
refundTo: '0x...', // refund address
|
|
58
|
+
amountWei: ethers.parseUnits('100', fromToken!.decimals).toString(),
|
|
59
|
+
slippageTolerance: 0.5, // 0.5%
|
|
60
|
+
// Optional
|
|
61
|
+
oneclickParams: {
|
|
62
|
+
appFees: [
|
|
63
|
+
{
|
|
64
|
+
// your fee collection address
|
|
65
|
+
recipient: "stableflow.near",
|
|
66
|
+
// Fee rate, as a percentage of the amount. 100 = 1%, 1 = 0.01%
|
|
67
|
+
fee: 100,
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Select the best quote and send transaction
|
|
74
|
+
const selectedQuote = quotes.find(q => q.quote && !q.error);
|
|
75
|
+
if (selectedQuote && selectedQuote.quote) {
|
|
76
|
+
const txHash = await SFA.send(selectedQuote.serviceType, {
|
|
77
|
+
wallet: wallet,
|
|
78
|
+
quote: selectedQuote.quote,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Check transaction status
|
|
82
|
+
const status = await SFA.getStatus(selectedQuote.serviceType, {
|
|
83
|
+
hash: txHash,
|
|
84
|
+
depositAddress: selectedQuote.quote.depositAddress,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Authentication
|
|
90
|
+
|
|
91
|
+
The StableFlow AI API requires JWT authentication for all endpoints.
|
|
92
|
+
|
|
93
|
+
### Getting Your JWT Token
|
|
94
|
+
|
|
95
|
+
To use the SDK, you need to apply for a JWT token:
|
|
96
|
+
|
|
97
|
+
1. Visit [https://app.stableflow.ai/apply](https://app.stableflow.ai/apply)
|
|
98
|
+
2. Submit an application form for API access
|
|
99
|
+
3. Once approved, you will receive your JWT token
|
|
100
|
+
|
|
101
|
+
### Using Your Token
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// Set your JWT token
|
|
105
|
+
OpenAPI.TOKEN = 'your-JSON-Web-Token-here';
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Core API Methods
|
|
109
|
+
|
|
110
|
+
### `getAllQuote` - Get Quotes from All Bridge Services
|
|
111
|
+
|
|
112
|
+
Retrieves quotes from all supported bridge services (OneClick, CCTP, USDT0) in parallel. Returns an array of quotes with their corresponding service types, allowing users to compare and select the best route.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const quotes = await SFA.getAllQuote({
|
|
116
|
+
singleService?: ServiceType, // Optional: query specific service only
|
|
117
|
+
dry?: boolean, // Set to true for testing without deposit address
|
|
118
|
+
minInputAmount?: string, // Minimum input amount (default: "1")
|
|
119
|
+
prices: Record<string, string>, // Token prices
|
|
120
|
+
fromToken: TokenConfig, // Source token configuration
|
|
121
|
+
toToken: TokenConfig, // Destination token configuration
|
|
122
|
+
wallet: WalletConfig, // Wallet instance (EVMWallet, SolanaWallet, etc.)
|
|
123
|
+
recipient: string, // Recipient address on destination chain
|
|
124
|
+
refundTo: string, // Refund address on source chain
|
|
125
|
+
amountWei: string, // Amount in smallest units (wei/satoshi/etc.)
|
|
126
|
+
slippageTolerance: number, // Slippage tolerance percentage (e.g., 0.5 for 0.5%)
|
|
127
|
+
oneclickParams?: {
|
|
128
|
+
// Custom fee rates
|
|
129
|
+
appFees?: { recipient: string; fee: number; }[];
|
|
130
|
+
// default is EXACT_INPUT
|
|
131
|
+
swapType?: "EXACT_INPUT" | "EXACT_OUTPUT";
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Returns**: `Promise<Array<{ serviceType: ServiceType; quote?: any; error?: string }>>`
|
|
137
|
+
|
|
138
|
+
**Example**:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { SFA, tokens, EVMWallet, GetAllQuoteParams } from 'stableflow-ai-sdk';
|
|
142
|
+
import { ethers } from 'ethers';
|
|
143
|
+
|
|
144
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
145
|
+
const signer = await provider.getSigner();
|
|
146
|
+
const wallet = new EVMWallet(provider, signer);
|
|
147
|
+
|
|
148
|
+
const fromToken = tokens.find(t => t.contractAddress === '0x...');
|
|
149
|
+
const toToken = tokens.find(t => t.contractAddress === '0x...');
|
|
150
|
+
|
|
151
|
+
const quotes = await SFA.getAllQuote({
|
|
152
|
+
dry: false,
|
|
153
|
+
prices: {},
|
|
154
|
+
fromToken: fromToken!,
|
|
155
|
+
toToken: toToken!,
|
|
156
|
+
wallet: wallet,
|
|
157
|
+
recipient: '0x1234...',
|
|
158
|
+
refundTo: '0x5678...',
|
|
159
|
+
amountWei: ethers.parseUnits('100', fromToken!.decimals).toString(),
|
|
160
|
+
slippageTolerance: 0.5,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Filter valid quotes
|
|
164
|
+
const validQuotes = quotes.filter(q => q.quote && !q.error);
|
|
165
|
+
console.log('Available routes:', validQuotes.map(q => q.serviceType));
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Response Structure**:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
[
|
|
172
|
+
{
|
|
173
|
+
serviceType: "oneclick",
|
|
174
|
+
quote: {
|
|
175
|
+
quote: QuoteResponse,
|
|
176
|
+
quoteParam: {...},
|
|
177
|
+
sendParam: {...},
|
|
178
|
+
depositAddress: "0x...",
|
|
179
|
+
needApprove: boolean,
|
|
180
|
+
approveSpender: "0x...",
|
|
181
|
+
fees: {...}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
serviceType: "cctp",
|
|
186
|
+
quote: {...},
|
|
187
|
+
error: undefined
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
serviceType: "usdt0",
|
|
191
|
+
error: "Amount exceeds max"
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### `send` - Execute Transaction
|
|
197
|
+
|
|
198
|
+
Executes the transaction using the specified bridge service based on the service type. This method handles token approval (if needed) and submits the transaction to the blockchain.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
const txHash = await SFA.send(
|
|
202
|
+
serviceType: ServiceType, // "oneclick" | "cctp" | "usdt0"
|
|
203
|
+
{
|
|
204
|
+
wallet: WalletConfig, // Wallet instance
|
|
205
|
+
quote: any, // Quote object from getAllQuote response
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Returns**: `Promise<string>` - Transaction hash or signature
|
|
211
|
+
|
|
212
|
+
**Example**:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
// After getting quotes and selecting one
|
|
216
|
+
const selectedQuote = quotes.find(q => q.quote && !q.error);
|
|
217
|
+
|
|
218
|
+
if (selectedQuote && selectedQuote.quote) {
|
|
219
|
+
// Check if approval is needed
|
|
220
|
+
if (selectedQuote.quote.needApprove) {
|
|
221
|
+
await wallet.approve({
|
|
222
|
+
contractAddress: selectedQuote.quote.quoteParam.fromToken.contractAddress,
|
|
223
|
+
spender: selectedQuote.quote.approveSpender,
|
|
224
|
+
amountWei: selectedQuote.quote.quoteParam.amountWei,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Send the transaction
|
|
229
|
+
const txHash = await SFA.send(selectedQuote.serviceType, {
|
|
230
|
+
wallet: wallet,
|
|
231
|
+
quote: selectedQuote.quote,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
console.log('Transaction hash:', txHash);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
**Note**: The `send` method automatically submits the transaction hash to the StableFlow service for tracking. You don't need to call `submitDepositTx` separately.
|
|
239
|
+
|
|
240
|
+
### `getStatus` - Check Transaction Status
|
|
241
|
+
|
|
242
|
+
Queries the transaction status from the specified bridge service. Returns the current status and destination chain transaction hash (if available).
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
const status = await SFA.getStatus(
|
|
246
|
+
serviceType: ServiceType, // "oneclick" | "cctp" | "usdt0"
|
|
247
|
+
{
|
|
248
|
+
depositAddress?: string, // Deposit address from quote (for OneClick)
|
|
249
|
+
hash?: string, // Transaction hash (for USDT0 and CCTP)
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Returns**: `Promise<{ status: TransactionStatus; toChainTxHash?: string }>`
|
|
255
|
+
|
|
256
|
+
**TransactionStatus**:
|
|
257
|
+
- `TransactionStatus.Pending` - Transaction is pending
|
|
258
|
+
- `TransactionStatus.Success` - Transaction completed successfully
|
|
259
|
+
- `TransactionStatus.Failed` - Transaction failed or was refunded
|
|
260
|
+
|
|
261
|
+
**Example**:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
import { SFA, Service, TransactionStatus } from 'stableflow-ai-sdk';
|
|
265
|
+
|
|
266
|
+
// For OneClick service
|
|
267
|
+
const status = await SFA.getStatus(Service.OneClick, {
|
|
268
|
+
depositAddress: '0x...',
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// For USDT0 or CCTP service
|
|
272
|
+
const status = await SFA.getStatus(Service.Usdt0, {
|
|
273
|
+
hash: '0x...',
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
console.log('Status:', status.status); // "pending" | "success" | "failed"
|
|
277
|
+
if (status.toChainTxHash) {
|
|
278
|
+
console.log('Destination tx hash:', status.toChainTxHash);
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
**Polling Example**:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
async function pollTransactionStatus(
|
|
286
|
+
serviceType: ServiceType,
|
|
287
|
+
params: { depositAddress?: string; hash?: string },
|
|
288
|
+
interval: number = 5000
|
|
289
|
+
): Promise<{ status: TransactionStatus; toChainTxHash?: string }> {
|
|
290
|
+
return new Promise((resolve) => {
|
|
291
|
+
const checkStatus = async () => {
|
|
292
|
+
try {
|
|
293
|
+
const result = await SFA.getStatus(serviceType, params);
|
|
294
|
+
if (result.status !== TransactionStatus.Pending) {
|
|
295
|
+
resolve(result);
|
|
296
|
+
} else {
|
|
297
|
+
setTimeout(checkStatus, interval);
|
|
298
|
+
}
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error('Error checking status:', error);
|
|
301
|
+
setTimeout(checkStatus, interval);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
checkStatus();
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Usage
|
|
309
|
+
const finalStatus = await pollTransactionStatus(Service.OneClick, {
|
|
310
|
+
depositAddress: '0x...',
|
|
311
|
+
});
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Supported Bridge Services
|
|
315
|
+
|
|
316
|
+
The SDK supports three bridge services:
|
|
317
|
+
|
|
318
|
+
- **OneClick** (`Service.OneClick`) - Native StableFlow bridge service
|
|
319
|
+
- **CCTP** (`Service.CCTP`) - Circle's Cross-Chain Transfer Protocol
|
|
320
|
+
- **USDT0** (`Service.Usdt0`) - LayerZero-based USDT bridge
|
|
321
|
+
|
|
322
|
+
Each service has different characteristics:
|
|
323
|
+
- Different fee structures
|
|
324
|
+
- Different supported token pairs
|
|
325
|
+
- Different processing times
|
|
326
|
+
- Different minimum/maximum amounts
|
|
327
|
+
|
|
328
|
+
### USDT0 Service Features
|
|
329
|
+
|
|
330
|
+
The USDT0 service provides LayerZero-based USDT bridging with the following capabilities:
|
|
331
|
+
|
|
332
|
+
- **Multi-chain Support**: Supports bridging from EVM chains (Ethereum, Arbitrum, Polygon, Optimism, etc.), Solana, and Tron
|
|
333
|
+
- **Multi-hop Routing**: Automatically handles multi-hop transfers when direct routes are not available (e.g., Solana → Arbitrum → Ethereum)
|
|
334
|
+
- **Dynamic Time Estimation**: Calculates estimated completion time based on source and destination chain block times and confirmations
|
|
335
|
+
- **Accurate Fee Estimation**: Improved fee calculation including LayerZero message fees, gas costs, and legacy mesh transfer fees (0.03% for legacy routes)
|
|
336
|
+
- **Legacy and Upgradeable Support**: Seamlessly handles both legacy and upgradeable OFT contracts
|
|
337
|
+
|
|
338
|
+
Use `getAllQuote` to compare all available routes and select the best one for your use case.
|
|
339
|
+
|
|
340
|
+
## Wallet Integration
|
|
341
|
+
|
|
342
|
+
The SDK supports multiple wallet types:
|
|
343
|
+
|
|
344
|
+
### EVM Wallets (Ethereum, Arbitrum, Polygon, etc.)
|
|
345
|
+
|
|
346
|
+
**Using ethers.js with BrowserProvider:**
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { EVMWallet } from 'stableflow-ai-sdk';
|
|
350
|
+
import { ethers } from 'ethers';
|
|
351
|
+
|
|
352
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
353
|
+
const signer = await provider.getSigner();
|
|
354
|
+
const wallet = new EVMWallet(provider, signer);
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Using wagmi/viem (recommended for React apps):**
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
import { EVMWallet } from 'stableflow-ai-sdk';
|
|
361
|
+
import { ethers } from 'ethers';
|
|
362
|
+
import { usePublicClient, useWalletClient } from 'wagmi';
|
|
363
|
+
|
|
364
|
+
// In your React component
|
|
365
|
+
const publicClient = usePublicClient();
|
|
366
|
+
const { data: walletClient } = useWalletClient();
|
|
367
|
+
|
|
368
|
+
const provider = new ethers.BrowserProvider(publicClient);
|
|
369
|
+
const signer = walletClient
|
|
370
|
+
? await new ethers.BrowserProvider(walletClient).getSigner()
|
|
371
|
+
: null;
|
|
372
|
+
|
|
373
|
+
const wallet = new EVMWallet(provider, signer);
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Solana Wallets
|
|
377
|
+
|
|
378
|
+
**Using @solana/wallet-adapter-react (recommended for React apps):**
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
import { SolanaWallet } from 'stableflow-ai-sdk';
|
|
382
|
+
import { useWallet } from '@solana/wallet-adapter-react';
|
|
383
|
+
|
|
384
|
+
// In your React component
|
|
385
|
+
const { publicKey, signTransaction } = useWallet();
|
|
386
|
+
|
|
387
|
+
const wallet = new SolanaWallet({
|
|
388
|
+
publicKey: publicKey,
|
|
389
|
+
signer: { signTransaction }
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Using wallet adapter directly:**
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
import { SolanaWallet } from 'stableflow-ai-sdk';
|
|
397
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
398
|
+
|
|
399
|
+
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
400
|
+
const publicKey = new PublicKey('YOUR_SOLANA_ADDRESS');
|
|
401
|
+
|
|
402
|
+
const wallet = new SolanaWallet({
|
|
403
|
+
publicKey: publicKey,
|
|
404
|
+
signer: {
|
|
405
|
+
signTransaction: async (transaction) => {
|
|
406
|
+
// Sign transaction using your wallet adapter
|
|
407
|
+
// Example with Phantom:
|
|
408
|
+
// const provider = window.solana;
|
|
409
|
+
// return await provider.signTransaction(transaction);
|
|
410
|
+
return signedTransaction;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Note**: Solana wallets can be used as the source chain for USDT0 bridging, enabling cross-chain transfers from Solana to EVM chains, Tron, and other supported networks.
|
|
417
|
+
|
|
418
|
+
### Near Wallets
|
|
419
|
+
|
|
420
|
+
```typescript
|
|
421
|
+
import { NearWallet } from 'stableflow-ai-sdk';
|
|
422
|
+
import { setupWalletSelector } from '@near-wallet-selector/core';
|
|
423
|
+
|
|
424
|
+
// Setup wallet selector (e.g., using @near-wallet-selector)
|
|
425
|
+
const selector = await setupWalletSelector({
|
|
426
|
+
network: 'mainnet',
|
|
427
|
+
modules: [
|
|
428
|
+
// Add your wallet modules here
|
|
429
|
+
]
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
const wallet = new NearWallet(selector);
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Note**: NearWallet requires a wallet selector instance from `@near-wallet-selector/core`. The selector handles wallet connection and transaction signing.
|
|
436
|
+
|
|
437
|
+
### Tron Wallets
|
|
438
|
+
|
|
439
|
+
```typescript
|
|
440
|
+
import { TronWallet } from 'stableflow-ai-sdk';
|
|
441
|
+
|
|
442
|
+
// Using TronLink or other Tron wallet adapters
|
|
443
|
+
const wallet = new TronWallet({
|
|
444
|
+
signAndSendTransaction: async (transaction: any) => {
|
|
445
|
+
// Sign transaction using TronWeb
|
|
446
|
+
const signedTransaction = await window.tronWeb.trx.sign(transaction);
|
|
447
|
+
// Send signed transaction
|
|
448
|
+
return await window.tronWeb.trx.sendRawTransaction(signedTransaction);
|
|
449
|
+
},
|
|
450
|
+
address: window.tronWeb?.defaultAddress?.base58, // User's Tron address
|
|
451
|
+
});
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**With TronLink Wallet:**
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
import { TronWallet } from 'stableflow-ai-sdk';
|
|
458
|
+
|
|
459
|
+
// Wait for TronLink to be available
|
|
460
|
+
if (window.tronWeb && window.tronWeb.ready) {
|
|
461
|
+
const wallet = new TronWallet({
|
|
462
|
+
signAndSendTransaction: async (transaction: any) => {
|
|
463
|
+
const signedTransaction = await window.tronWeb.trx.sign(transaction);
|
|
464
|
+
const result = await window.tronWeb.trx.sendRawTransaction(signedTransaction);
|
|
465
|
+
// Return transaction ID (txid)
|
|
466
|
+
return typeof result === 'string' ? result : result.txid;
|
|
467
|
+
},
|
|
468
|
+
address: window.tronWeb.defaultAddress.base58,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
**Note:** The `signAndSendTransaction` function should:
|
|
474
|
+
- Accept a transaction object as parameter
|
|
475
|
+
- Sign the transaction using the connected wallet
|
|
476
|
+
- Send the signed transaction to the network
|
|
477
|
+
- Return the transaction ID (txid) as a string, or an object with a `txid` property
|
|
478
|
+
|
|
479
|
+
### Aptos Wallets
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
import { AptosWallet } from 'stableflow-ai-sdk';
|
|
483
|
+
import { useWallet } from '@aptos-labs/wallet-adapter-react';
|
|
484
|
+
|
|
485
|
+
// Using Aptos wallet adapter
|
|
486
|
+
const { account, signAndSubmitTransaction } = useWallet();
|
|
487
|
+
|
|
488
|
+
const wallet = new AptosWallet({
|
|
489
|
+
account: account,
|
|
490
|
+
signAndSubmitTransaction: signAndSubmitTransaction,
|
|
491
|
+
});
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**Note**: AptosWallet requires an account object and a `signAndSubmitTransaction` function from the Aptos wallet adapter (e.g., `@aptos-labs/wallet-adapter-react`).
|
|
495
|
+
|
|
496
|
+
## Token Configuration
|
|
497
|
+
|
|
498
|
+
The SDK provides pre-configured token information:
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
import { tokens, usdtTokens, usdcTokens } from 'stableflow-ai-sdk';
|
|
502
|
+
|
|
503
|
+
// Get all supported tokens
|
|
504
|
+
const allTokens = tokens;
|
|
505
|
+
|
|
506
|
+
// Get USDT tokens only
|
|
507
|
+
const usdtOnly = usdtTokens;
|
|
508
|
+
|
|
509
|
+
// Get USDC tokens only
|
|
510
|
+
const usdcOnly = usdcTokens;
|
|
511
|
+
|
|
512
|
+
// Find token by contract address
|
|
513
|
+
const token = tokens.find(t =>
|
|
514
|
+
t.contractAddress.toLowerCase() === '0x...'.toLowerCase()
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
// Find tokens by chain
|
|
518
|
+
const ethereumTokens = tokens.filter(t => t.chainName === 'Ethereum');
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
Each token configuration includes:
|
|
522
|
+
- `chainName` - Name of the blockchain
|
|
523
|
+
- `chainType` - Type of chain (evm, solana, near, tron, aptos)
|
|
524
|
+
- `symbol` - Token symbol (USDT, USDC, etc.)
|
|
525
|
+
- `decimals` - Token decimals
|
|
526
|
+
- `contractAddress` - Token contract address
|
|
527
|
+
- `assetId` - StableFlow asset identifier
|
|
528
|
+
- `services` - Array of supported bridge services
|
|
529
|
+
- `rpcUrls` - RPC endpoint URLs
|
|
530
|
+
|
|
531
|
+
## Complete Example
|
|
532
|
+
|
|
533
|
+
### Example 1: EVM to EVM Bridge (Ethereum → Arbitrum)
|
|
534
|
+
|
|
535
|
+
Here's a complete example of a cross-chain swap:
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
import { SFA, OpenAPI, tokens, EVMWallet, Service, TransactionStatus, setRpcUrls } from 'stableflow-ai-sdk';
|
|
539
|
+
import { ethers } from 'ethers';
|
|
540
|
+
|
|
541
|
+
// 1. Initialize SDK
|
|
542
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
543
|
+
OpenAPI.TOKEN = 'your-jwt-token';
|
|
544
|
+
|
|
545
|
+
// (Optional) Configure custom RPC endpoints
|
|
546
|
+
setRpcUrls({
|
|
547
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
548
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
// 2. Setup wallet
|
|
552
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
553
|
+
await provider.send('eth_requestAccounts', []);
|
|
554
|
+
const signer = await provider.getSigner();
|
|
555
|
+
const wallet = new EVMWallet(provider, signer);
|
|
556
|
+
const userAddress = await signer.getAddress();
|
|
557
|
+
|
|
558
|
+
// 3. Select tokens
|
|
559
|
+
const fromToken = tokens.find(t =>
|
|
560
|
+
t.chainName === 'Ethereum' && t.symbol === 'USDT'
|
|
561
|
+
);
|
|
562
|
+
const toToken = tokens.find(t =>
|
|
563
|
+
t.chainName === 'Arbitrum' && t.symbol === 'USDT'
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
if (!fromToken || !toToken) {
|
|
567
|
+
throw new Error('Token pair not supported');
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// 4. Get quotes
|
|
571
|
+
const quotes = await SFA.getAllQuote({
|
|
572
|
+
dry: false,
|
|
573
|
+
prices: {},
|
|
574
|
+
fromToken,
|
|
575
|
+
toToken,
|
|
576
|
+
wallet,
|
|
577
|
+
recipient: userAddress, // or another address
|
|
578
|
+
refundTo: userAddress,
|
|
579
|
+
amountWei: ethers.parseUnits('100', fromToken.decimals).toString(),
|
|
580
|
+
slippageTolerance: 0.5,
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// 5. Select best quote (e.g., first valid one)
|
|
584
|
+
const selectedQuote = quotes.find(q => q.quote && !q.error);
|
|
585
|
+
if (!selectedQuote || !selectedQuote.quote) {
|
|
586
|
+
throw new Error('No valid quotes available');
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
console.log(`Selected route: ${selectedQuote.serviceType}`);
|
|
590
|
+
console.log(`Estimated time: ${selectedQuote.quote.estimateTime}s`);
|
|
591
|
+
|
|
592
|
+
// 6. Handle approval if needed
|
|
593
|
+
if (selectedQuote.quote.needApprove) {
|
|
594
|
+
const allowance = await wallet.allowance({
|
|
595
|
+
contractAddress: selectedQuote.quote.quoteParam.fromToken.contractAddress,
|
|
596
|
+
spender: selectedQuote.quote.approveSpender,
|
|
597
|
+
address: userAddress,
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
if (allowance < BigInt(selectedQuote.quote.quoteParam.amountWei)) {
|
|
601
|
+
await wallet.approve({
|
|
602
|
+
contractAddress: selectedQuote.quote.quoteParam.fromToken.contractAddress,
|
|
603
|
+
spender: selectedQuote.quote.approveSpender,
|
|
604
|
+
amountWei: selectedQuote.quote.quoteParam.amountWei,
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// 7. Send transaction
|
|
610
|
+
const txHash = await SFA.send(selectedQuote.serviceType, {
|
|
611
|
+
wallet,
|
|
612
|
+
quote: selectedQuote.quote,
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
console.log('Transaction submitted:', txHash);
|
|
616
|
+
|
|
617
|
+
// 8. Poll for status
|
|
618
|
+
const statusParams = selectedQuote.serviceType === Service.OneClick
|
|
619
|
+
? { depositAddress: selectedQuote.quote.quote?.depositAddress }
|
|
620
|
+
: { hash: txHash };
|
|
621
|
+
|
|
622
|
+
const checkStatus = async () => {
|
|
623
|
+
const status = await SFA.getStatus(selectedQuote.serviceType, statusParams);
|
|
624
|
+
console.log('Current status:', status.status);
|
|
625
|
+
|
|
626
|
+
if (status.status === TransactionStatus.Success) {
|
|
627
|
+
console.log('Swap completed! Destination tx:', status.toChainTxHash);
|
|
628
|
+
} else if (status.status === TransactionStatus.Failed) {
|
|
629
|
+
console.log('Swap failed or refunded');
|
|
630
|
+
} else {
|
|
631
|
+
// Still pending, check again later
|
|
632
|
+
setTimeout(checkStatus, 5000);
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
checkStatus();
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Example 2: Solana to EVM Bridge (Solana → Ethereum)
|
|
640
|
+
|
|
641
|
+
Bridge USDT from Solana to Ethereum using USDT0:
|
|
642
|
+
|
|
643
|
+
```typescript
|
|
644
|
+
import { SFA, OpenAPI, tokens, SolanaWallet, Service, TransactionStatus, setRpcUrls } from 'stableflow-ai-sdk';
|
|
645
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
646
|
+
|
|
647
|
+
// 1. Initialize SDK
|
|
648
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
649
|
+
OpenAPI.TOKEN = 'your-jwt-token';
|
|
650
|
+
|
|
651
|
+
// (Optional) Configure custom RPC endpoints
|
|
652
|
+
setRpcUrls({
|
|
653
|
+
"sol": ["https://api.mainnet-beta.solana.com"],
|
|
654
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
// 2. Setup Solana wallet
|
|
658
|
+
// Note: In a real application, get these from your wallet adapter
|
|
659
|
+
// Example with @solana/wallet-adapter-react:
|
|
660
|
+
// const { publicKey, signTransaction } = useWallet();
|
|
661
|
+
// const wallet = new SolanaWallet({
|
|
662
|
+
// publicKey: publicKey,
|
|
663
|
+
// signer: { signTransaction }
|
|
664
|
+
// });
|
|
665
|
+
|
|
666
|
+
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
667
|
+
const publicKey = new PublicKey('YOUR_SOLANA_ADDRESS');
|
|
668
|
+
const wallet = new SolanaWallet({
|
|
669
|
+
publicKey: publicKey,
|
|
670
|
+
signer: {
|
|
671
|
+
signTransaction: async (tx) => {
|
|
672
|
+
// Sign transaction using your Solana wallet adapter
|
|
673
|
+
// Example with Phantom:
|
|
674
|
+
// const provider = window.solana;
|
|
675
|
+
// return await provider.signTransaction(tx);
|
|
676
|
+
throw new Error('Implement wallet signing');
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// 3. Select tokens
|
|
682
|
+
const fromToken = tokens.find(t =>
|
|
683
|
+
t.chainName === 'Solana' && t.symbol === 'USDT'
|
|
684
|
+
);
|
|
685
|
+
const toToken = tokens.find(t =>
|
|
686
|
+
t.chainName === 'Ethereum' && t.symbol === 'USDT'
|
|
687
|
+
);
|
|
688
|
+
|
|
689
|
+
if (!fromToken || !toToken) {
|
|
690
|
+
throw new Error('Token pair not supported');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// 4. Get quotes (USDT0 will automatically use multi-hop routing if needed)
|
|
694
|
+
const quotes = await SFA.getAllQuote({
|
|
695
|
+
dry: false,
|
|
696
|
+
prices: {},
|
|
697
|
+
fromToken,
|
|
698
|
+
toToken,
|
|
699
|
+
wallet,
|
|
700
|
+
recipient: '0x...', // Ethereum recipient address
|
|
701
|
+
refundTo: publicKey.toString(), // Solana refund address
|
|
702
|
+
amountWei: '1000000', // 1 USDT (6 decimals)
|
|
703
|
+
slippageTolerance: 0.5,
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
// 5. Find USDT0 quote
|
|
707
|
+
const usdt0Quote = quotes.find(q => q.serviceType === Service.Usdt0 && q.quote && !q.error);
|
|
708
|
+
if (usdt0Quote && usdt0Quote.quote) {
|
|
709
|
+
console.log(`USDT0 route available`);
|
|
710
|
+
console.log(`Estimated time: ${usdt0Quote.quote.estimateTime}s`);
|
|
711
|
+
console.log(`Total fees: $${usdt0Quote.quote.totalFeesUsd}`);
|
|
712
|
+
|
|
713
|
+
// 6. Send transaction
|
|
714
|
+
const txHash = await SFA.send(Service.Usdt0, {
|
|
715
|
+
wallet,
|
|
716
|
+
quote: usdt0Quote.quote,
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
console.log('Transaction submitted:', txHash);
|
|
720
|
+
|
|
721
|
+
// 7. Poll for status
|
|
722
|
+
const checkStatus = async () => {
|
|
723
|
+
const status = await SFA.getStatus(Service.Usdt0, { hash: txHash });
|
|
724
|
+
console.log('Current status:', status.status);
|
|
725
|
+
|
|
726
|
+
if (status.status === TransactionStatus.Success) {
|
|
727
|
+
console.log('Bridge completed! Destination tx:', status.toChainTxHash);
|
|
728
|
+
} else if (status.status === TransactionStatus.Failed) {
|
|
729
|
+
console.log('Bridge failed or refunded');
|
|
730
|
+
} else {
|
|
731
|
+
setTimeout(checkStatus, 5000);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
checkStatus();
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
## Error Handling
|
|
740
|
+
|
|
741
|
+
The SDK throws typed errors that you can catch and handle:
|
|
742
|
+
|
|
743
|
+
```typescript
|
|
744
|
+
import { ApiError } from 'stableflow-ai-sdk';
|
|
745
|
+
|
|
746
|
+
try {
|
|
747
|
+
const quotes = await SFA.getAllQuote(params);
|
|
748
|
+
} catch (error) {
|
|
749
|
+
if (error instanceof ApiError) {
|
|
750
|
+
switch (error.status) {
|
|
751
|
+
case 401:
|
|
752
|
+
console.error('Authentication failed: JWT is missing or invalid');
|
|
753
|
+
break;
|
|
754
|
+
case 400:
|
|
755
|
+
console.error('Invalid request:', error.body);
|
|
756
|
+
break;
|
|
757
|
+
default:
|
|
758
|
+
console.error('API error:', error.message);
|
|
759
|
+
}
|
|
760
|
+
} else {
|
|
761
|
+
console.error('Unexpected error:', error);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
Common error scenarios:
|
|
767
|
+
|
|
768
|
+
- **Invalid parameters**: Missing or invalid token configurations, addresses, or amounts
|
|
769
|
+
- **Insufficient balance**: User doesn't have enough tokens
|
|
770
|
+
- **Amount too low**: Amount below minimum threshold for the bridge service
|
|
771
|
+
- **Amount exceeds max**: Amount above maximum limit for the bridge service
|
|
772
|
+
- **No route available**: No bridge service supports the token pair
|
|
773
|
+
- **Network errors**: Connection issues or RPC failures
|
|
774
|
+
|
|
775
|
+
## Type Definitions
|
|
776
|
+
|
|
777
|
+
The SDK provides full TypeScript type definitions:
|
|
778
|
+
|
|
779
|
+
- `GetAllQuoteParams` - Parameters for `getAllQuote`
|
|
780
|
+
- `ServiceType` - Bridge service type (`"oneclick" | "cctp" | "usdt0"`)
|
|
781
|
+
- `Service` - Service constants
|
|
782
|
+
- `TokenConfig` - Token configuration interface
|
|
783
|
+
- `WalletConfig` - Wallet interface
|
|
784
|
+
- `TransactionStatus` - Transaction status enum
|
|
785
|
+
|
|
786
|
+
## Custom RPC Configuration
|
|
787
|
+
|
|
788
|
+
The SDK allows you to configure custom RPC endpoints for different blockchains. This is useful when you want to use your own RPC providers, private endpoints, or RPC services with API keys.
|
|
789
|
+
|
|
790
|
+
### Setting Custom RPC URLs
|
|
791
|
+
|
|
792
|
+
You can set custom RPC URLs using the `setRpcUrls` function. The function accepts a record where keys are blockchain identifiers and values are arrays of RPC URLs.
|
|
793
|
+
|
|
794
|
+
**Supported Blockchain Identifiers:**
|
|
795
|
+
- `"eth"` - Ethereum
|
|
796
|
+
- `"arb"` - Arbitrum
|
|
797
|
+
- `"bsc"` - BNB Smart Chain
|
|
798
|
+
- `"avax"` - Avalanche
|
|
799
|
+
- `"base"` - Base
|
|
800
|
+
- `"pol"` - Polygon
|
|
801
|
+
- `"gnosis"` - Gnosis Chain
|
|
802
|
+
- `"op"` - Optimism
|
|
803
|
+
- `"bera"` - Berachain
|
|
804
|
+
- `"tron"` - Tron
|
|
805
|
+
- `"aptos"` - Aptos
|
|
806
|
+
- `"sol"` - Solana
|
|
807
|
+
- `"near"` - NEAR Protocol
|
|
808
|
+
- `"xlayer"` - X Layer
|
|
809
|
+
|
|
810
|
+
**Basic Usage:**
|
|
811
|
+
|
|
812
|
+
```typescript
|
|
813
|
+
import { setRpcUrls } from 'stableflow-ai-sdk';
|
|
814
|
+
|
|
815
|
+
// Set custom RPC URLs for specific blockchains
|
|
816
|
+
setRpcUrls({
|
|
817
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
818
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
819
|
+
"sol": ["https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY"],
|
|
820
|
+
"near": ["https://rpc.mainnet.near.org"],
|
|
821
|
+
});
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
**Multiple RPC URLs (Fallback Support):**
|
|
825
|
+
|
|
826
|
+
You can provide multiple RPC URLs for the same blockchain. The SDK will use them in order, with the first URL being the primary endpoint:
|
|
827
|
+
|
|
828
|
+
```typescript
|
|
829
|
+
setRpcUrls({
|
|
830
|
+
"eth": [
|
|
831
|
+
"https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY",
|
|
832
|
+
"https://eth.merkle.io",
|
|
833
|
+
"https://cloudflare-eth.com"
|
|
834
|
+
],
|
|
835
|
+
"arb": [
|
|
836
|
+
"https://arbitrum-one-rpc.publicnode.com",
|
|
837
|
+
"https://arb1.arbitrum.io/rpc"
|
|
838
|
+
],
|
|
839
|
+
});
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
**How It Works:**
|
|
843
|
+
|
|
844
|
+
- Custom RPC URLs are prepended to the default RPC URLs for each blockchain
|
|
845
|
+
- If a custom URL already exists in the default list, it won't be duplicated
|
|
846
|
+
- The SDK will prioritize custom URLs over default ones
|
|
847
|
+
- Multiple URLs can be provided for redundancy and fallback support
|
|
848
|
+
|
|
849
|
+
**Getting Current RPC URLs:**
|
|
850
|
+
|
|
851
|
+
You can access the current RPC configuration using `NetworkRpcUrlsMap`:
|
|
852
|
+
|
|
853
|
+
```typescript
|
|
854
|
+
import { NetworkRpcUrlsMap, getRpcUrls } from 'stableflow-ai-sdk';
|
|
855
|
+
|
|
856
|
+
// Get all RPC URLs for a specific blockchain
|
|
857
|
+
const ethRpcUrls = getRpcUrls("eth");
|
|
858
|
+
console.log(ethRpcUrls); // ["https://custom-rpc.com", "https://eth.merkle.io", ...]
|
|
859
|
+
|
|
860
|
+
// Access the full RPC URLs map
|
|
861
|
+
console.log(NetworkRpcUrlsMap);
|
|
862
|
+
```
|
|
863
|
+
|
|
864
|
+
**Complete Example:**
|
|
865
|
+
|
|
866
|
+
```typescript
|
|
867
|
+
import { OpenAPI, SFA, tokens, EVMWallet, setRpcUrls } from 'stableflow-ai-sdk';
|
|
868
|
+
import { ethers } from 'ethers';
|
|
869
|
+
|
|
870
|
+
// Initialize the API client
|
|
871
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
872
|
+
OpenAPI.TOKEN = "your-JSON-Web-Token";
|
|
873
|
+
|
|
874
|
+
// Configure custom RPC endpoints
|
|
875
|
+
setRpcUrls({
|
|
876
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
877
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
878
|
+
"sol": ["https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY"],
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
// Get wallet instance (will use custom RPC if configured)
|
|
882
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
883
|
+
const signer = await provider.getSigner();
|
|
884
|
+
const wallet = new EVMWallet(provider, signer);
|
|
885
|
+
|
|
886
|
+
// Continue with your swap flow...
|
|
887
|
+
const fromToken = tokens.find(t => t.chainName === 'Ethereum' && t.symbol === 'USDT');
|
|
888
|
+
const toToken = tokens.find(t => t.chainName === 'Arbitrum' && t.symbol === 'USDT');
|
|
889
|
+
|
|
890
|
+
const quotes = await SFA.getAllQuote({
|
|
891
|
+
dry: false,
|
|
892
|
+
minInputAmount: "0.1",
|
|
893
|
+
prices: {},
|
|
894
|
+
fromToken: fromToken!,
|
|
895
|
+
toToken: toToken!,
|
|
896
|
+
wallet: wallet,
|
|
897
|
+
recipient: '0x...',
|
|
898
|
+
refundTo: '0x...',
|
|
899
|
+
amountWei: ethers.parseUnits('100', fromToken!.decimals).toString(),
|
|
900
|
+
slippageTolerance: 0.5,
|
|
901
|
+
});
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
**Best Practices:**
|
|
905
|
+
|
|
906
|
+
1. **Set RPC URLs Early**: Configure custom RPC URLs before initializing wallets or making API calls
|
|
907
|
+
2. **Use Multiple URLs**: Provide fallback RPC URLs for better reliability
|
|
908
|
+
3. **API Key Security**: Never commit API keys to version control. Use environment variables:
|
|
909
|
+
```typescript
|
|
910
|
+
setRpcUrls({
|
|
911
|
+
"eth": [process.env.ETH_RPC_URL || "https://eth.merkle.io"],
|
|
912
|
+
"sol": [process.env.SOL_RPC_URL || "https://solana-rpc.publicnode.com"],
|
|
913
|
+
});
|
|
914
|
+
```
|
|
915
|
+
4. **Test Your RPCs**: Ensure your custom RPC endpoints are working correctly before deploying
|
|
916
|
+
|
|
917
|
+
## Examples
|
|
918
|
+
|
|
919
|
+
### 🌐 Web Application Demo 2.0
|
|
920
|
+
|
|
921
|
+
**Try our interactive web app with real wallet connection:**
|
|
922
|
+
|
|
923
|
+
```bash
|
|
924
|
+
cd examples/web-demo-2.0
|
|
925
|
+
npm install
|
|
926
|
+
npm run dev
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
Features:
|
|
930
|
+
- 🔗 **Multi-Wallet Support** - Connect MetaMask, Solana, Near, Tron, Aptos wallets
|
|
931
|
+
- 🎨 **Modern UI** - Beautiful interface with real-time updates
|
|
932
|
+
- 🌐 **Multiple Chains** - Support for all major blockchains
|
|
933
|
+
- 💰 **Multi-Token Support** - USDT and USDC bridging
|
|
934
|
+
- 💵 **Real-Time Quotes** - Compare quotes from all bridge services
|
|
935
|
+
- 🚀 **One-Click Execution** - Execute transactions with automatic approval
|
|
936
|
+
- 📊 **Transaction History** - Track your bridging activity with status polling
|
|
937
|
+
|
|
938
|
+
**Tech Stack**: TypeScript, React, Vite, StableFlow SDK
|
|
939
|
+
|
|
940
|
+
See [examples/web-demo-2.0/README.md](examples/web-demo-2.0/README.md) for full documentation.
|
|
941
|
+
|
|
942
|
+
## Migration from v1.0
|
|
943
|
+
|
|
944
|
+
If you're using SDK v1.0, see the [v1.0 documentation](README-v1.md) for the old API methods (`getQuote`, `getExecutionStatus`, `submitDepositTx`).
|
|
945
|
+
|
|
946
|
+
Key differences in v2.0:
|
|
947
|
+
- `getAllQuote` replaces `getQuote` and returns quotes from all services
|
|
948
|
+
- `send` replaces `submitDepositTx` and handles transaction submission automatically
|
|
949
|
+
- `getStatus` replaces `getExecutionStatus` with service-specific status checking
|
|
950
|
+
- Wallet instances are now required for quote requests
|
|
951
|
+
- Token configurations are provided via the `tokens` export
|
|
952
|
+
|
|
953
|
+
## Development
|
|
954
|
+
|
|
955
|
+
Developer commands:
|
|
956
|
+
|
|
957
|
+
```bash
|
|
958
|
+
# Install dependencies
|
|
959
|
+
npm install
|
|
960
|
+
|
|
961
|
+
# Build the SDK
|
|
962
|
+
npm run build
|
|
963
|
+
|
|
964
|
+
# Clean build artifacts
|
|
965
|
+
npm run clean
|
|
966
|
+
|
|
967
|
+
# Watch mode for development
|
|
968
|
+
npm run dev
|
|
969
|
+
```
|
|
970
|
+
|
|
971
|
+
## License
|
|
972
|
+
|
|
973
|
+
MIT
|
|
974
|
+
|
|
975
|
+
## Support
|
|
976
|
+
|
|
977
|
+
For issues or support:
|
|
978
|
+
|
|
979
|
+
- Open an issue on GitHub
|
|
980
|
+
- Check the documentation
|
|
981
|
+
- Contact our support team
|
|
982
|
+
|
|
983
|
+
## Changelog
|
|
984
|
+
|
|
985
|
+
### v2.0.0
|
|
986
|
+
- Added `getAllQuote` method to get quotes from all bridge services
|
|
987
|
+
- Added `send` method for executing transactions
|
|
988
|
+
- Added `getStatus` method for checking transaction status
|
|
989
|
+
- Support for multiple bridge services (OneClick, CCTP, USDT0)
|
|
990
|
+
- Wallet integration for multiple chains
|
|
991
|
+
- Pre-configured token information
|
|
992
|
+
- **USDT0 Improvements**:
|
|
993
|
+
- Support for bridging from Solana as source chain
|
|
994
|
+
- Multi-hop routing support for cross-chain transfers
|
|
995
|
+
- Improved fee estimation accuracy
|
|
996
|
+
- Dynamic time estimation based on chain block times
|
|
997
|
+
- Fixed multi-hop composer issues
|
|
998
|
+
|
|
999
|
+
### v1.0.0
|
|
1000
|
+
- Initial release
|
|
1001
|
+
- Support for cross-chain token swaps
|
|
1002
|
+
- JWT authentication support
|
|
1003
|
+
- Full TypeScript type definitions
|