@zenswap-labs/sdk
v0.6.0
Published
A comprehensive SDK for interacting with the Zenswap protocol and various blockchain networks
Maintainers
Readme
Zenswap SDK
A comprehensive SDK for interacting with the Zenswap protocol and various blockchain networks.
Installation
npm install @zenswap-analog/sdk
# or
yarn add @zenswap-analog/sdk
# or
pnpm add @zenswap-analog/sdkFeatures
- Support for multiple blockchain networks (Ethereum, Binance Smart Chain, Polygon, etc.)
- Cross-chain token swaps and transfers
- Automatic route finding and price quotes
- Fee estimation (gas fees and cross-chain transfer fees)
- Provider implementations for connecting to blockchains
- Storage utilities for local data persistence
- Math utilities for precise calculations
- Substrate blockchain integration
Smart Contract Interaction Guide
The Zenswap SDK provides a powerful interface for interacting with Zenswap's smart contracts directly, enabling cross-chain swaps, liquidity provision, and more without requiring a UI.
Core Features
- Multi-chain Support: Interact with contracts across multiple EVM-compatible blockchains
- Cross-chain Swaps: Execute token swaps between different blockchains
- Fee Estimation: Calculate gas fees and cross-chain transfer fees
- Route Finding: Automatically find the most efficient swap routes
- Price Quotes: Get accurate price quotes including price impact
Key Components
SwapRouter
The SwapRouter class is the main entry point for interacting with Zenswap's smart contracts:
import {
SwapRouter,
NetworkId,
ChainId,
getNetworkId,
getChainId,
} from "@zenswap-analog/sdk";
// The SDK comes with default configurations for:
// - Contract addresses for Sepolia and Arbitrum Sepolia testnet deployments
// - GMP IDs for cross-chain messaging
// - Fee parameters (0.25% fee, default recipient)
// - Network configurations (RPC URLs, chain IDs, etc.)
// - Native token configurations
// - Token standards and interfaces
// - Cross-chain protocols
// Create router instance with default configurations
const router = new SwapRouter();
// Or override specific configurations
const customContracts = {
[ChainId.EthereumMainnet]: {
zenswap: "0x...", // Your deployed Zenswap contract address
gmpPlugin: "0x...", // Your deployed GMP plugin address
gmpGateway: "0x...", // Your deployed GMP gateway address
},
};
const customGmpIds = {
[ChainId.EthereumMainnet]: 1,
};
const customFeePercent = 0.3; // 0.3%
const customFeeRecipient = "0x...";
// Create router instance with custom configurations
const customRouter = new SwapRouter(
customContracts, // null to use defaults
customGmpIds, // null to use defaults
customFeePercent, // null to use defaults
customFeeRecipient // null to use defaults
);Supported Swap Strategies
The SDK supports various swap strategies:
- Swap: Token swap within the same blockchain
- SwapAndTransfer: Swap on chain A, then transfer to chain B
- TransferAndSwap: Transfer to chain B, then swap on chain B
- Transfer: Direct token transfer between chains
- SwapAndSwap: Swap on chain A, transfer to chain B, then swap again on chain B
- Wrap: Convert native tokens to wrapped tokens (e.g., ETH to WETH)
- Unwrap: Convert wrapped tokens to native tokens (e.g., WETH to ETH)
Basic Usage Examples
1. Finding a Swap Route
import { SwapRouter, NetworkToken } from "@zenswap-analog/sdk";
// Define input parameters
const swapParams = {
input: tokenIn, // NetworkToken object for input token
output: tokenOut, // NetworkToken object for output token
amount: "1.5", // Amount to swap as string
recipient: "0x...", // Recipient address
slippagePercent: 0.5, // Slippage tolerance (0.5%)
deadlineInSeconds: 1800, // Transaction deadline (30 minutes)
};
// Find the best route
const route = await router.findRoute(swapParams);
if (route) {
console.log("Swap route found:");
console.log("Input amount:", route.input.amount);
console.log("Output amount:", route.output.amount);
console.log("Price impact:", route.priceImpact, "%");
console.log("Strategy:", route.strategy);
// The route.method contains the transaction parameters
const txParams = route.method?.parameters;
// Execute the transaction using your preferred web3 provider
// e.g., with ethers.js:
// const tx = await signer.sendTransaction(txParams);
}2. Cross-chain Token Transfer
// Example of a cross-chain transfer from Ethereum to Polygon
const transferParams = {
input: usdcEthereum, // USDC on Ethereum
output: usdcPolygon, // USDC on Polygon
amount: "100", // Amount to transfer
recipient: "0x...", // Recipient address
slippagePercent: 0.1,
deadlineInSeconds: 1800,
};
const transferRoute = await router.findRoute(transferParams);
// The transferRoute.method contains the transaction parameters
// The transferRoute.fee contains the estimated gas fee
// The transferRoute.transferFee contains the cross-chain transfer fee3. Getting a Quote Without Executing
// Get a quote for a swap
const quote = await router.quote(swapParams);
if (quote) {
console.log("Estimated output:", quote.output.amount);
console.log("Fee in native currency:", quote.fee.amount);
if (quote.transferFee) {
console.log("Transfer fee:", quote.transferFee.amount);
}
if (quote.gmpFee) {
console.log("GMP fee:", quote.gmpFee.amount);
}
}4. Understanding Cross-Chain Fees
// For cross-chain operations, there are two types of fees:
// 1. Transfer Fee: Gas fee for executing the transaction on the destination chain
// 2. GMP Fee: Fee for cross-chain message passing
// The GMP fee is calculated by the prepareGmpFee method
const gmpFee = await router.prepareGmpFee(proxyToken);
// The GMP fee is then applied when creating a transfer route
const transferRoute = router.createDirectRoute(
amount, // Amount to transfer
tokenIn, // Source token
tokenOut, // Destination token
RouteType.Transfer,
gmpFee.amount // GMP fee amount to deduct
);
// The output amount will be reduced by the GMP fee
console.log("Input amount:", amount);
console.log("GMP fee:", gmpFee.amount);
console.log("Output amount after GMP fee:", transferRoute.output.amount);Advanced Features
Fee Calculation and Gas Estimation
// 1. Estimate gas for a specific transaction
const gasUsed = await SwapRouter.estimateGasUsed(networkId, {
data,
from,
to,
value,
});
// 2. Create a SwapFee instance with custom coefficients
const swapFee = new SwapFee(
networkFee.token,
networkFee.gasLimit,
networkFee.baseFeePerGas
);
swapFee.baseCoeff = baseCoeff; // For different speed preferences
swapFee.priorityCoeff = priorityCoeff;
swapFee.additionalValue = transferFee?.value ?? BigInt(0);
// 3. Get maximum available amount considering fees
const maxAmount = getMaxValue(balance, combinedFee.amount, isNativeToken);Transaction Lifecycle Management
// 1. Create transaction request from router result
const { data, value, to } = route.method.parameters;
const txRequest = {
data,
value: value.toString(),
to,
maxFeePerGas: maxFeePerGas?.toString(),
maxPriorityFeePerGas: maxPriorityFeePerGas?.toString(),
};
// 2. Track transaction details
const txDetails = {
id: generateTxId(),
input: {
token: tokenIn,
amount: amountIn,
},
output: {
token: tokenOut,
amount: amountOut,
},
networkFee,
transferFee,
gmpFee,
routerFee,
priceImpact,
estimatedTime,
startTime: Date.now(),
state: TxState.Pending,
};
// 3. Execute and monitor transaction
const tx = await signer.sendTransaction(txRequest);
await waitForEvmTransactionMined(tx);
// 4. Update transaction state and details
txDetails.state = TxState.Done;
txDetails.endTime = Date.now();
txDetails.executionTime = txDetails.endTime - txDetails.startTime;
// 5. Handle cross-chain transactions
if (transferFee) {
// Monitor source chain confirmation
txDetails.sourceHash = tx.hash;
// Monitor destination chain execution
const destTx = await waitForDestinationTx(tx.hash);
txDetails.destHash = destTx.hash;
txDetails.received = {
token: tokenOut,
amount: destTx.amount,
};
}The SDK provides comprehensive transaction tracking capabilities:
Transaction States:
- Pending: Initial state when transaction is submitted
- Confirming: Transaction is being mined
- Executing: Cross-chain operations in progress
- Done: Transaction completed successfully
- Failed: Transaction failed
Transaction Details:
- Input/Output amounts and tokens
- Network fees and transfer fees
- Price impact and router fees
- Execution time and estimated completion time
- Transaction hashes for both chains in cross-chain swaps
Progress Monitoring:
- Track transaction state changes
- Monitor cross-chain message delivery
- Calculate remaining time for completion
- Handle transaction failures and timeouts
Fee Management:
- Network gas fees: Standard gas fees for blockchain transactions
- Cross-chain transfer fees: Fees for moving tokens between chains
- GMP (General Message Passing) fees: Fees for cross-chain message delivery
- Used for communication between chains in cross-chain swaps
- Separate from transfer fees and varies based on message size and gas prices
- Calculated using the
prepareGmpFeemethod which queries the GMP plugin contract - Deducted from the transfer amount in cross-chain operations via the
createDirectRoutemethod - Affects the final output amount received on the destination chain
- Critical for ensuring reliable cross-chain operations
- Router protocol fees: Optional fees charged by the protocol
Token Approvals
// 1. Check if approval is needed
const isApproved = BigNumber(allowance).gte(BigNumber(amount));
// 2. Approve if needed
if (!isApproved) {
const tx = await approveToken(contractAddress, tokenAddress);
await waitForEvmTransactionMined(tx);
}Periodic Quote Updates
const QUOTE_UPDATE_INTERVAL = 15000; // 15 seconds
const QUOTE_DEBOUNCE_TIMEOUT = 1000; // 1 second
// 1. Create a debounced quote function
const debouncedQuote = debouncedHandler(updateQuote, QUOTE_DEBOUNCE_TIMEOUT);
// 2. Schedule periodic updates
function scheduleQuoteUpdate(quoteId) {
setTimeout(() => {
if (isCurrentQuoteId(quoteId)) {
updateQuote(quoteId);
}
}, QUOTE_UPDATE_INTERVAL);
}
// 3. Update quote with proper error handling
async function updateQuote(quoteId) {
try {
const result = await router.findRoute(params);
if (result && isCurrentQuoteId(quoteId)) {
await updateGasEstimates(result);
setQuoteResult(result);
scheduleQuoteUpdate(quoteId);
}
} catch (error) {
console.error("Quote update failed:", error);
}
}Integration Best Practices
Quote Management:
- Implement debouncing for quote requests
- Set up periodic quote updates (e.g., every 15 seconds)
- Track quote IDs to handle race conditions
- Handle loading states and errors appropriately
Fee Handling:
- Always check if the user has sufficient balance for both the swap amount and fees
- Consider different fee modes (fast, normal, slow)
- Include cross-chain transfer fees in calculations
- Update gas estimates before executing transactions
Transaction Flow:
- Check token approvals before swaps
- Estimate gas for the specific sender
- Monitor transaction status
- Update token balances after successful transactions
Error Handling:
- Handle null routes (no valid path found)
- Handle insufficient balance/allowance cases
- Handle transaction failures
- Implement proper loading states for all async operations
Boost Mode Integration
The Zenswap SDK supports a Boost Mode feature, which allows for enhanced performance and reduced fees during cross-chain swaps. To use Boost Mode, you can pass a boostParams object to the findRoute method.
Example of Using Boost Mode
import { SwapRouter, NetworkToken } from "@zenswap-analog/sdk";
// Define input parameters
const swapParams = {
input: tokenIn, // NetworkToken object for input token
output: tokenOut, // NetworkToken object for output token
amount: "1.5", // Amount to swap as string
recipient: "0x...", // Recipient address
slippagePercent: 0.5, // Slippage tolerance (0.5%)
deadlineInSeconds: 1800, // Transaction deadline (30 minutes)
};
// Define boost parameters
const boostParams = {
rewardAmount: "1", // Reward amount for the swap
};
// Find the best route with boost mode
const route = await router.findRoute(swapParams, boostParams);
if (route) {
console.log("Boost mode route found:");
console.log("Input amount:", route.input.amount);
console.log("Output amount:", route.output.amount);
console.log("Price impact:", route.priceImpact, "%");
console.log("Strategy:", route.strategy);
// The route.method contains the transaction parameters
const txParams = route.method?.parameters;
// Execute the transaction using your preferred web3 provider
// e.g., with ethers.js:
// const tx = await signer.sendTransaction(txParams);
}This feature allows you to optimize your swaps for better performance and lower fees. Adjust the boostParams as needed to fit your specific use case.
Examples
The SDK includes several examples to help you get started:
JavaScript Example
# Build the SDK
npm run build
# Run the JavaScript example
npm run example:jsTypeScript Example
# Build the SDK
npm run build
# Run the TypeScript example
npm run example:tsTesting with Real Contract Addresses
The SDK includes test scripts that demonstrate how to use it with real contract addresses:
# Run the basic test script
npm run test-sdkDevelopment Mode
You can also run the SDK in development mode, which provides a REPL for interactive testing:
npm run devThis will:
- Build the SDK in watch mode
- Run a basic example
- Start a REPL with the SDK available as the
SDKvariable
Documentation
For detailed documentation, see the API Reference.
You can also generate the documentation locally:
# Generate documentation
npm run docs
# The documentation will be available in the docs directoryContributing
Contributions are welcome! Please feel free to submit a Pull Request.
Testing
The SDK includes a comprehensive test suite. To run all tests, linting, and type checking:
npm run test:allThis will:
- Run the linter
- Run the type checker
- Run the tests with coverage
- Generate a coverage report
You can also run individual test commands:
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverageLicense
This project is licensed under the MIT License - see the LICENSE file for details.
