UNPKG

@syncswap/sdk

Version:

SyncSwap TypeScript SDK for building DeFi applications

329 lines (252 loc) 9.73 kB
# SyncSwap TypeScript SDK SyncSwap TypeScript SDK for building DeFi applications on zkSync Era and other supported networks. ## Features - **Provider + Address Architecture**: Secure separation of data generation and signing - **Multi-network Support**: zkSync Era, Linea, Scroll, Sophon, and more - **Complete Trading Functions**: Swap, liquidity management, and route optimization - **Smart Routing**: Multi-hop and split routing for optimal execution - **Gas Optimization**: Paymaster support and gas-efficient transactions - **TypeScript Support**: Full type safety and IntelliSense support - **Backend/Frontend Separation**: Generate transaction data on backend, sign on frontend ## Installation ```bash npm install @syncswap/sdk # or yarn add @syncswap/sdk ``` ## Quick Start (Provider + Address Mode) ### Backend Usage ```typescript import SyncSwapSDK from '@syncswap/sdk'; import { Provider } from 'zksync-web3'; import { UserContext } from '@syncswap/sdk/types/UserContext'; // Initialize provider (no private key needed) const provider = new Provider('https://mainnet.era.zksync.io'); // Create SDK instance const sdk = new SyncSwapSDK({ network: 'zkSyncMainnet', allowUniswapV3Pools: true, enableHops: true, enableSplits: true }); // Initialize with provider only (no user data) await sdk.initialize(provider); // Create user context with settings const userContext: UserContext = { address: '0x...', // User's wallet address settings: { slippage: 0.5, // 0.5% slippage gasPrice: 30, }, enableLimitedUnlock: true, allowSponsoredPaymaster: false }; // Get swap route with user context const routePools = await sdk.fetchSyncSwapRouteData( 'TOKEN_IN_ADDRESS', 'TOKEN_OUT_ADDRESS', userContext ); // Calculate route const route = await sdk.calculateSyncSwapRoute( routePools, 'TOKEN_IN_ADDRESS', 'TOKEN_OUT_ADDRESS', amountIn ); // Get permit signature data for frontend const permitData = await sdk.getPermitSignatureData( 'TOKEN_IN_ADDRESS', amountIn, userContext ); // Generate transaction data (no signing) const swapTx = await sdk.swapExactInput(route, null, userContext); // Send transaction data to frontend return { permitData, // For frontend to sign swapTx // For frontend to execute }; ``` ### Frontend Usage ```typescript // Frontend receives permitData and swapTx from backend // Sign permit data if available let permitSignature = null; if (permitData) { const signature = await signer._signTypedData( permitData.domain, permitData.types, permitData.values ); permitSignature = { signature, data: permitData.values }; } // Execute transaction const receipt = await signer.sendTransaction(swapTx); ``` ## Legacy Signer Mode (Backward Compatibility) ```typescript import SyncSwapSDK from '@syncswap/sdk'; import { Provider, Wallet } from 'zksync-web3'; import { UserContext } from '@syncswap/sdk/types/UserContext'; // Initialize with signer (legacy approach) const provider = new Provider('https://mainnet.era.zksync.io'); const signer = new Wallet('YOUR_PRIVATE_KEY', provider); const sdk = new SyncSwapSDK({ network: 'zkSyncMainnet' }); // Initialize with signer (backward compatibility) await sdk.initialize(signer); // Create user context with signer const userContext: UserContext = { address: await signer.getAddress(), signer: signer, settings: { slippage: 0.5 } }; // Updated API with UserContext const routePools = await sdk.fetchSyncSwapRouteData(tokenA, tokenB, userContext); const route = await sdk.calculateSyncSwapRoute(routePools, tokenA, tokenB, amountIn); const swapTx = await sdk.swapExactInput(route, null, userContext); const receipt = await signer.sendTransaction(swapTx); ``` ## Token Management ```typescript // Get all token information const allTokens = sdk.getAllTokens(); const verifiedTokens = sdk.getVerifiedTokens(); const indexedTokens = sdk.getIndexedTokens(); // Find specific tokens const usdcToken = sdk.getTokenBySymbol("USDC"); const tokenByAddress = sdk.getTokenByAddress("0x..."); // Check token status const isVerified = sdk.isTokenVerified("0x..."); const isIndexed = sdk.isTokenIndexed("0x..."); // Get network-specific addresses const wethAddress = sdk.getWETHAddress(); const routeTokens = sdk.getRouteTokens(); ``` ## Advanced Configuration ```typescript const sdk = new SyncSwapSDK({ network: "sophonMainnet", // Network name allowUniswapV3Pools: true, // Enable Uniswap V3 style pools aquaPoolOnly: false, // Only use Aqua pools enableHops: true, // Enable multi-hop swaps enableSplits: true, // Enable split routes }); // User-specific settings via UserContext const userContext: UserContext = { address: "0x...", settings: { slippage: 0.5, // Custom slippage (or "auto") gasPrice: 30, // Custom gas price }, enableLimitedUnlock: true, // Limited token approvals allowSponsoredPaymaster: true, // Gas sponsorship feeToken: customFeeToken, // Custom fee token }; ``` ## Supported Networks - Sophon Mainnet (`sophonMainnet`) - zkSync Mainnet (`zkSyncMainnet`) - Linea Mainnet (`lineaMainnet`) - Scroll Mainnet (`scrollMainnet`) - Sophon Testnet (`sophonTestnet`) - zkSync Testnet (`zkSyncTestnet`) ## API Reference ### Initialization #### `initialize(provider: Provider)` (Recommended) Initialize the SDK with provider only for concurrent-safe operations. #### `initialize(signer: Signer)` (Legacy) Initialize the SDK with a signer for backward compatibility. ### Core Methods (All require UserContext) #### `fetchSyncSwapRouteData(tokenA, tokenB, userContext, routeTokens?)` Fetch route pools data for token pair with user context. #### `calculateSyncSwapRoute(routePools, tokenIn, tokenOut, amountIn)` Calculate optimal swap route and amounts. #### `swapExactInput(route, permitSignature, userContext)` Generate swap transaction data with user context. #### `checkApproval(tokenAddress, amount, userContext, spender?)` Check if token allowance is sufficient for user. #### `approve(tokenAddress, amount, userContext, spender?)` Generate approval transaction data for user. ### Signature Management #### `getPermitSignatureData(tokenAddress, amount, userContext, spender?, deadline?)` Get structured data for frontend EIP-2612 permit signing. #### `getTokenPermitData(tokenAddress)` Get permit metadata for EIP-2612 compatible tokens. #### `signPermit(tokenAddress, amount, userContext, spender?, deadline?)` (Legacy) Sign permit for gasless approval (requires signer in UserContext). ### UserContext Interface ```typescript interface UserContext { address: string; // Required: User's wallet address signer?: ethers.Signer; // Optional: For legacy compatibility settings?: { slippage?: number | string; // Slippage tolerance gasPrice?: number; // Gas price setting }; feeToken?: Token; // Custom fee token enableLimitedUnlock?: boolean; // Limited approvals allowSponsoredPaymaster?: boolean; // Gas sponsorship // ... more options } ``` ### Token Management #### `getAllTokens()` Get all registered tokens. #### `getTokenByAddress(address)` Get token by contract address. #### `getTokenBySymbol(symbol)` Get token by symbol. #### `lookupTokenByAddress(address, shouldRegister?, isIndexed?)` Lookup token from blockchain and optionally register. #### `getWETHAddress()` Get wrapped ETH address for current network. #### `getRouteTokens()` Get route tokens for current network. ## Examples For complete working examples, please see [`example/index.ts`](./example/index.ts). ## Migration Guide ### From Legacy to New UserContext Architecture **Before (Legacy):** ```typescript const signer = new Wallet(privateKey, provider); await sdk.initialize(signer); const routePools = await sdk.fetchSyncSwapRouteData(tokenA, tokenB); const signature = await sdk.signPermit(tokenAddress, amount); ``` **After (New Architecture):** ```typescript await sdk.initialize(provider); // Provider only const userContext: UserContext = { address: userAddress, settings: { slippage: 0.5 } }; const routePools = await sdk.fetchSyncSwapRouteData(tokenA, tokenB, userContext); const signatureData = await sdk.getPermitSignatureData(tokenAddress, amount, userContext); // Send signatureData to frontend for signing ``` ### Breaking Changes in v2.0 1. **All methods now require UserContext**: Pass user context as parameter instead of relying on global state 2. **Initialization simplified**: Use `initialize(provider)` instead of `initialize(provider, userAddress)` 3. **Enhanced type safety**: UserContext interface provides better TypeScript support 4. **Concurrent safety**: Multiple users can use the same SDK instance simultaneously ## Performance & Security Benefits The refactored architecture delivers significant improvements: ### Performance - **True Scalability**: Single instance handles thousands of concurrent users - **Memory Efficient**: Shared network config, isolated user state - **No Blocking**: Users don't block each other during operations ### Security - **Private Key Isolation**: Private keys never leave the frontend/user device - **Backend Safety**: Backend servers only handle data generation, not signing - **State Isolation**: Complete separation between users, no data leakage - **Reduced Attack Surface**: Eliminates risk of private key exposure in backend systems - **User Control**: Users maintain full control over their signing operations ### Reliability - **No Race Conditions**: Concurrent operations are completely safe - **Stateless Design**: No global state pollution between users - **Fault Isolation**: One user's error doesn't affect others ## License MIT