The unified deposit API simplifies deposits by automatically detecting the optimal authorization method. Use prepareDepositAuthorization() to determine the method, then prepareDeposit() to execute.
Breaking change in v0.5.0: All transaction functions identify vaults by
vaultName: string instead of yieldType. Use getVaultsByConfig() or
findVaultByConfig() to discover vault names first. See the
migration guide.
Import
import {
prepareDepositAuthorization,
prepareDeposit,
getVaultsByConfig,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from '@paxoslabs/amplify-sdk'
prepareDepositAuthorization()
Determines the optimal authorization method for a deposit operation.
Function Signature
async function prepareDepositAuthorization(
params: PrepareDepositAuthorizationParams
): Promise<DepositAuthorizationResult>
Parameters
interface PrepareDepositAuthorizationParams {
/** Human-readable vault name (from AmplifyVault.name) */
vaultName: string
/** Token contract address to deposit */
depositAsset: Address
/** Amount of assets to deposit as decimal string (e.g., "100.25") */
depositAmount: string
/** User's wallet address (permit owner / approval sender) */
to: Address
/** Blockchain network ID */
chainId: number
/** Optional deadline for permit signature (defaults to 1 hour from now) */
deadline?: bigint
/** Force specific authorization method (bypasses automatic detection) */
forceMethod?: 'permit' | 'approval'
}
| Parameter | Type | Required | Description |
|---|
vaultName | string | Yes | Vault name from AmplifyVault.name (e.g. from getVaultsByConfig()) |
depositAsset | Address | Yes | Token contract address to deposit |
depositAmount | string | Yes | Amount as decimal string (e.g., “100.25”) |
to | Address | Yes | Recipient address for vault shares |
chainId | number | Yes | Blockchain network ID |
deadline | bigint | No | Permit deadline (defaults to 1 hour) |
forceMethod | "permit" | "approval" | No | Override automatic detection |
Return Type (Discriminated Union)
Type Definition
Permit Result
Approval Result
Already Approved Result
type DepositAuthorizationResult =
| PermitAuthorizationResult
| ApprovalAuthorizationResult
| AlreadyApprovedAuthorizationResult;
/** Returned when token supports EIP-2612 permit */
interface PermitAuthorizationResult {
method: "permit";
/** EIP-712 typed data ready for wallet signing */
permitData: PermitSignatureData;
}
/** Returned when an ERC20 approval transaction is needed */
interface ApprovalAuthorizationResult {
method: "approval";
/** Transaction data for ERC20 approve() call */
txData: ApproveDepositTokenTxData;
}
/** Returned when existing allowance is sufficient */
interface AlreadyApprovedAuthorizationResult {
method: "already_approved";
/** Current allowance (human-readable) */
allowance: string;
/** Current allowance as BigInt string */
allowanceAsBigInt: string;
}
Decision Logic
The function follows this priority order:
- Check
forceMethod — If specified, use that method directly
- Detect smart wallet — If the address has deployed bytecode (Safe, EIP-4337, EIP-7702), route to
APPROVAL so callers can batch approve + deposit atomically
- Check permit support — If the token supports EIP-2612, return permit signature data
- Check existing allowance — If sufficient, return
ALREADY_APPROVED
- Default to approval — Return approval transaction data
Token Permit Support
The following table shows which supported tokens use the gas-efficient EIP-2612 permit path versus the standard ERC-20 approval path. The SDK detects this automatically — use forceMethod: "approval" to override when needed (e.g., smart contract wallets).
| Token | Authorization Method | Notes |
|---|
| USDC | Permit (EIP-2612) | Single-transaction gasless signature |
| USDG | Permit (EIP-2612) | Single-transaction gasless signature |
| pyUSD | Permit (EIP-2612) | Single-transaction gasless signature |
| USD₮0 | Permit (EIP-2612) | Single-transaction gasless signature |
| USDT | Approval (ERC-20) | Requires separate approval transaction. Also requires resetting allowance to 0 before setting a new value when a non-zero allowance already exists. |
prepareDeposit()
Prepares transaction data for a deposit, automatically using the correct method based on provided parameters.
Function Signature
async function prepareDeposit(
params: PrepareDepositParams
): Promise<PrepareDepositResult>
Parameters
interface PrepareDepositParams {
/** Human-readable vault name (from AmplifyVault.name) */
vaultName: string
/** Token contract address to deposit */
depositAsset: Address
/** Amount of assets to deposit as decimal string (e.g., "100.25") */
depositAmount: string
/** Recipient address for vault shares */
to: Address
/** Blockchain network ID */
chainId: number
/** Permit signature (required for permit flow) */
signature?: Hex
/** Permit deadline (required for permit flow) */
deadline?: bigint
/** Optional slippage in basis points (default: 50 = 0.5%) */
slippage?: number
/** Optional distributor code for fee attribution */
distributorCode?: string
/** Force deposit method (bypasses automatic routing) */
forceMethod?: 'permit' | 'approval'
}
Return Type
Returns a discriminated union based on which deposit method is used:
/** Standard deposit (after approval or when already approved) */
interface StandardDepositResult {
method: 'approval'
txData: DepositTxData // flat: { abi, address, functionName, args, chainId }
}
/** Permit deposit (with signature) */
interface PermitDepositResult {
method: 'permit'
txData: UnencodedDepositWithPermitData // nested: { address, chainId, data: { abi, functionName, args } }
}
type PrepareDepositResult = StandardDepositResult | PermitDepositResult
The two result variants have different txData shapes. Standard deposits use
a flat structure (txData.abi), while permit deposits use a nested structure
(txData.data.abi). Use result.method to determine which shape you’re
working with.
Complete Flow Example
import { mainnet } from 'viem/chains'
import {
getVaultsByConfig,
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from '@paxoslabs/amplify-sdk'
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48' as `0x${string}`
// Step 0: Discover the vault to get its name
const [vault] = await getVaultsByConfig({
yieldType: YieldType.CORE,
chainId: mainnet.id,
depositAssetAddress: USDC,
})
const params = {
vaultName: vault.name,
depositAsset: USDC,
depositAmount: '1000',
to: userAddress,
chainId: mainnet.id,
}
// Step 1: Get authorization method
const auth = await prepareDepositAuthorization(params)
// Step 2: Handle based on method using type guards
if (isPermitAuth(auth)) {
// Sign permit off-chain
const signature = await walletClient.signTypedData({
account: userAddress,
...auth.permitData,
})
// Prepare and execute deposit with permit
const prepared = await prepareDeposit({
...params,
signature,
deadline: auth.permitData.message.deadline,
})
// Permit path: txData has nested .data structure
await walletClient.writeContract({
address: prepared.txData.address,
abi: prepared.txData.data.abi,
functionName: prepared.txData.data.functionName,
args: prepared.txData.data.args,
account: userAddress,
})
} else if (isApprovalAuth(auth)) {
// Execute approval first
const approvalHash = await walletClient.writeContract(auth.txData)
await publicClient.waitForTransactionReceipt({ hash: approvalHash })
// Then deposit (standard path: txData is flat)
const prepared = await prepareDeposit(params)
await walletClient.writeContract(prepared.txData)
} else if (isAlreadyApprovedAuth(auth)) {
// Deposit directly (standard path: txData is flat)
const prepared = await prepareDeposit(params)
await walletClient.writeContract(prepared.txData)
}
Force Specific Method
Override automatic detection when needed:
// Force permit even if automatic detection would choose approval
const authForcePermit = await prepareDepositAuthorization({
...params,
forceMethod: 'permit',
})
// Force approval even for permit-supporting tokens (useful for smart wallets)
const authForceApproval = await prepareDepositAuthorization({
...params,
forceMethod: 'approval',
})
Slippage Configuration
const prepared = await prepareDeposit({
...params,
slippage: 100, // 1% instead of default 0.5%
})
Error Handling
| Error Message Pattern | Description | Resolution |
|---|
"SDK not initialized" | SDK used before init | Call initAmplifySDK() first |
"Vault not found" | No vault matches vaultName | Verify vault name via getVaultsByConfig() |
"does not support EIP-2612 permit" | Token doesn’t support permits | Use approval flow instead |
"requires both signature and deadline" | Missing permit params | Provide signature and deadline for permit deposits |