stableflow-ai-sdk 2.0.2 → 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 -17
- package/dist/index.d.mts +152 -68
- package/dist/index.d.ts +152 -68
- package/dist/index.js +1097 -352
- package/dist/index.mjs +1082 -339
- 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,14 +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%
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
+
},
|
|
62
71
|
});
|
|
63
72
|
|
|
64
73
|
// Select the best quote and send transaction
|
|
@@ -115,7 +124,14 @@ const quotes = await SFA.getAllQuote({
|
|
|
115
124
|
refundTo: string, // Refund address on source chain
|
|
116
125
|
amountWei: string, // Amount in smallest units (wei/satoshi/etc.)
|
|
117
126
|
slippageTolerance: number, // Slippage tolerance percentage (e.g., 0.5 for 0.5%)
|
|
118
|
-
|
|
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
|
+
};
|
|
119
135
|
});
|
|
120
136
|
```
|
|
121
137
|
|
|
@@ -299,11 +315,12 @@ const finalStatus = await pollTransactionStatus(Service.OneClick, {
|
|
|
299
315
|
|
|
300
316
|
## Supported Bridge Services
|
|
301
317
|
|
|
302
|
-
The SDK supports three bridge services:
|
|
318
|
+
The SDK supports three bridge services for general cross-chain swaps, plus a dedicated Hyperliquid deposit flow:
|
|
303
319
|
|
|
304
320
|
- **OneClick** (`Service.OneClick`) - Native StableFlow bridge service
|
|
305
321
|
- **CCTP** (`Service.CCTP`) - Circle's Cross-Chain Transfer Protocol
|
|
306
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.
|
|
307
324
|
|
|
308
325
|
Each service has different characteristics:
|
|
309
326
|
- Different fee structures
|
|
@@ -311,14 +328,113 @@ Each service has different characteristics:
|
|
|
311
328
|
- Different processing times
|
|
312
329
|
- Different minimum/maximum amounts
|
|
313
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
|
+
|
|
314
341
|
Use `getAllQuote` to compare all available routes and select the best one for your use case.
|
|
315
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
|
+
|
|
316
430
|
## Wallet Integration
|
|
317
431
|
|
|
318
432
|
The SDK supports multiple wallet types:
|
|
319
433
|
|
|
320
434
|
### EVM Wallets (Ethereum, Arbitrum, Polygon, etc.)
|
|
321
435
|
|
|
436
|
+
**Using ethers.js with BrowserProvider:**
|
|
437
|
+
|
|
322
438
|
```typescript
|
|
323
439
|
import { EVMWallet } from 'stableflow-ai-sdk';
|
|
324
440
|
import { ethers } from 'ethers';
|
|
@@ -328,40 +444,145 @@ const signer = await provider.getSigner();
|
|
|
328
444
|
const wallet = new EVMWallet(provider, signer);
|
|
329
445
|
```
|
|
330
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
|
+
|
|
331
466
|
### Solana Wallets
|
|
332
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
|
+
|
|
333
485
|
```typescript
|
|
334
486
|
import { SolanaWallet } from 'stableflow-ai-sdk';
|
|
335
487
|
import { Connection, PublicKey } from '@solana/web3.js';
|
|
336
488
|
|
|
337
489
|
const connection = new Connection('https://api.mainnet-beta.solana.com');
|
|
338
|
-
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
|
+
});
|
|
339
504
|
```
|
|
340
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
|
+
|
|
341
508
|
### Near Wallets
|
|
342
509
|
|
|
343
510
|
```typescript
|
|
344
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
|
+
});
|
|
345
521
|
|
|
346
|
-
const wallet = new NearWallet(
|
|
522
|
+
const wallet = new NearWallet(selector);
|
|
347
523
|
```
|
|
348
524
|
|
|
525
|
+
**Note**: NearWallet requires a wallet selector instance from `@near-wallet-selector/core`. The selector handles wallet connection and transaction signing.
|
|
526
|
+
|
|
349
527
|
### Tron Wallets
|
|
350
528
|
|
|
351
529
|
```typescript
|
|
352
530
|
import { TronWallet } from 'stableflow-ai-sdk';
|
|
353
531
|
|
|
354
|
-
|
|
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
|
+
});
|
|
542
|
+
```
|
|
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
|
+
}
|
|
355
561
|
```
|
|
356
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
|
+
|
|
357
569
|
### Aptos Wallets
|
|
358
570
|
|
|
359
571
|
```typescript
|
|
360
572
|
import { AptosWallet } from 'stableflow-ai-sdk';
|
|
573
|
+
import { useWallet } from '@aptos-labs/wallet-adapter-react';
|
|
574
|
+
|
|
575
|
+
// Using Aptos wallet adapter
|
|
576
|
+
const { account, signAndSubmitTransaction } = useWallet();
|
|
361
577
|
|
|
362
|
-
const wallet = new AptosWallet(
|
|
578
|
+
const wallet = new AptosWallet({
|
|
579
|
+
account: account,
|
|
580
|
+
signAndSubmitTransaction: signAndSubmitTransaction,
|
|
581
|
+
});
|
|
363
582
|
```
|
|
364
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
|
+
|
|
365
586
|
## Token Configuration
|
|
366
587
|
|
|
367
588
|
The SDK provides pre-configured token information:
|
|
@@ -395,20 +616,28 @@ Each token configuration includes:
|
|
|
395
616
|
- `contractAddress` - Token contract address
|
|
396
617
|
- `assetId` - StableFlow asset identifier
|
|
397
618
|
- `services` - Array of supported bridge services
|
|
398
|
-
- `
|
|
619
|
+
- `rpcUrls` - RPC endpoint URLs
|
|
399
620
|
|
|
400
621
|
## Complete Example
|
|
401
622
|
|
|
623
|
+
### Example 1: EVM to EVM Bridge (Ethereum → Arbitrum)
|
|
624
|
+
|
|
402
625
|
Here's a complete example of a cross-chain swap:
|
|
403
626
|
|
|
404
627
|
```typescript
|
|
405
|
-
import { SFA, OpenAPI, tokens, EVMWallet, Service, TransactionStatus } from 'stableflow-ai-sdk';
|
|
628
|
+
import { SFA, OpenAPI, tokens, EVMWallet, Service, TransactionStatus, setRpcUrls } from 'stableflow-ai-sdk';
|
|
406
629
|
import { ethers } from 'ethers';
|
|
407
630
|
|
|
408
631
|
// 1. Initialize SDK
|
|
409
632
|
OpenAPI.BASE = 'https://api.stableflow.ai';
|
|
410
633
|
OpenAPI.TOKEN = 'your-jwt-token';
|
|
411
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
|
+
|
|
412
641
|
// 2. Setup wallet
|
|
413
642
|
const provider = new ethers.BrowserProvider(window.ethereum);
|
|
414
643
|
await provider.send('eth_requestAccounts', []);
|
|
@@ -448,6 +677,7 @@ if (!selectedQuote || !selectedQuote.quote) {
|
|
|
448
677
|
}
|
|
449
678
|
|
|
450
679
|
console.log(`Selected route: ${selectedQuote.serviceType}`);
|
|
680
|
+
console.log(`Estimated time: ${selectedQuote.quote.estimateTime}s`);
|
|
451
681
|
|
|
452
682
|
// 6. Handle approval if needed
|
|
453
683
|
if (selectedQuote.quote.needApprove) {
|
|
@@ -496,6 +726,106 @@ const checkStatus = async () => {
|
|
|
496
726
|
checkStatus();
|
|
497
727
|
```
|
|
498
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
|
+
|
|
499
829
|
## Error Handling
|
|
500
830
|
|
|
501
831
|
The SDK throws typed errors that you can catch and handle:
|
|
@@ -543,6 +873,137 @@ The SDK provides full TypeScript type definitions:
|
|
|
543
873
|
- `WalletConfig` - Wallet interface
|
|
544
874
|
- `TransactionStatus` - Transaction status enum
|
|
545
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
|
+
|
|
546
1007
|
## Examples
|
|
547
1008
|
|
|
548
1009
|
### 🌐 Web Application Demo 2.0
|
|
@@ -618,6 +1079,12 @@ For issues or support:
|
|
|
618
1079
|
- Support for multiple bridge services (OneClick, CCTP, USDT0)
|
|
619
1080
|
- Wallet integration for multiple chains
|
|
620
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
|
|
621
1088
|
|
|
622
1089
|
### v1.0.0
|
|
623
1090
|
- Initial release
|