Skip to main content

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:

  1. Smart Pools SDK installed and client initialized
  2. Sufficient pool share balance
  3. 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​

  1. Share Balance

    • Always verify your LP token balance before withdrawal
    • Check for any locked or vested shares
    • Consider withdrawal fees if applicable
  2. Slippage Protection

    • Use amount0Min and amount1Min to protect against slippage
    • Calculate minimum amounts based on current pool share price
    • Add buffer for price movements (e.g., 1% slippage tolerance)
  3. Custom Recipient

    • Optionally specify a custom recipient address for the withdrawn tokens
    • If not specified, tokens will be sent to the transaction sender
  4. 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​

  1. Pre-withdrawal Checks

    • Verify LP token balance
    • Calculate expected token amounts
    • Validate pool status
  2. Transaction Monitoring

    • Monitor withdrawal transaction
    • Track token receipt
    • Implement proper error handling
  3. Slippage Considerations

    • Calculate appropriate minimum amounts
    • Consider market volatility
    • Implement proper slippage protection

Next Steps​