Redeem vault shares in a single transaction using prepareWithdrawTxData and viem’s wallet client. This script fetches the target vault, prepares the calldata with a slippage safeguard, submits the transaction, and waits for confirmation.
Overview
- Discover a vault that supports withdrawals.
- Prepare withdrawal calldata with slippage tolerance.
- Submit and confirm the transaction with viem.
- Handle failures by surfacing the
APIError payload.
Prerequisites
- Node.js >= 20
- viem >= 2.0.0
- @paxoslabs/amplify-sdk installed and initialized (
initAmplifySDK elsewhere in your app)
- RPC URL (Alchemy, Infura, etc.)
- Private key with gas and vault shares to redeem
Never commit private keys. Use environment variables or a secrets manager in
production.
Complete Code Example
/**
* Viem Withdrawal Example
*
* Demonstrates complete withdrawal flow using viem (vanilla TypeScript):
* 1. Approve withdrawal
* 2. Execute withdraw transaction
*/
import {
fetchSupportedAssets,
prepareApproveWithdrawTxData,
prepareWithdrawTxData,
YieldType,
} from "@paxoslabs/amplify-sdk";
import { createPublicClient, createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";
const CONFIG = {
chainId: 1,
yieldType: YieldType.PRIME,
offerAmount: "5.0", // decimal string of the earn token to exchange
slippage: 75, // Optional: 0.75% slippage tolerance in basis points
rpcUrl:
process.env.RPC_URL ?? "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY",
privateKey: process.env.PRIVATE_KEY ?? "0x...",
};
async function withdraw() {
// Step 1: Setup wallet client
const account = privateKeyToAccount(CONFIG.privateKey as `0x${string}`);
const publicClient = createPublicClient({
chain: mainnet,
transport: http(CONFIG.rpcUrl),
});
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: http(CONFIG.rpcUrl),
});
// Fetch supported assets to get the want asset address
const supportedAssets = await fetchSupportedAssets({
yieldType: CONFIG.yieldType,
});
const asset = supportedAssets[0];
if (!asset) {
throw new Error("No supported assets found for the selected yield type.");
}
const wantAssetAddress = asset.address as `0x${string}`;
try {
// Step 2: Approve withdrawal
console.log("Step 1: Preparing approval transaction...");
const approvalTx = await prepareApproveWithdrawTxData({
chainId: CONFIG.chainId,
wantAssetAddress,
yieldType: CONFIG.yieldType,
});
console.log(`Approval target: ${approvalTx.address}`);
console.log();
console.log("Executing approval transaction...");
const approvalHash = await walletClient.writeContract(approvalTx);
console.log(`Approval tx hash: ${approvalHash}`);
console.log();
console.log("Waiting for approval confirmation...");
const approvalReceipt = await publicClient.waitForTransactionReceipt({
hash: approvalHash,
});
if (approvalReceipt.status === "success") {
console.log(
`✓ Approval confirmed in block ${approvalReceipt.blockNumber}`
);
} else {
throw new Error("Approval transaction failed");
}
console.log();
// Step 3: Prepare and execute withdrawal transaction
console.log("Step 2: Preparing withdrawal transaction...");
const tx = await prepareWithdrawTxData({
yieldType: CONFIG.yieldType,
wantAssetAddress,
offerAmount: CONFIG.offerAmount,
chainId: CONFIG.chainId,
});
console.log("Submitting transaction...");
const withdrawalHash = await walletClient.writeContract({ ...tx, account });
console.log(`Withdrawal sent: ${withdrawalHash}`);
console.log("Waiting for confirmation...");
const withdrawalReceipt = await publicClient.waitForTransactionReceipt({
hash: withdrawalHash,
});
if (withdrawalReceipt.status !== "success") {
throw new Error(`Withdrawal reverted in tx ${withdrawalHash}`);
}
console.log(
`✓ Withdrawal confirmed in block ${withdrawalReceipt.blockNumber}`
);
return withdrawalReceipt;
} catch (error) {
console.error();
console.error("=".repeat(60));
console.error("✗ Withdrawal failed");
console.error("=".repeat(60));
if (error instanceof Error) {
console.error(`Error: ${error.message}`);
} else {
console.error("Unknown error:", error);
}
throw error;
}
}
withdraw()
.then(() => {
process.exit(0);
})
.catch((error) => {
console.error(error);
process.exit(1);
});
prepareWithdrawTxData throws APIError when a vault, token, or chain is
unsupported. Log the endpoint and cause fields to help users fall back to
alternative flows when liquidity is unavailable.