npm package: @syncswap/sdk
Description: SyncSwap TypeScript SDK for building DeFi applications
Author: SyncSwap
Latest version: 0.2.23

# 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