stableflow-ai-sdk 2.0.1 → 2.0.3
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 +484 -8
- package/dist/index.d.mts +153 -64
- package/dist/index.d.ts +153 -64
- package/dist/index.js +1163 -357
- package/dist/index.mjs +1148 -344
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -23,13 +23,19 @@ pnpm add stableflow-ai-sdk
|
|
|
23
23
|
## Quick Start
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
|
-
import { OpenAPI, SFA, tokens, EVMWallet } from 'stableflow-ai-sdk';
|
|
26
|
+
import { OpenAPI, SFA, tokens, EVMWallet, setRpcUrls } from 'stableflow-ai-sdk';
|
|
27
27
|
import { ethers } from 'ethers';
|
|
28
28
|
|
|
29
29
|
// Initialize the API client
|
|
30
30
|
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
31
31
|
OpenAPI.TOKEN = "your-JSON-Web-Token";
|
|
32
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
|
+
|
|
33
39
|
// Get wallet instance (example with EVM)
|
|
34
40
|
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
35
41
|
const signer = await provider.getSigner();
|
|
@@ -51,6 +57,17 @@ const quotes = await SFA.getAllQuote({
|
|
|
51
57
|
refundTo: '0x...', // refund address
|
|
52
58
|
amountWei: ethers.parseUnits('100', fromToken!.decimals).toString(),
|
|
53
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
|
+
},
|
|
54
71
|
});
|
|
55
72
|
|
|
56
73
|
// Select the best quote and send transaction
|
|
@@ -107,6 +124,14 @@ const quotes = await SFA.getAllQuote({
|
|
|
107
124
|
refundTo: string, // Refund address on source chain
|
|
108
125
|
amountWei: string, // Amount in smallest units (wei/satoshi/etc.)
|
|
109
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
|
+
// default is true
|
|
133
|
+
isProxy?: boolean;
|
|
134
|
+
};
|
|
110
135
|
});
|
|
111
136
|
```
|
|
112
137
|
|
|
@@ -290,11 +315,12 @@ const finalStatus = await pollTransactionStatus(Service.OneClick, {
|
|
|
290
315
|
|
|
291
316
|
## Supported Bridge Services
|
|
292
317
|
|
|
293
|
-
The SDK supports three bridge services:
|
|
318
|
+
The SDK supports three bridge services for general cross-chain swaps, plus a dedicated Hyperliquid deposit flow:
|
|
294
319
|
|
|
295
320
|
- **OneClick** (`Service.OneClick`) - Native StableFlow bridge service
|
|
296
321
|
- **CCTP** (`Service.CCTP`) - Circle's Cross-Chain Transfer Protocol
|
|
297
322
|
- **USDT0** (`Service.Usdt0`) - LayerZero-based USDT bridge
|
|
323
|
+
- **Hyperliquid** – Deposit from multiple chains into Hyperliquid (destination: Arbitrum USDC). See [Hyperliquid Service](#hyperliquid-service) below.
|
|
298
324
|
|
|
299
325
|
Each service has different characteristics:
|
|
300
326
|
- Different fee structures
|
|
@@ -302,14 +328,113 @@ Each service has different characteristics:
|
|
|
302
328
|
- Different processing times
|
|
303
329
|
- Different minimum/maximum amounts
|
|
304
330
|
|
|
331
|
+
### USDT0 Service Features
|
|
332
|
+
|
|
333
|
+
The USDT0 service provides LayerZero-based USDT bridging with the following capabilities:
|
|
334
|
+
|
|
335
|
+
- **Multi-chain Support**: Supports bridging from EVM chains (Ethereum, Arbitrum, Polygon, Optimism, etc.), Solana, and Tron
|
|
336
|
+
- **Multi-hop Routing**: Automatically handles multi-hop transfers when direct routes are not available (e.g., Solana → Arbitrum → Ethereum)
|
|
337
|
+
- **Dynamic Time Estimation**: Calculates estimated completion time based on source and destination chain block times and confirmations
|
|
338
|
+
- **Accurate Fee Estimation**: Improved fee calculation including LayerZero message fees, gas costs, and legacy mesh transfer fees (0.03% for legacy routes)
|
|
339
|
+
- **Legacy and Upgradeable Support**: Seamlessly handles both legacy and upgradeable OFT contracts
|
|
340
|
+
|
|
305
341
|
Use `getAllQuote` to compare all available routes and select the best one for your use case.
|
|
306
342
|
|
|
343
|
+
### Hyperliquid Service
|
|
344
|
+
|
|
345
|
+
The Hyperliquid service enables depositing tokens from multiple source chains into Hyperliquid. The destination is fixed as **USDC on Arbitrum**; the SDK uses the OneClick bridge under the hood to swap/bridge from your chosen source token to Arbitrum USDC, then submits a deposit with permit to the Hyperliquid deposit API.
|
|
346
|
+
|
|
347
|
+
**Exports:**
|
|
348
|
+
|
|
349
|
+
- `Hyperliquid` – singleton service instance
|
|
350
|
+
- `HyperliquidFromTokens` – list of supported source tokens (all tokens except Arbitrum USDC)
|
|
351
|
+
- `HyperliuquidToToken` – destination token config (Arbitrum USDC)
|
|
352
|
+
- `HyperliuquidMinAmount` – minimum amount in wei (e.g. 5 USDC)
|
|
353
|
+
- Types: `HyperliquidQuoteParams`, `HyperliquidTransferParams`, `HyperliquidDepositParams`, `HyperliquidGetStatusParams`, `HyperliquidDepositResponse`, `HyperliquidDepositStatusResponse`, etc.
|
|
354
|
+
|
|
355
|
+
**Methods:**
|
|
356
|
+
|
|
357
|
+
| Method | Description |
|
|
358
|
+
|--------|-------------|
|
|
359
|
+
| `quote(params)` | Get a quote for depositing to Hyperliquid. Returns `{ quote, error }`. |
|
|
360
|
+
| `transfer(params)` | Send tokens from the user's wallet to the bridge (uses OneClick). Returns source chain tx hash. |
|
|
361
|
+
| `deposit(params)` | After transfer, submit deposit with EIP-2612 permit. Returns `{ code, data: { depositId } }`. |
|
|
362
|
+
| `getStatus(params)` | Query deposit status by `depositId`. Returns `{ code, data: { status, txHash } }`. |
|
|
363
|
+
|
|
364
|
+
**Flow (typical):**
|
|
365
|
+
|
|
366
|
+
1. User selects source token from `HyperliquidFromTokens` and amount (≥ `HyperliuquidMinAmount`).
|
|
367
|
+
2. Call `Hyperliquid.quote(params)` (optionally with `dry: true` for preview, then `dry: false` to get `depositAddress`).
|
|
368
|
+
3. Call `Hyperliquid.transfer({ wallet, quote, evmWallet, evmWalletAddress })` to send tokens; receive `txhash`.
|
|
369
|
+
4. Optionally switch the wallet to Arbitrum, then call `Hyperliquid.deposit({ ...transferParams, txhash })` to submit the deposit and get `depositId`.
|
|
370
|
+
5. Poll or one-off check with `Hyperliquid.getStatus({ depositId })` for `status` and `txHash`. `status` enum is `type HyperliquidDepositStatus = "PROCESSING" | "SUCCESS" | "REFUNDED" | "FAILED";`
|
|
371
|
+
|
|
372
|
+
**Example:**
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import {
|
|
376
|
+
Hyperliquid,
|
|
377
|
+
HyperliquidFromTokens,
|
|
378
|
+
HyperliuquidToToken,
|
|
379
|
+
HyperliuquidMinAmount,
|
|
380
|
+
OpenAPI,
|
|
381
|
+
} from 'stableflow-ai-sdk';
|
|
382
|
+
import Big from 'big.js';
|
|
383
|
+
|
|
384
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
385
|
+
OpenAPI.TOKEN = 'your-JWT';
|
|
386
|
+
|
|
387
|
+
// 1. Quote (dry: false to get deposit address for transfer)
|
|
388
|
+
const quoteRes = await Hyperliquid.quote({
|
|
389
|
+
dry: false,
|
|
390
|
+
slippageTolerance: 0.05,
|
|
391
|
+
refundTo: evmAddress,
|
|
392
|
+
recipient: evmAddress,
|
|
393
|
+
wallet,
|
|
394
|
+
fromToken: selectedFromToken,
|
|
395
|
+
prices: {},
|
|
396
|
+
amountWei: Big(amount).times(10 ** HyperliuquidToToken.decimals).toFixed(0, 0),
|
|
397
|
+
});
|
|
398
|
+
if (quoteRes.error || !quoteRes.quote) throw new Error(quoteRes.error || 'No quote');
|
|
399
|
+
const quote = quoteRes.quote;
|
|
400
|
+
|
|
401
|
+
// 2. Transfer on source chain
|
|
402
|
+
const txhash = await Hyperliquid.transfer({
|
|
403
|
+
wallet,
|
|
404
|
+
evmWallet,
|
|
405
|
+
evmWalletAddress,
|
|
406
|
+
quote,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// 3. Submit deposit (after switching to Arbitrum if needed)
|
|
410
|
+
const depositRes = await Hyperliquid.deposit({
|
|
411
|
+
wallet,
|
|
412
|
+
evmWallet,
|
|
413
|
+
evmWalletAddress,
|
|
414
|
+
quote,
|
|
415
|
+
txhash,
|
|
416
|
+
});
|
|
417
|
+
const depositId = depositRes.data?.depositId;
|
|
418
|
+
|
|
419
|
+
// 4. Check status
|
|
420
|
+
const statusRes = await Hyperliquid.getStatus({ depositId: String(depositId) });
|
|
421
|
+
// statusRes.data.status, statusRes.data.txHash
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Token configs:**
|
|
425
|
+
|
|
426
|
+
- Use `HyperliquidFromTokens` for the source token list (filter by `chainType === 'evm'` if you only support EVM).
|
|
427
|
+
- Destination is always `HyperliuquidToToken` (Arbitrum USDC).
|
|
428
|
+
- Enforce minimum amount with `HyperliuquidMinAmount` so users do not send below the bridge minimum.
|
|
429
|
+
|
|
307
430
|
## Wallet Integration
|
|
308
431
|
|
|
309
432
|
The SDK supports multiple wallet types:
|
|
310
433
|
|
|
311
434
|
### EVM Wallets (Ethereum, Arbitrum, Polygon, etc.)
|
|
312
435
|
|
|
436
|
+
**Using ethers.js with BrowserProvider:**
|
|
437
|
+
|
|
313
438
|
```typescript
|
|
314
439
|
import { EVMWallet } from 'stableflow-ai-sdk';
|
|
315
440
|
import { ethers } from 'ethers';
|
|
@@ -319,40 +444,145 @@ const signer = await provider.getSigner();
|
|
|
319
444
|
const wallet = new EVMWallet(provider, signer);
|
|
320
445
|
```
|
|
321
446
|
|
|
447
|
+
**Using wagmi/viem (recommended for React apps):**
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
import { EVMWallet } from 'stableflow-ai-sdk';
|
|
451
|
+
import { ethers } from 'ethers';
|
|
452
|
+
import { usePublicClient, useWalletClient } from 'wagmi';
|
|
453
|
+
|
|
454
|
+
// In your React component
|
|
455
|
+
const publicClient = usePublicClient();
|
|
456
|
+
const { data: walletClient } = useWalletClient();
|
|
457
|
+
|
|
458
|
+
const provider = new ethers.BrowserProvider(publicClient);
|
|
459
|
+
const signer = walletClient
|
|
460
|
+
? await new ethers.BrowserProvider(walletClient).getSigner()
|
|
461
|
+
: null;
|
|
462
|
+
|
|
463
|
+
const wallet = new EVMWallet(provider, signer);
|
|
464
|
+
```
|
|
465
|
+
|
|
322
466
|
### Solana Wallets
|
|
323
467
|
|
|
468
|
+
**Using @solana/wallet-adapter-react (recommended for React apps):**
|
|
469
|
+
|
|
470
|
+
```typescript
|
|
471
|
+
import { SolanaWallet } from 'stableflow-ai-sdk';
|
|
472
|
+
import { useWallet } from '@solana/wallet-adapter-react';
|
|
473
|
+
|
|
474
|
+
// In your React component
|
|
475
|
+
const { publicKey, signTransaction } = useWallet();
|
|
476
|
+
|
|
477
|
+
const wallet = new SolanaWallet({
|
|
478
|
+
publicKey: publicKey,
|
|
479
|
+
signer: { signTransaction }
|
|
480
|
+
});
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Using wallet adapter directly:**
|
|
484
|
+
|
|
324
485
|
```typescript
|
|
325
486
|
import { SolanaWallet } from 'stableflow-ai-sdk';
|
|
326
487
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
327
488
|
|
|
328
489
|
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
329
|
-
const
|
|
490
|
+
const publicKey = new PublicKey('YOUR_SOLANA_ADDRESS');
|
|
491
|
+
|
|
492
|
+
const wallet = new SolanaWallet({
|
|
493
|
+
publicKey: publicKey,
|
|
494
|
+
signer: {
|
|
495
|
+
signTransaction: async (transaction) => {
|
|
496
|
+
// Sign transaction using your wallet adapter
|
|
497
|
+
// Example with Phantom:
|
|
498
|
+
// const provider = window.solana;
|
|
499
|
+
// return await provider.signTransaction(transaction);
|
|
500
|
+
return signedTransaction;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
});
|
|
330
504
|
```
|
|
331
505
|
|
|
506
|
+
**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.
|
|
507
|
+
|
|
332
508
|
### Near Wallets
|
|
333
509
|
|
|
334
510
|
```typescript
|
|
335
511
|
import { NearWallet } from 'stableflow-ai-sdk';
|
|
512
|
+
import { setupWalletSelector } from '@near-wallet-selector/core';
|
|
513
|
+
|
|
514
|
+
// Setup wallet selector (e.g., using @near-wallet-selector)
|
|
515
|
+
const selector = await setupWalletSelector({
|
|
516
|
+
network: 'mainnet',
|
|
517
|
+
modules: [
|
|
518
|
+
// Add your wallet modules here
|
|
519
|
+
]
|
|
520
|
+
});
|
|
336
521
|
|
|
337
|
-
const wallet = new NearWallet(
|
|
522
|
+
const wallet = new NearWallet(selector);
|
|
338
523
|
```
|
|
339
524
|
|
|
525
|
+
**Note**: NearWallet requires a wallet selector instance from `@near-wallet-selector/core`. The selector handles wallet connection and transaction signing.
|
|
526
|
+
|
|
340
527
|
### Tron Wallets
|
|
341
528
|
|
|
342
529
|
```typescript
|
|
343
530
|
import { TronWallet } from 'stableflow-ai-sdk';
|
|
344
531
|
|
|
345
|
-
|
|
532
|
+
// Using TronLink or other Tron wallet adapters
|
|
533
|
+
const wallet = new TronWallet({
|
|
534
|
+
signAndSendTransaction: async (transaction: any) => {
|
|
535
|
+
// Sign transaction using TronWeb
|
|
536
|
+
const signedTransaction = await window.tronWeb.trx.sign(transaction);
|
|
537
|
+
// Send signed transaction
|
|
538
|
+
return await window.tronWeb.trx.sendRawTransaction(signedTransaction);
|
|
539
|
+
},
|
|
540
|
+
address: window.tronWeb?.defaultAddress?.base58, // User's Tron address
|
|
541
|
+
});
|
|
346
542
|
```
|
|
347
543
|
|
|
544
|
+
**With TronLink Wallet:**
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
import { TronWallet } from 'stableflow-ai-sdk';
|
|
548
|
+
|
|
549
|
+
// Wait for TronLink to be available
|
|
550
|
+
if (window.tronWeb && window.tronWeb.ready) {
|
|
551
|
+
const wallet = new TronWallet({
|
|
552
|
+
signAndSendTransaction: async (transaction: any) => {
|
|
553
|
+
const signedTransaction = await window.tronWeb.trx.sign(transaction);
|
|
554
|
+
const result = await window.tronWeb.trx.sendRawTransaction(signedTransaction);
|
|
555
|
+
// Return transaction ID (txid)
|
|
556
|
+
return typeof result === 'string' ? result : result.txid;
|
|
557
|
+
},
|
|
558
|
+
address: window.tronWeb.defaultAddress.base58,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
**Note:** The `signAndSendTransaction` function should:
|
|
564
|
+
- Accept a transaction object as parameter
|
|
565
|
+
- Sign the transaction using the connected wallet
|
|
566
|
+
- Send the signed transaction to the network
|
|
567
|
+
- Return the transaction ID (txid) as a string, or an object with a `txid` property
|
|
568
|
+
|
|
348
569
|
### Aptos Wallets
|
|
349
570
|
|
|
350
571
|
```typescript
|
|
351
572
|
import { AptosWallet } from 'stableflow-ai-sdk';
|
|
573
|
+
import { useWallet } from '@aptos-labs/wallet-adapter-react';
|
|
352
574
|
|
|
353
|
-
|
|
575
|
+
// Using Aptos wallet adapter
|
|
576
|
+
const { account, signAndSubmitTransaction } = useWallet();
|
|
577
|
+
|
|
578
|
+
const wallet = new AptosWallet({
|
|
579
|
+
account: account,
|
|
580
|
+
signAndSubmitTransaction: signAndSubmitTransaction,
|
|
581
|
+
});
|
|
354
582
|
```
|
|
355
583
|
|
|
584
|
+
**Note**: AptosWallet requires an account object and a `signAndSubmitTransaction` function from the Aptos wallet adapter (e.g., `@aptos-labs/wallet-adapter-react`).
|
|
585
|
+
|
|
356
586
|
## Token Configuration
|
|
357
587
|
|
|
358
588
|
The SDK provides pre-configured token information:
|
|
@@ -386,20 +616,28 @@ Each token configuration includes:
|
|
|
386
616
|
- `contractAddress` - Token contract address
|
|
387
617
|
- `assetId` - StableFlow asset identifier
|
|
388
618
|
- `services` - Array of supported bridge services
|
|
389
|
-
- `
|
|
619
|
+
- `rpcUrls` - RPC endpoint URLs
|
|
390
620
|
|
|
391
621
|
## Complete Example
|
|
392
622
|
|
|
623
|
+
### Example 1: EVM to EVM Bridge (Ethereum → Arbitrum)
|
|
624
|
+
|
|
393
625
|
Here's a complete example of a cross-chain swap:
|
|
394
626
|
|
|
395
627
|
```typescript
|
|
396
|
-
import { SFA, OpenAPI, tokens, EVMWallet, Service, TransactionStatus } from 'stableflow-ai-sdk';
|
|
628
|
+
import { SFA, OpenAPI, tokens, EVMWallet, Service, TransactionStatus, setRpcUrls } from 'stableflow-ai-sdk';
|
|
397
629
|
import { ethers } from 'ethers';
|
|
398
630
|
|
|
399
631
|
// 1. Initialize SDK
|
|
400
632
|
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
401
633
|
OpenAPI.TOKEN = 'your-jwt-token';
|
|
402
634
|
|
|
635
|
+
// (Optional) Configure custom RPC endpoints
|
|
636
|
+
setRpcUrls({
|
|
637
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
638
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
639
|
+
});
|
|
640
|
+
|
|
403
641
|
// 2. Setup wallet
|
|
404
642
|
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
405
643
|
await provider.send('eth_requestAccounts', []);
|
|
@@ -439,6 +677,7 @@ if (!selectedQuote || !selectedQuote.quote) {
|
|
|
439
677
|
}
|
|
440
678
|
|
|
441
679
|
console.log(`Selected route: ${selectedQuote.serviceType}`);
|
|
680
|
+
console.log(`Estimated time: ${selectedQuote.quote.estimateTime}s`);
|
|
442
681
|
|
|
443
682
|
// 6. Handle approval if needed
|
|
444
683
|
if (selectedQuote.quote.needApprove) {
|
|
@@ -487,6 +726,106 @@ const checkStatus = async () => {
|
|
|
487
726
|
checkStatus();
|
|
488
727
|
```
|
|
489
728
|
|
|
729
|
+
### Example 2: Solana to EVM Bridge (Solana → Ethereum)
|
|
730
|
+
|
|
731
|
+
Bridge USDT from Solana to Ethereum using USDT0:
|
|
732
|
+
|
|
733
|
+
```typescript
|
|
734
|
+
import { SFA, OpenAPI, tokens, SolanaWallet, Service, TransactionStatus, setRpcUrls } from 'stableflow-ai-sdk';
|
|
735
|
+
import { Connection, PublicKey } from '@solana/web3.js';
|
|
736
|
+
|
|
737
|
+
// 1. Initialize SDK
|
|
738
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
739
|
+
OpenAPI.TOKEN = 'your-jwt-token';
|
|
740
|
+
|
|
741
|
+
// (Optional) Configure custom RPC endpoints
|
|
742
|
+
setRpcUrls({
|
|
743
|
+
"sol": ["https://api.mainnet-beta.solana.com"],
|
|
744
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
// 2. Setup Solana wallet
|
|
748
|
+
// Note: In a real application, get these from your wallet adapter
|
|
749
|
+
// Example with @solana/wallet-adapter-react:
|
|
750
|
+
// const { publicKey, signTransaction } = useWallet();
|
|
751
|
+
// const wallet = new SolanaWallet({
|
|
752
|
+
// publicKey: publicKey,
|
|
753
|
+
// signer: { signTransaction }
|
|
754
|
+
// });
|
|
755
|
+
|
|
756
|
+
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
757
|
+
const publicKey = new PublicKey('YOUR_SOLANA_ADDRESS');
|
|
758
|
+
const wallet = new SolanaWallet({
|
|
759
|
+
publicKey: publicKey,
|
|
760
|
+
signer: {
|
|
761
|
+
signTransaction: async (tx) => {
|
|
762
|
+
// Sign transaction using your Solana wallet adapter
|
|
763
|
+
// Example with Phantom:
|
|
764
|
+
// const provider = window.solana;
|
|
765
|
+
// return await provider.signTransaction(tx);
|
|
766
|
+
throw new Error('Implement wallet signing');
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
// 3. Select tokens
|
|
772
|
+
const fromToken = tokens.find(t =>
|
|
773
|
+
t.chainName === 'Solana' && t.symbol === 'USDT'
|
|
774
|
+
);
|
|
775
|
+
const toToken = tokens.find(t =>
|
|
776
|
+
t.chainName === 'Ethereum' && t.symbol === 'USDT'
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
if (!fromToken || !toToken) {
|
|
780
|
+
throw new Error('Token pair not supported');
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// 4. Get quotes (USDT0 will automatically use multi-hop routing if needed)
|
|
784
|
+
const quotes = await SFA.getAllQuote({
|
|
785
|
+
dry: false,
|
|
786
|
+
prices: {},
|
|
787
|
+
fromToken,
|
|
788
|
+
toToken,
|
|
789
|
+
wallet,
|
|
790
|
+
recipient: '0x...', // Ethereum recipient address
|
|
791
|
+
refundTo: publicKey.toString(), // Solana refund address
|
|
792
|
+
amountWei: '1000000', // 1 USDT (6 decimals)
|
|
793
|
+
slippageTolerance: 0.5,
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
// 5. Find USDT0 quote
|
|
797
|
+
const usdt0Quote = quotes.find(q => q.serviceType === Service.Usdt0 && q.quote && !q.error);
|
|
798
|
+
if (usdt0Quote && usdt0Quote.quote) {
|
|
799
|
+
console.log(`USDT0 route available`);
|
|
800
|
+
console.log(`Estimated time: ${usdt0Quote.quote.estimateTime}s`);
|
|
801
|
+
console.log(`Total fees: $${usdt0Quote.quote.totalFeesUsd}`);
|
|
802
|
+
|
|
803
|
+
// 6. Send transaction
|
|
804
|
+
const txHash = await SFA.send(Service.Usdt0, {
|
|
805
|
+
wallet,
|
|
806
|
+
quote: usdt0Quote.quote,
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
console.log('Transaction submitted:', txHash);
|
|
810
|
+
|
|
811
|
+
// 7. Poll for status
|
|
812
|
+
const checkStatus = async () => {
|
|
813
|
+
const status = await SFA.getStatus(Service.Usdt0, { hash: txHash });
|
|
814
|
+
console.log('Current status:', status.status);
|
|
815
|
+
|
|
816
|
+
if (status.status === TransactionStatus.Success) {
|
|
817
|
+
console.log('Bridge completed! Destination tx:', status.toChainTxHash);
|
|
818
|
+
} else if (status.status === TransactionStatus.Failed) {
|
|
819
|
+
console.log('Bridge failed or refunded');
|
|
820
|
+
} else {
|
|
821
|
+
setTimeout(checkStatus, 5000);
|
|
822
|
+
}
|
|
823
|
+
};
|
|
824
|
+
|
|
825
|
+
checkStatus();
|
|
826
|
+
}
|
|
827
|
+
```
|
|
828
|
+
|
|
490
829
|
## Error Handling
|
|
491
830
|
|
|
492
831
|
The SDK throws typed errors that you can catch and handle:
|
|
@@ -534,6 +873,137 @@ The SDK provides full TypeScript type definitions:
|
|
|
534
873
|
- `WalletConfig` - Wallet interface
|
|
535
874
|
- `TransactionStatus` - Transaction status enum
|
|
536
875
|
|
|
876
|
+
## Custom RPC Configuration
|
|
877
|
+
|
|
878
|
+
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.
|
|
879
|
+
|
|
880
|
+
### Setting Custom RPC URLs
|
|
881
|
+
|
|
882
|
+
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.
|
|
883
|
+
|
|
884
|
+
**Supported Blockchain Identifiers:**
|
|
885
|
+
- `"eth"` - Ethereum
|
|
886
|
+
- `"arb"` - Arbitrum
|
|
887
|
+
- `"bsc"` - BNB Smart Chain
|
|
888
|
+
- `"avax"` - Avalanche
|
|
889
|
+
- `"base"` - Base
|
|
890
|
+
- `"pol"` - Polygon
|
|
891
|
+
- `"gnosis"` - Gnosis Chain
|
|
892
|
+
- `"op"` - Optimism
|
|
893
|
+
- `"bera"` - Berachain
|
|
894
|
+
- `"tron"` - Tron
|
|
895
|
+
- `"aptos"` - Aptos
|
|
896
|
+
- `"sol"` - Solana
|
|
897
|
+
- `"near"` - NEAR Protocol
|
|
898
|
+
- `"xlayer"` - X Layer
|
|
899
|
+
|
|
900
|
+
**Basic Usage:**
|
|
901
|
+
|
|
902
|
+
```typescript
|
|
903
|
+
import { setRpcUrls } from 'stableflow-ai-sdk';
|
|
904
|
+
|
|
905
|
+
// Set custom RPC URLs for specific blockchains
|
|
906
|
+
setRpcUrls({
|
|
907
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
908
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
909
|
+
"sol": ["https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY"],
|
|
910
|
+
"near": ["https://rpc.mainnet.near.org"],
|
|
911
|
+
});
|
|
912
|
+
```
|
|
913
|
+
|
|
914
|
+
**Multiple RPC URLs (Fallback Support):**
|
|
915
|
+
|
|
916
|
+
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:
|
|
917
|
+
|
|
918
|
+
```typescript
|
|
919
|
+
setRpcUrls({
|
|
920
|
+
"eth": [
|
|
921
|
+
"https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY",
|
|
922
|
+
"https://eth.merkle.io",
|
|
923
|
+
"https://cloudflare-eth.com"
|
|
924
|
+
],
|
|
925
|
+
"arb": [
|
|
926
|
+
"https://arbitrum-one-rpc.publicnode.com",
|
|
927
|
+
"https://arb1.arbitrum.io/rpc"
|
|
928
|
+
],
|
|
929
|
+
});
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
**How It Works:**
|
|
933
|
+
|
|
934
|
+
- Custom RPC URLs are prepended to the default RPC URLs for each blockchain
|
|
935
|
+
- If a custom URL already exists in the default list, it won't be duplicated
|
|
936
|
+
- The SDK will prioritize custom URLs over default ones
|
|
937
|
+
- Multiple URLs can be provided for redundancy and fallback support
|
|
938
|
+
|
|
939
|
+
**Getting Current RPC URLs:**
|
|
940
|
+
|
|
941
|
+
You can access the current RPC configuration using `NetworkRpcUrlsMap`:
|
|
942
|
+
|
|
943
|
+
```typescript
|
|
944
|
+
import { NetworkRpcUrlsMap, getRpcUrls } from 'stableflow-ai-sdk';
|
|
945
|
+
|
|
946
|
+
// Get all RPC URLs for a specific blockchain
|
|
947
|
+
const ethRpcUrls = getRpcUrls("eth");
|
|
948
|
+
console.log(ethRpcUrls); // ["https://custom-rpc.com", "https://eth.merkle.io", ...]
|
|
949
|
+
|
|
950
|
+
// Access the full RPC URLs map
|
|
951
|
+
console.log(NetworkRpcUrlsMap);
|
|
952
|
+
```
|
|
953
|
+
|
|
954
|
+
**Complete Example:**
|
|
955
|
+
|
|
956
|
+
```typescript
|
|
957
|
+
import { OpenAPI, SFA, tokens, EVMWallet, setRpcUrls } from 'stableflow-ai-sdk';
|
|
958
|
+
import { ethers } from 'ethers';
|
|
959
|
+
|
|
960
|
+
// Initialize the API client
|
|
961
|
+
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
962
|
+
OpenAPI.TOKEN = "your-JSON-Web-Token";
|
|
963
|
+
|
|
964
|
+
// Configure custom RPC endpoints
|
|
965
|
+
setRpcUrls({
|
|
966
|
+
"eth": ["https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY"],
|
|
967
|
+
"arb": ["https://arbitrum-one-rpc.publicnode.com"],
|
|
968
|
+
"sol": ["https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY"],
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
// Get wallet instance (will use custom RPC if configured)
|
|
972
|
+
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
973
|
+
const signer = await provider.getSigner();
|
|
974
|
+
const wallet = new EVMWallet(provider, signer);
|
|
975
|
+
|
|
976
|
+
// Continue with your swap flow...
|
|
977
|
+
const fromToken = tokens.find(t => t.chainName === 'Ethereum' && t.symbol === 'USDT');
|
|
978
|
+
const toToken = tokens.find(t => t.chainName === 'Arbitrum' && t.symbol === 'USDT');
|
|
979
|
+
|
|
980
|
+
const quotes = await SFA.getAllQuote({
|
|
981
|
+
dry: false,
|
|
982
|
+
minInputAmount: "0.1",
|
|
983
|
+
prices: {},
|
|
984
|
+
fromToken: fromToken!,
|
|
985
|
+
toToken: toToken!,
|
|
986
|
+
wallet: wallet,
|
|
987
|
+
recipient: '0x...',
|
|
988
|
+
refundTo: '0x...',
|
|
989
|
+
amountWei: ethers.parseUnits('100', fromToken!.decimals).toString(),
|
|
990
|
+
slippageTolerance: 0.5,
|
|
991
|
+
});
|
|
992
|
+
```
|
|
993
|
+
|
|
994
|
+
**Best Practices:**
|
|
995
|
+
|
|
996
|
+
1. **Set RPC URLs Early**: Configure custom RPC URLs before initializing wallets or making API calls
|
|
997
|
+
2. **Use Multiple URLs**: Provide fallback RPC URLs for better reliability
|
|
998
|
+
3. **API Key Security**: Never commit API keys to version control. Use environment variables:
|
|
999
|
+
```typescript
|
|
1000
|
+
setRpcUrls({
|
|
1001
|
+
"eth": [process.env.ETH_RPC_URL || "https://eth.merkle.io"],
|
|
1002
|
+
"sol": [process.env.SOL_RPC_URL || "https://solana-rpc.publicnode.com"],
|
|
1003
|
+
});
|
|
1004
|
+
```
|
|
1005
|
+
4. **Test Your RPCs**: Ensure your custom RPC endpoints are working correctly before deploying
|
|
1006
|
+
|
|
537
1007
|
## Examples
|
|
538
1008
|
|
|
539
1009
|
### 🌐 Web Application Demo 2.0
|
|
@@ -609,6 +1079,12 @@ For issues or support:
|
|
|
609
1079
|
- Support for multiple bridge services (OneClick, CCTP, USDT0)
|
|
610
1080
|
- Wallet integration for multiple chains
|
|
611
1081
|
- Pre-configured token information
|
|
1082
|
+
- **USDT0 Improvements**:
|
|
1083
|
+
- Support for bridging from Solana as source chain
|
|
1084
|
+
- Multi-hop routing support for cross-chain transfers
|
|
1085
|
+
- Improved fee estimation accuracy
|
|
1086
|
+
- Dynamic time estimation based on chain block times
|
|
1087
|
+
- Fixed multi-hop composer issues
|
|
612
1088
|
|
|
613
1089
|
### v1.0.0
|
|
614
1090
|
- Initial release
|