Redeem

bulkWithdraw

TypeScript Example

Note: This example assumes you have a walletClient configured in your code base. Please refer to https://viem.sh/docs/clients/wallet for detailed documentation.

import {
  parseUnits,
  isAddress,
  type Address,
} from "viem";
import { publicClient, walletClient } from "./client"; // Assumes client.ts is in the same folder

// --- ABIs ---

const tellerAbi = [
  /* ... (start of ABI) ... */
  {
    inputs: [
      { internalType: "contract ERC20", name: "withdrawAsset", type: "address" },
      { internalType: "uint256", name: "shareAmount", type: "uint256" },
      { internalType: "uint256", name: "minimumAssets", type: "uint256" },
      { internalType: "address", name: "to", type: "address" },
    ],
    name: "bulkWithdraw",
    outputs: [{ internalType: "uint256", name: "assetsOut", type: "uint256" }],
    stateMutability: "nonpayable",
    type: "function",
  },
  /* ... (rest of the ABI) ... */
] as const;

const accountantAbi = [
  {
    inputs: [{ internalType: "address", name: "asset", type: "address" }],
    name: "getRateInQuote",
    outputs: [{ internalType: "uint256", name: "rate", type: "uint256" }],
    stateMutability: "view",
    type: "function",
  },
] as const;

// --- Main Withdraw Function ---

async function makeBulkWithdraw({
  tellerAddress,
  accountantAddress,
  withdrawAssetAddress,
  shareAmount, // The amount of shares to withdraw, as a string
  slippageBps = 50, // 50 bps = 0.5%
  recipient,
}: {
  tellerAddress: Address;
  accountantAddress: Address;
  withdrawAssetAddress: Address;
  shareAmount: string;
  slippage?: number; 
  recipient: Address;
}) {
  if (!isAddress(tellerAddress) || tellerAddress === "0x...") {
    console.error("A valid teller contract address is required.");
    return;
  }

  try {
    // 1. Convert the human-readable share amount to its base unit (uint256)
    const parsedShareAmount = parseUnits(shareAmount, 6);

    // 2. Fetch the rate from the blockchain to calculate expected output
    console.log("Fetching current rate from accountant...");
    const rate = await publicClient.readContract({
      abi: accountantAbi,
      address: accountantAddress,
      functionName: "getRateInQuote",
      args: [withdrawAssetAddress],
    });
    console.log(`Rate received: ${rate}`);

    // 3. Calculate the minimumAssets value using our helper
    const minimumAssets = calculateMinimumAssetsOut(
      parsedShareAmount,
      rate,
      slippageBps,
    );
    console.log(`Calculated minimum assets to receive: ${minimumAssets}`);

    // 4. Use `writeContract` to send the transaction
    const hash = await walletClient.writeContract({
      abi: tellerAbi,
      address: tellerAddress,
      functionName: "bulkWithdraw",
      args: [withdrawAssetAddress, parsedShareAmount, minimumAssets, recipient],
    });

    console.log(`Transaction sent! Hash: ${hash}`);
    console.log("Waiting for transaction to be mined...");

    // 5. Wait for the transaction to be included in a block
    const receipt = await publicClient.waitForTransactionReceipt({ hash });

    console.log("Transaction was successfully mined!");
    console.log(`- Block Number: ${receipt.blockNumber}`);
    console.log(
      `- View on Etherscan: https://etherscan.io/tx/${receipt.transactionHash}`,
    );

  } catch (err) {
    console.error("Error sending bulk withdraw transaction:", err);
  }
}

// --- Execution Example ---

/* ... (start of Withdrawl function) ... */

// Call the function to withdraw 100 shares
await makeBulkWithdraw({
  tellerAddress: myTellerAddress,
  accountantAddress: myAccountantAddress,
  withdrawAssetAddress: usdcAddress,
  shareAmount: "100.0", // The number of shares to burn
  recipient: recipientAddress,
  slippageBps: 50, // Optional: 0.5% slippage
});

/* ... (rest of Withdrawl function) ... */

TypeScript Helper Functions

const calculateMinimumAssetsOut = (
  shareAmount: bigint,
  rate: bigint,
  slippage: number, // In bps (e.g., 50 for 0.5%)
): bigint => {
  // Convert bps to WAD format (multiply by WAD/10000)
  const slippageAsBigInt = (BigInt(slippage) * WAD.bigint) / 10000n;

  // Calculate ideal asset amount without slippage
  // idealAssets = shareAmount * rate (with WAD precision)
  const wantAssetsOut = (shareAmount * rate) / WAD.bigint;

  // Calculate the amount to subtract for slippage tolerance
  const slippageAmount = (idealAssetsOut * slippageAsBigInt) / WAD.bigint;

  // Return asset amount minus slippage buffer
  return wantAssetsOut - slippageAmount;
};

Last updated