@syncswap/sdk
v0.2.23
Published
SyncSwap TypeScript SDK for building DeFi applications
Maintainers
Readme
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
npm install @syncswap/sdk
# or
yarn add @syncswap/sdkQuick Start (Provider + Address Mode)
Backend Usage
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
// 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)
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
// 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
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
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.
Migration Guide
From Legacy to New UserContext Architecture
Before (Legacy):
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):
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 signingBreaking Changes in v2.0
- All methods now require UserContext: Pass user context as parameter instead of relying on global state
- Initialization simplified: Use
initialize(provider)instead ofinitialize(provider, userAddress) - Enhanced type safety: UserContext interface provides better TypeScript support
- 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
