Documentation Index
Fetch the complete documentation index at: https://developers.paxoslabs.com/llms.txt
Use this file to discover all available pages before exploring further.
Determine whether account 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 account 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
// First discover the vault
const [vault] = await getVaultsByConfig({
yieldType: 'CORE',
chainId: 1,
})
const auth = await prepareWithdrawalAuthorization({
vaultName: vault.name,
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
| Parameter | Type | Required | Description |
|---|
vaultName | string | Yes | Account name from AmplifyVault.name (e.g. from getVaultsByConfig()) |
wantAsset | Address | Yes | Token address to receive upon withdrawal |
withdrawAmount | string | Yes | Account shares to withdraw (decimal string) |
userAddress | Address | Yes | Owner of account shares |
chainId | number | Yes | Blockchain network ID |
forceMethod | "approval" | "allowance_check" | No | Override 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 [vault] = await getVaultsByConfig({ yieldType: 'CORE', chainId: 1 })
const auth = await prepareWithdrawalAuthorization({
vaultName: vault.name,
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:
const [vault] = await getVaultsByConfig({ yieldType: 'CORE', chainId: 1 })
// Always return approval tx data (skip checks)
const forceApproval = await prepareWithdrawalAuthorization({
vaultName: vault.name,
wantAsset: USDC_ADDRESS,
withdrawAmount: '1.0',
userAddress,
chainId: 1,
forceMethod: 'approval',
})
// Always run allowance check (skip smart-wallet heuristic)
const forceAllowanceCheck = await prepareWithdrawalAuthorization({
vaultName: vault.name,
wantAsset: USDC_ADDRESS,
withdrawAmount: '1.0',
userAddress,
chainId: 1,
forceMethod: 'allowance_check',
})
Examples
Complete Viem Flow
Smart Wallet Batching
import {
getVaultsByConfig,
prepareWithdrawalAuthorization,
isWithdrawApprovalAuth,
prepareWithdrawal,
YieldType,
} from "@paxoslabs/amplify-sdk";
async function withdraw(
walletClient: WalletClient,
publicClient: PublicClient,
userAddress: `0x${string}`,
) {
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const withdrawAmount = "1.0";
// Discover vault
const [vault] = await getVaultsByConfig({
yieldType: YieldType.CORE,
chainId: 1,
});
// Step 1: Authorize
const auth = await prepareWithdrawalAuthorization({
vaultName: vault.name,
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({
vaultName: vault.name,
wantAsset: USDC,
userAddress,
chainId: 1,
withdrawAmount,
});
const hash = await walletClient.writeContract(withdrawTx);
return hash;
}
import {
getVaultsByConfig,
prepareWithdrawalAuthorization,
isWithdrawApprovalAuth,
prepareWithdrawal,
YieldType,
} from "@paxoslabs/amplify-sdk";
import { encodeFunctionData } from "viem";
async function batchedWithdraw(safeAddress: `0x${string}`) {
const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
const withdrawAmount = "1.0";
const [vault] = await getVaultsByConfig({
yieldType: YieldType.CORE,
chainId: 1,
});
// Get authorization (default: APPROVAL for smart wallets)
const auth = await prepareWithdrawalAuthorization({
vaultName: vault.name,
wantAsset: USDC,
withdrawAmount,
userAddress: safeAddress,
chainId: 1,
});
const calls = [];
// Add approval call
if (isWithdrawApprovalAuth(auth)) {
calls.push({
to: auth.txData.address,
data: encodeFunctionData({
abi: auth.txData.abi,
functionName: auth.txData.functionName,
args: auth.txData.args,
}),
value: 0n,
});
}
// Add withdrawal call
const withdrawTx = await prepareWithdrawal({
vaultName: vault.name,
wantAsset: USDC,
userAddress: safeAddress,
chainId: 1,
withdrawAmount,
});
calls.push({
to: withdrawTx.address,
data: encodeFunctionData({
abi: withdrawTx.abi,
functionName: withdrawTx.functionName,
args: withdrawTx.args,
}),
value: 0n,
});
// Execute both atomically via smart wallet
return calls;
}
Comparison with Deposit Authorization
prepareWithdrawalAuthorization() mirrors the deposit flow’s prepareDepositAuthorization():
| Feature | Deposit Auth | Withdrawal Auth |
|---|
| Methods | PERMIT, APPROVAL, ALREADY_APPROVED | APPROVAL, ALREADY_APPROVED |
| Permit Support | Yes (EIP-2612) | No |
| Smart Wallet Auto-Detect | Yes | Yes |
| Force Method | forceMethod: "permit" | "approval" | forceMethod: "approval" | "allowance_check" |
Withdrawals don’t support EIP-2612 permits since the approval is on account shares (BoringVault ERC20), not the deposit token.
Error Handling
| Error | Description | Resolution |
|---|
Vault not found | Invalid account name | Verify account name via getVaultsByConfig() |
Failed to check withdrawal approval | On-chain multicall failed | Check RPC connectivity and retry |
import {
getVaultsByConfig,
prepareWithdrawalAuthorization,
APIError,
} from '@paxoslabs/amplify-sdk'
const [vault] = await getVaultsByConfig({ yieldType: 'CORE', chainId: 1 })
try {
const auth = await prepareWithdrawalAuthorization({
vaultName: vault.name,
wantAsset: USDC_ADDRESS,
withdrawAmount: '1.0',
userAddress: '0x...',
chainId: 1,
})
} catch (error) {
if (error instanceof APIError) {
console.error('SDK Error:', error.message)
}
}