Skip to main content
Copy this page into your AI coding assistant (Cursor, Copilot, Claude, etc.) for accurate Amplify vault direct contract completions.
This page is a condensed, single-file reference for calling Amplify vault contracts directly — without the SDK. For full documentation with interactive examples, see the Direct Contract Integration guides.

Contract Source

Open-source Solidity: github.com/paxoslabs/nucleus-boring-vault

Architecture

ContractRoleGraphQL Field
DistributorCodeDepositorDeposits (standard + permit)vault.communityCodeDepositorModuleId
WithdrawQueueWithdrawal orders + cancellations (ERC-721 per order)vault.withdrawQueueModuleId
BoringVaultERC-20 vault share token (18 decimals)vault.boringVaultAddress
AccountantExchange rate oraclevault.accountantModuleId
TellerPause statevault.tellerModuleId
FeeModuleWithdrawal fee calculatorObtained via WithdrawQueue.feeModule()
communityCodeDepositorModuleId is a legacy GraphQL field name. It returns the DistributorCodeDepositor address.

Obtain Addresses — GraphQL API

POST https://api.paxoslabs.com/graphql
Headers: Content-Type: application/json, x-api-key: <YOUR_API_KEY>

Query

query AmplifySdkConfigs($chainId: Int, $yieldType: YieldType) {
  amplifySdkConfigs(chainId: $chainId, yieldType: $yieldType) {
    id
    chainId
    yieldType
    vault {
      id
      name
      chainId
      boringVaultAddress
      tellerModuleId
      accountantModuleId
      withdrawQueueModuleId
      communityCodeDepositorModuleId
      supportedAssets {
        address
        chainId
        depositable
        withdrawable
        symbol
        tokenName
        decimals
      }
    }
  }
}

Example cURL

curl -s -X POST "https://api.paxoslabs.com/graphql" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $AMPLIFY_API_KEY" \
  -d '{
    "query": "query AmplifySdkConfigs($chainId: Int, $yieldType: YieldType) { amplifySdkConfigs(chainId: $chainId, yieldType: $yieldType) { id chainId yieldType vault { id name chainId boringVaultAddress tellerModuleId accountantModuleId withdrawQueueModuleId communityCodeDepositorModuleId supportedAssets { address chainId depositable withdrawable symbol tokenName decimals } } } }",
    "variables": { "chainId": 1 }
  }' | jq

Response Shape

{
  "data": {
    "amplifySdkConfigs": [
      {
        "id": "config-id",
        "chainId": 1,
        "yieldType": "CORE",
        "vault": {
          "id": "vault-id",
          "name": "Amplify Core",
          "chainId": 1,
          "boringVaultAddress": "0x...",
          "tellerModuleId": "0x...",
          "accountantModuleId": "0x...",
          "withdrawQueueModuleId": "0x...",
          "communityCodeDepositorModuleId": "0x...",
          "supportedAssets": [
            {
              "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
              "chainId": 1,
              "depositable": true,
              "withdrawable": true,
              "symbol": "USDC",
              "tokenName": "USD Coin",
              "decimals": 6
            }
          ]
        }
      }
    ]
  }
}
Multiple configs can reference the same vault. Deduplicate by vault.id. withdrawQueueModuleId and communityCodeDepositorModuleId can be null if the vault doesn’t support those operations.

GraphQL Variables

VariableTypeDescription
chainIdIntFilter by chain (e.g., 1 for Ethereum, 8453 for Base)
yieldTypeYieldTypeFilter by yield type: CORE, TREASURY, FRONTIER, PRIME, TBILL, LENDING

ABIs

DistributorCodeDepositor

[
  {
    "inputs": [
      { "name": "depositAsset", "type": "address" },
      { "name": "depositAmount", "type": "uint256" },
      { "name": "minimumMint", "type": "uint256" },
      { "name": "to", "type": "address" },
      { "name": "distributorCode", "type": "bytes" }
    ],
    "name": "deposit",
    "outputs": [{ "name": "shares", "type": "uint256" }],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "depositAsset", "type": "address" },
      { "name": "depositAmount", "type": "uint256" },
      { "name": "minimumMint", "type": "uint256" },
      { "name": "to", "type": "address" },
      { "name": "distributorCode", "type": "bytes" },
      { "name": "deadline", "type": "uint256" },
      { "name": "v", "type": "uint8" },
      { "name": "r", "type": "bytes32" },
      { "name": "s", "type": "bytes32" }
    ],
    "name": "depositWithPermit",
    "outputs": [{ "name": "shares", "type": "uint256" }],
    "stateMutability": "nonpayable",
    "type": "function"
  }
]

WithdrawQueue

[
  {
    "inputs": [
      {
        "components": [
          { "name": "amountOffer", "type": "uint256" },
          { "name": "wantAsset", "type": "address" },
          { "name": "intendedDepositor", "type": "address" },
          { "name": "receiver", "type": "address" },
          { "name": "refundReceiver", "type": "address" },
          {
            "components": [
              { "name": "approvalMethod", "type": "uint8" },
              { "name": "approvalV", "type": "uint8" },
              { "name": "approvalR", "type": "bytes32" },
              { "name": "approvalS", "type": "bytes32" },
              { "name": "submitWithSignature", "type": "bool" },
              { "name": "deadline", "type": "uint256" },
              { "name": "eip2612Signature", "type": "bytes" }
            ],
            "name": "signatureParams",
            "type": "tuple"
          }
        ],
        "name": "params",
        "type": "tuple"
      }
    ],
    "name": "submitOrder",
    "outputs": [{ "name": "orderIndex", "type": "uint256" }],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [{ "name": "orderIndex", "type": "uint256" }],
    "name": "cancelOrder",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "orderIndex", "type": "uint256" },
      { "name": "deadline", "type": "uint256" },
      { "name": "cancelSignature", "type": "bytes" }
    ],
    "name": "cancelOrderWithSignature",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [{ "name": "orderIndex", "type": "uint256" }],
    "name": "getOrderStatus",
    "outputs": [{ "name": "", "type": "uint8" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "minimumOrderSize",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeModule",
    "outputs": [{ "name": "", "type": "address" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "owner", "type": "address" }],
    "name": "balanceOf",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "owner", "type": "address" },
      { "name": "index", "type": "uint256" }
    ],
    "name": "tokenOfOwnerByIndex",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "tokenId", "type": "uint256" }],
    "name": "ownerOf",
    "outputs": [{ "name": "", "type": "address" }],
    "stateMutability": "view",
    "type": "function"
  }
]

ERC-20 (BoringVault shares + deposit tokens)

[
  {
    "inputs": [
      { "name": "spender", "type": "address" },
      { "name": "amount", "type": "uint256" }
    ],
    "name": "approve",
    "outputs": [{ "name": "", "type": "bool" }],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      { "name": "owner", "type": "address" },
      { "name": "spender", "type": "address" }
    ],
    "name": "allowance",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "account", "type": "address" }],
    "name": "balanceOf",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [{ "name": "", "type": "uint8" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [{ "name": "owner", "type": "address" }],
    "name": "nonces",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]

Accountant

[
  {
    "inputs": [{ "name": "quote", "type": "address" }],
    "name": "getRateInQuoteSafe",
    "outputs": [{ "name": "rateInQuote", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]

FeeModule

[
  {
    "inputs": [
      { "name": "amount", "type": "uint256" },
      { "name": "offerAsset", "type": "address" },
      { "name": "wantAsset", "type": "address" },
      { "name": "receiver", "type": "address" }
    ],
    "name": "calculateOfferFees",
    "outputs": [{ "name": "feeAmount", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "offerFeePercentage",
    "outputs": [{ "name": "", "type": "uint256" }],
    "stateMutability": "view",
    "type": "function"
  }
]

Teller

[
  {
    "inputs": [],
    "name": "isPaused",
    "outputs": [{ "name": "", "type": "bool" }],
    "stateMutability": "view",
    "type": "function"
  }
]

Pre-Flight: Pause State Check

Before submitting any deposit or withdrawal transaction, check whether the vault is paused:
const paused = await publicClient.readContract({
  address: TELLER,
  abi: tellerAbi,
  functionName: 'isPaused',
})
if (paused) throw new Error('Vault is paused — transactions will revert with TellerIsPaused')

Deposit Flow — Standard (Approve + Deposit)

Two transactions: ERC-20 approve() then deposit().
// Step 1: Check allowance
const allowance = await publicClient.readContract({
  address: DEPOSIT_TOKEN,
  abi: erc20Abi,
  functionName: 'allowance',
  args: [account.address, DISTRIBUTOR_CODE_DEPOSITOR],
})

// Step 2: Approve if needed
if (allowance < depositAmount) {
  // USDT QUIRK: if token is USDT and allowance > 0, reset to 0 first
  // await walletClient.writeContract({ address: DEPOSIT_TOKEN, abi: erc20Abi, functionName: 'approve', args: [DISTRIBUTOR_CODE_DEPOSITOR, 0n] })
  const hash = await walletClient.writeContract({
    address: DEPOSIT_TOKEN,
    abi: erc20Abi,
    functionName: 'approve',
    args: [DISTRIBUTOR_CODE_DEPOSITOR, depositAmount],
  })
  await publicClient.waitForTransactionReceipt({ hash })
}

// Step 3: Calculate minimumMint (slippage protection)
const rate = await publicClient.readContract({
  address: ACCOUNTANT,
  abi: accountantAbi,
  functionName: 'getRateInQuoteSafe',
  args: [DEPOSIT_TOKEN],
})
const SLIPPAGE_BPS = 50n // 0.5%
const expectedShares = (depositAmount * 10n ** 18n) / rate
const minimumMint = expectedShares - (expectedShares * SLIPPAGE_BPS) / 10000n

// Step 4: Deposit
const hash = await walletClient.writeContract({
  address: DISTRIBUTOR_CODE_DEPOSITOR,
  abi: depositorAbi,
  functionName: 'deposit',
  args: [DEPOSIT_TOKEN, depositAmount, minimumMint, account.address, '0x'],
})
const receipt = await publicClient.waitForTransactionReceipt({ hash })

Deposit Parameters

ParameterTypeDescription
depositAssetaddressERC-20 token to deposit (e.g., USDC)
depositAmountuint256Amount in token’s smallest unit (USDC 6 decimals: 1000 USDC = 1000000000)
minimumMintuint256Min shares to receive (slippage protection). 0 to disable.
toaddressRecipient of minted vault shares
distributorCodebytesReferral code as bytes. 0x if none.

Distributor Codes

If Paxos Labs provided a distributor code, encode it as bytes: toHex('your_code') in JS, b'your_code' in Python, []byte("your_code") in Go. Otherwise pass 0x / b"" / []byte{}.

Deposit Flow — Permit (Single Transaction)

For tokens supporting EIP-2612 (USDC, USDG, pyUSD, USD₮0). Not available for USDT. Not available for smart contract wallets (Privy Smart Wallets, Safe) — they cannot sign typed data.
// Step 1: Get permit nonce
const nonce = await publicClient.readContract({
  address: DEPOSIT_TOKEN,
  abi: erc20Abi,
  functionName: 'nonces',
  args: [account.address],
})

// Step 2: Sign EIP-712 permit
const deadline = BigInt(Math.floor(Date.now() / 1000) + 3600)
const signature = await walletClient.signTypedData({
  account,
  domain: {
    name: 'USD Coin',        // varies by token — must match token's EIP-712 domain
    version: '2',            // varies by token
    chainId: 1,
    verifyingContract: DEPOSIT_TOKEN,
  },
  types: {
    Permit: [
      { name: 'owner', type: 'address' },
      { name: 'spender', type: 'address' },
      { name: 'value', type: 'uint256' },
      { name: 'nonce', type: 'uint256' },
      { name: 'deadline', type: 'uint256' },
    ],
  },
  primaryType: 'Permit',
  message: {
    owner: account.address,
    spender: DISTRIBUTOR_CODE_DEPOSITOR,
    value: depositAmount,
    nonce,
    deadline,
  },
})

// Step 3: Parse signature into v, r, s
const { v, r, s } = parseSignature(signature) // viem: import { parseSignature } from 'viem'

// Step 4: Calculate minimumMint (same as standard flow)
const rate = await publicClient.readContract({
  address: ACCOUNTANT,
  abi: accountantAbi,
  functionName: 'getRateInQuoteSafe',
  args: [DEPOSIT_TOKEN],
})
const expectedShares = (depositAmount * 10n ** 18n) / rate
const minimumMint = expectedShares - (expectedShares * 50n) / 10000n

// Step 5: depositWithPermit (single transaction — no separate approve needed)
const hash = await walletClient.writeContract({
  address: DISTRIBUTOR_CODE_DEPOSITOR,
  abi: depositorAbi,
  functionName: 'depositWithPermit',
  args: [DEPOSIT_TOKEN, depositAmount, minimumMint, account.address, '0x', deadline, v, r, s],
})

Permit EIP-712 Domain (varies by token)

Tokennameversion
USDC"USD Coin""2"
USDGCheck tokenCheck
pyUSDCheck tokenCheck
USD₮0Check tokenCheck
Always read the token’s name(), version() (or EIP712_VERSION()) and use those for the domain.

Slippage / minimumMint Formula

rate           = Accountant.getRateInQuoteSafe(depositTokenAddress)
expectedShares = (depositAmount × 1e18) / rate
minimumMint    = expectedShares × (10000 − SLIPPAGE_BPS) / 10000
Common default: SLIPPAGE_BPS = 50 (0.5%). Setting minimumMint = 0 disables slippage protection (fine for testing, not production).

Withdrawal Flow (Complete)

Withdrawals are order-based, not instant. The vault operator fulfills orders (typically within 24 hours).
// Step 1: Check share balance
const shareBalance = await publicClient.readContract({
  address: BORING_VAULT,
  abi: erc20Abi,
  functionName: 'balanceOf',
  args: [account.address],
})

// Step 2: Convert want amount to shares
const rate = await publicClient.readContract({
  address: ACCOUNTANT,
  abi: accountantAbi,
  functionName: 'getRateInQuoteSafe',
  args: [WANT_ASSET], // e.g., USDC address
})
const wantAmount = parseUnits('1000', 6) // 1000 USDC
let sharesNeeded = (wantAmount * 10n ** 18n) / rate

// Step 3: Calculate withdrawal fee
const feeModuleAddr = await publicClient.readContract({
  address: WITHDRAW_QUEUE,
  abi: queueAbi,
  functionName: 'feeModule',
})
const feeAmount = await publicClient.readContract({
  address: feeModuleAddr,
  abi: feeModuleAbi,
  functionName: 'calculateOfferFees',
  args: [sharesNeeded, BORING_VAULT, WANT_ASSET, account.address],
})
// Fee is deducted from offered shares. To receive full wantAmount, add fee:
sharesNeeded = sharesNeeded + feeAmount

// Step 4: Check minimum order size
const minimumShares = await publicClient.readContract({
  address: WITHDRAW_QUEUE,
  abi: queueAbi,
  functionName: 'minimumOrderSize',
})
if (sharesNeeded < minimumShares) throw new Error('Below minimum order size')

// Step 5: Approve vault shares to WithdrawQueue
const allowance = await publicClient.readContract({
  address: BORING_VAULT,
  abi: erc20Abi,
  functionName: 'allowance',
  args: [account.address, WITHDRAW_QUEUE],
})
if (allowance < sharesNeeded) {
  const hash = await walletClient.writeContract({
    address: BORING_VAULT,
    abi: erc20Abi,
    functionName: 'approve',
    args: [WITHDRAW_QUEUE, sharesNeeded],
  })
  await publicClient.waitForTransactionReceipt({ hash })
}

// Step 6: Submit withdrawal order
const EMPTY_SIG = {
  approvalMethod: 0,
  approvalV: 0,
  approvalR: ('0x' + '00'.repeat(32)) as `0x${string}`,
  approvalS: ('0x' + '00'.repeat(32)) as `0x${string}`,
  submitWithSignature: false,
  deadline: 0n,
  eip2612Signature: '0x' as `0x${string}`,
}

const hash = await walletClient.writeContract({
  address: WITHDRAW_QUEUE,
  abi: queueAbi,
  functionName: 'submitOrder',
  args: [
    {
      amountOffer: sharesNeeded,
      wantAsset: WANT_ASSET,
      intendedDepositor: account.address, // MUST match msg.sender
      receiver: account.address,
      refundReceiver: account.address,
      signatureParams: EMPTY_SIG,
    },
  ],
})
const receipt = await publicClient.waitForTransactionReceipt({ hash })
// Extract orderIndex from receipt logs or return value

// Step 7: Poll for completion
let status = 1
while (status === 1) {
  await new Promise((r) => setTimeout(r, 60_000))
  status = await publicClient.readContract({
    address: WITHDRAW_QUEUE,
    abi: queueAbi,
    functionName: 'getOrderStatus',
    args: [orderIndex],
  })
}
// status 2 = COMPLETE, 5 = REFUNDED, 6 = FAILED_TRANSFER_REFUNDED

submitOrder Parameters

FieldTypeDescription
amountOfferuint256Vault shares to offer (18 decimals)
wantAssetaddressToken to receive (e.g., USDC). Must be withdrawable.
intendedDepositoraddressMust match msg.sender
receiveraddressWhere the want asset is sent when fulfilled
refundReceiveraddressWhere shares go if order is cancelled
signatureParamstuplePass all-zeros struct for standard ERC-20 approval flow

Share-to-Asset Conversion

rate         = Accountant.getRateInQuoteSafe(wantAssetAddress)
sharesNeeded = (wantAmount × 1e18) / rate

Withdrawal Fee Calculation

feeModuleAddr = WithdrawQueue.feeModule()
feeAmount     = FeeModule.calculateOfferFees(shareAmount, boringVaultAddress, wantAssetAddress, receiverAddress)
feePercentage = FeeModule.offerFeePercentage()  // 18-decimal precision, e.g., 5000000000000000 = 0.5%
Fee is subtracted from offered shares. To receive the full want amount, offer sharesNeeded + feeAmount.

Cancellation Flow — Direct

Only orders with PENDING status (value 1) can be cancelled. The WithdrawQueue is an ERC-721 — each order is an NFT.
// Enumerate order NFTs
const count = await publicClient.readContract({
  address: WITHDRAW_QUEUE,
  abi: queueAbi,
  functionName: 'balanceOf',
  args: [account.address],
})
for (let i = 0n; i < count; i++) {
  const orderIndex = await publicClient.readContract({
    address: WITHDRAW_QUEUE,
    abi: queueAbi,
    functionName: 'tokenOfOwnerByIndex',
    args: [account.address, i],
  })
  const status = await publicClient.readContract({
    address: WITHDRAW_QUEUE,
    abi: queueAbi,
    functionName: 'getOrderStatus',
    args: [orderIndex],
  })
  if (status === 1) {
    // PENDING — cancel it
    const hash = await walletClient.writeContract({
      address: WITHDRAW_QUEUE,
      abi: queueAbi,
      functionName: 'cancelOrder',
      args: [orderIndex],
    })
    await publicClient.waitForTransactionReceipt({ hash })
    // Shares returned to refundReceiver set during submitOrder
  }
}
If you already have the orderIndex (from the OrderSubmitted event), skip enumeration and call cancelOrder(orderIndex) directly after verifying getOrderStatus(orderIndex) === 1.

Cancellation Flow — Meta-Transaction (Gasless)

A relayer submits the cancellation on behalf of the order owner using an EIP-712 signature.

EIP-712 Cancel Signature

// Order owner signs off-chain
const cancelDeadline = BigInt(Math.floor(Date.now() / 1000) + 3600)
const signature = await walletClient.signTypedData({
  account,
  domain: {
    name: 'WithdrawQueue',
    chainId: 1,
    verifyingContract: WITHDRAW_QUEUE,
  },
  types: {
    Cancel: [
      { name: 'orderIndex', type: 'uint256' },
      { name: 'deadline', type: 'uint256' },
      { name: 'queueAddress', type: 'address' },
      { name: 'chainId', type: 'uint256' },
    ],
  },
  primaryType: 'Cancel',
  message: {
    orderIndex,
    deadline: cancelDeadline,
    queueAddress: WITHDRAW_QUEUE,
    chainId: 1n,
  },
})

// Relayer submits (anyone can call this)
await walletClient.writeContract({
  address: WITHDRAW_QUEUE,
  abi: queueAbi,
  functionName: 'cancelOrderWithSignature',
  args: [orderIndex, cancelDeadline, signature],
})
The deadline in the signed message and the function call must match exactly. Reverts with SignatureExpired if the block timestamp exceeds the deadline.

REST API Endpoints

All require x-api-key: <your_key> header. Base URL: https://api.paxoslabs.com

Vault APY

GET /v2/amplify/vaultApys?filter=vaultAddress%3D{VAULT_ADDRESS}&orderByTimestamp=desc&pageSize=1
{ "vaultApys": [{ "vaultAddress": "0x...", "chainId": 1, "apy": "0.0523", "timestamp": "2025-01-15T12:00:00Z" }] }
apy is a decimal string — multiply by 100 for percentage (e.g., 0.0523 = 5.23%).

Vault TVL

GET /v2/amplify/vaultTvls?filter=vaultAddress%3D{VAULT_ADDRESS}&includeCurrent=true&orderByTimestamp=desc&pageSize=1
{ "vaultTvls": [{ "vaultAddress": "0x...", "chainId": 1, "tvl": "15234567.89", "timestamp": "2025-01-15T12:00:00Z" }] }

Vault Assets (simplified vault discovery)

GET /v2/amplify/vaultAssets?pageSize=100
{
  "vaultAssets": [{ "vaultAddress": "0x...", "chainId": 1, "assetAddress": "0x...", "depositable": true, "withdrawable": true }],
  "nextPageToken": null,
  "tokenMetadata": { "1:0xA0b8...": { "address": "0xA0b8...", "chain_id": "1", "symbol": "USDC", "name": "USD Coin", "decimals": "6" } }
}
Only returns vaultAddress (BoringVault). Use the GraphQL API for full contract addresses.

Withdrawal Requests

GET /v2/amplify/withdrawalRequests?filter=userAddress%3D{USER_ADDRESS}&pageSize=20
{
  "withdrawalRequests": [{
    "orderIndex": "42", "userAddress": "0x...", "vaultAddress": "0x...", "chainId": 1,
    "offerAmount": "1000000000000000000", "wantAsset": "0x...", "status": "PENDING",
    "createdAt": "2025-01-15T10:30:00Z", "fulfilledAt": null
  }],
  "nextPageToken": null
}
REST status values: PENDING, COMPLETE, PENDING_REFUND, REFUNDED.

Order Status Enum (On-Chain)

ValueStatusCancellable?
0NOT_FOUNDNo
1PENDINGYes
2COMPLETENo
3COMPLETE_PRE_FILLEDNo
4PENDING_REFUNDNo
5COMPLETE_REFUNDEDNo
6FAILED_TRANSFER_REFUNDEDNo

Token Notes

TokenDecimalsPermit (EIP-2612)Notes
USDC6Yes
USDG6Yes
pyUSD6Yes
USD₮06Yes
USDT6NoMust reset allowance to 0 before setting new value
For USDT: if current allowance > 0, call approve(spender, 0) first, then approve(spender, amount). Smart contract wallets (Privy Smart Wallets, Safe) cannot sign permits — use the standard approve + deposit flow.

Common Revert Errors

ErrorCauseFix
TellerIsPausedVault operations pausedCheck Teller.isPaused() before submitting
PermitFailedAndAllowanceTooLowInvalid permit sig and no existing ERC-20 approvalFix EIP-712 domain params or use approve flow
ERC20: insufficient allowanceSpender not approvedCall approve() on token first
ERC20: transfer amount exceeds balanceInsufficient token balanceCheck balanceOf() before transacting
AmountBelowMinimumWithdrawal order below minimum sizeCheck WithdrawQueue.minimumOrderSize()
InvalidDepositorintendedDepositormsg.senderSet intendedDepositor to the transaction sender
AssetNotSupportedWant asset not enabled for this vaultCheck supportedAssets with withdrawable: true
OnlyOrderOwnerCanCancelCaller doesn’t own the order NFTOnly the NFT holder can cancel
InvalidOrderTypeOrder not in PENDING statusCheck getOrderStatus() — only status 1 cancellable
SignatureExpiredMeta-tx cancel deadline passedRe-sign with future deadline

Supported Chains

ChainID
Ethereum1
HyperEVM999
Base8453