@syncswap/sdk
Version:
SyncSwap TypeScript SDK for building DeFi applications
329 lines (252 loc) • 9.73 kB
Markdown
# 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