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