Skip to main content
Determine whether vault share approval is needed for a withdrawal operation and prepare the appropriate authorization. This is the recommended entry point for the withdrawal flow. It automatically:
  • Checks existing vault share allowance
  • Detects smart contract wallets (Safe, EIP-4337, EIP-7702)
  • Returns the appropriate authorization result

Import

import {
  prepareWithdrawalAuthorization,
  isWithdrawApprovalAuth,
  isWithdrawAlreadyApprovedAuth,
  WithdrawAuthMethod,
} from "@paxoslabs/amplify-sdk";

Usage

const auth = await prepareWithdrawalAuthorization({
  yieldType: "CORE",
  wantAsset: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // USDC
  withdrawAmount: "1.0",
  userAddress: "0x1234...",
  chainId: 1,
});

if (isWithdrawApprovalAuth(auth)) {
  // Execute approval transaction
  await walletClient.writeContract(auth.txData);
} else {
  // Already approved, proceed to withdrawal
  console.log(`Allowance: ${auth.allowance}`);
}

Parameters

ParameterTypeRequiredDescription
yieldTypeYieldTypeYesYield strategy (CORE, TREASURY, FRONTIER)
wantAssetAddressYesToken address to receive upon withdrawal
withdrawAmountstringYesVault shares to withdraw (decimal string)
userAddressAddressYesOwner of vault shares
chainIdChainIdYesBlockchain network ID
forceMethod"approval" | "allowance_check"NoOverride auto routing behavior

Return Type

Returns a discriminated union WithdrawAuthorizationResult:

WithdrawAuthMethod.APPROVAL

Returned when approval is needed (insufficient allowance, smart wallet detected in auto mode, or forceMethod: "approval").
interface WithdrawApprovalAuthorizationResult {
  method: "approval";
  txData: ApproveWithdrawOrderTxData; // Ready-to-use approval tx
}

WithdrawAuthMethod.ALREADY_APPROVED

Returned when existing allowance is sufficient.
interface WithdrawAlreadyApprovedAuthorizationResult {
  method: "already_approved";
  allowance: string;
  allowanceAsBigInt: string;
}

Type Guards

Use type guards for type-safe handling:
import {
  isWithdrawApprovalAuth,
  isWithdrawAlreadyApprovedAuth,
} from "@paxoslabs/amplify-sdk";

const auth = await prepareWithdrawalAuthorization({ ... });

if (isWithdrawApprovalAuth(auth)) {
  // TypeScript knows auth.txData exists
  await walletClient.writeContract(auth.txData);
}

if (isWithdrawAlreadyApprovedAuth(auth)) {
  // TypeScript knows auth.allowance exists
  console.log(auth.allowance);
}
Or use a switch statement:
switch (auth.method) {
  case WithdrawAuthMethod.APPROVAL:
    await walletClient.writeContract(auth.txData);
    break;
  case WithdrawAuthMethod.ALREADY_APPROVED:
    console.log(`Approved: ${auth.allowance}`);
    break;
}

Smart Wallet Behavior

In auto mode, smart contract wallets (Safe, EIP-4337, EIP-7702) are routed to APPROVAL with approve tx data so they can batch approve + withdraw atomically.
// Smart wallet detected automatically
const auth = await prepareWithdrawalAuthorization({
  yieldType: "CORE",
  wantAsset: USDC_ADDRESS,
  withdrawAmount: "1.0",
  userAddress: safeAddress, // Smart contract wallet
  chainId: 1,
});

// Returns APPROVAL in auto mode for smart wallets
// auth.method === WithdrawAuthMethod.APPROVAL
The SDK detects smart wallets by checking for deployed bytecode at the address using getCode. This covers:
  • Safe (Gnosis Safe) multi-sig wallets
  • EIP-4337 smart accounts (e.g., Biconomy, ZeroDev, Alchemy)
  • EIP-7702 delegated EOAs
  • Privy embedded wallets (when using smart wallets)

Force Method Overrides

Use forceMethod for deterministic behavior:
// Always return approval tx data (skip checks)
const forceApproval = await prepareWithdrawalAuthorization({
  yieldType: "CORE",
  wantAsset: USDC_ADDRESS,
  withdrawAmount: "1.0",
  userAddress,
  chainId: 1,
  forceMethod: "approval",
});

// Always run allowance check (skip smart-wallet heuristic)
const forceAllowanceCheck = await prepareWithdrawalAuthorization({
  yieldType: "CORE",
  wantAsset: USDC_ADDRESS,
  withdrawAmount: "1.0",
  userAddress,
  chainId: 1,
  forceMethod: "allowance_check",
});

Examples

import {
  prepareWithdrawalAuthorization,
  isWithdrawApprovalAuth,
  prepareWithdrawal,
} from "@paxoslabs/amplify-sdk";

async function withdraw(
  walletClient: WalletClient,
  publicClient: PublicClient,
  userAddress: `0x${string}`,
) {
  const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
  const withdrawAmount = "1.0";

  // Step 1: Authorize
  const auth = await prepareWithdrawalAuthorization({
    yieldType: "CORE",
    wantAsset: USDC,
    withdrawAmount,
    userAddress,
    chainId: 1,
  });

  if (isWithdrawApprovalAuth(auth)) {
    const approveHash = await walletClient.writeContract(auth.txData);
    await publicClient.waitForTransactionReceipt({ hash: approveHash });
  }

  // Step 2: Submit withdrawal order
  const withdrawTx = await prepareWithdrawal({
    yieldType: "CORE",
    wantAsset: USDC,
    userAddress,
    chainId: 1,
    withdrawAmount,
  });

  const hash = await walletClient.writeContract(withdrawTx);
  return hash;
}

Comparison with Deposit Authorization

prepareWithdrawalAuthorization() mirrors the deposit flow’s prepareDepositAuthorization():
FeatureDeposit AuthWithdrawal Auth
MethodsPERMIT, APPROVAL, ALREADY_APPROVEDAPPROVAL, ALREADY_APPROVED
Permit SupportYes (EIP-2612)No
Smart Wallet Auto-DetectYesYes
Force MethodforceMethod: "permit" | "approval"forceMethod: "approval" | "allowance_check"
Withdrawals don’t support EIP-2612 permits since the approval is on vault shares (BoringVault ERC20), not the deposit token.

Error Handling

ErrorDescriptionResolution
No vault found for assetInvalid yield type, chain, or asset combinationVerify parameters match an existing vault
Failed to check withdrawal approvalOn-chain multicall failedCheck RPC connectivity and retry
import { prepareWithdrawalAuthorization, APIError } from "@paxoslabs/amplify-sdk";

try {
  const auth = await prepareWithdrawalAuthorization({
    yieldType: "CORE",
    wantAsset: USDC_ADDRESS,
    withdrawAmount: "1.0",
    userAddress: "0x...",
    chainId: 1,
  });
} catch (error) {
  if (error instanceof APIError) {
    console.error("SDK Error:", error.message);
  }
}