Withdrawing from Smart Pools
This guide explains how to programmatically withdraw assets from Smart Pools.
Installation
First, install the Steer Protocol SDK:
npm install @steerprotocol/sdk
Client Setup
Initialize the Steer Protocol client:
import { SteerClient } from '@steerprotocol/sdk';
import { createPublicClient, createWalletClient, http } from 'viem';
import { polygon } from 'viem/chains';
// Create Viem clients
const publicClient = createPublicClient({
chain: polygon,
transport: http()
});
const walletClient = createWalletClient({
chain: polygon,
transport: http()
});
// Initialize SteerClient
const steerClient = new SteerClient({
environment: 'production', // Use 'testnet' for testing
client: publicClient,
walletClient: walletClient
});
Prerequisites
Before withdrawing from a Smart Pool, ensure you have:
- Smart Pools SDK installed and client initialized
- Sufficient pool share balance
- Pool shares are not locked or vested
Implementation Steps
1. Calculate Token Amounts from LP Tokens
Before withdrawing, you can calculate how many underlying tokens you'll receive for your LP tokens:
interface TokenAmountsResponse {
token0Val: bigint;
token1Val: bigint;
}
// Calculate token amounts for 1 LP token
const lpTokenAmount = parseUnits('1', 18); // LP tokens have 18 decimals
const response = await steerClient.getTokensFromLp(
vaultAddress as `0x${string}`,
lpTokenAmount
);
if (!response.success || !response.data) {
throw new Error('Failed to calculate token amounts');
}
const { token0Val, token1Val } = response.data;
// Note: For new pools with zero LP supply
// token0Val and token1Val will both be 1
2. Prepare Withdrawal Transaction
You can use the SDK's prepareWithdrawTx
method to prepare the withdrawal transaction parameters:
// Prepare withdrawal parameters
const shares = parseUnits('1', 18); // Amount of LP tokens to withdraw
const amount0Min = token0Val * BigInt(99) / BigInt(100); // 1% slippage
const amount1Min = token1Val * BigInt(99) / BigInt(100); // 1% slippage
// Optional: Specify custom recipient
const customRecipient = '0x9876543210987654321098765432109876543210';
// Prepare the withdrawal transaction
const response = await steerClient.prepareWithdrawTx({
vaultAddress: vaultAddress as `0x${string}`,
shares,
amount0Min,
amount1Min,
to: customRecipient as `0x${string}` // Optional
});
if (!response.success || !response.data) {
throw new Error('Failed to prepare withdrawal transaction');
}
// The response contains all necessary transaction parameters
const {
address, // The vault contract address
functionName, // 'withdraw'
abi, // The ABI for the withdraw function
args // Arguments for the withdraw function [shares, amount0Min, amount1Min, to]
} = response.data;
3. Execute Withdrawal
You can execute the withdrawal using either Viem or Ethers.js with the prepared transaction parameters:
Using Viem
// Execute withdrawal using prepared transaction
const hash = await walletClient.writeContract({
address,
abi,
functionName,
args
});
// Wait for transaction confirmation
const receipt = await publicClient.waitForTransactionReceipt({ hash });
Using Ethers.js
import { ethers } from 'ethers';
// Create contract instance
const vaultContract = new ethers.Contract(
address,
abi,
signer
);
// Execute withdrawal using prepared transaction
const tx = await vaultContract[functionName](...args);
await tx.wait();
Important Notes
Share Balance
- Always verify your LP token balance before withdrawal
- Check for any locked or vested shares
- Consider withdrawal fees if applicable
Slippage Protection
- Use
amount0Min
andamount1Min
to protect against slippage - Calculate minimum amounts based on current pool share price
- Add buffer for price movements (e.g., 1% slippage tolerance)
- Use
Custom Recipient
- Optionally specify a custom recipient address for the withdrawn tokens
- If not specified, tokens will be sent to the transaction sender
Gas Optimization
- Implement proper gas estimation
- Consider network conditions
- Bundle transactions when possible
Error Handling
try {
// Check LP token balance
const lpBalance = await vaultContract.balanceOf(address);
if (lpBalance.lt(shares)) {
throw new Error('Insufficient LP token balance');
}
// Calculate expected token amounts
const tokenAmounts = await steerClient.getTokensFromLp(
vaultAddress as `0x${string}`,
shares
);
if (!tokenAmounts.success) {
throw new Error('Failed to calculate token amounts');
}
// Proceed with withdrawal
// ...
} catch (error) {
console.error('Withdrawal failed:', error);
// Handle error appropriately
}
Best Practices
Pre-withdrawal Checks
- Verify LP token balance
- Calculate expected token amounts
- Validate pool status
Transaction Monitoring
- Monitor withdrawal transaction
- Track token receipt
- Implement proper error handling
Slippage Considerations
- Calculate appropriate minimum amounts
- Consider market volatility
- Implement proper slippage protection