Skip to main content
The unified deposit API simplifies deposits by automatically detecting the optimal authorization method. Use prepareDepositAuthorization() to determine the method, then prepareDeposit() to execute.

Import

import {
  prepareDepositAuthorization,
  prepareDeposit,
  isPermitAuth,
  isApprovalAuth,
  isAlreadyApprovedAuth,
} 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 {
  /** Yield strategy type (e.g., YieldType.CORE) */
  yieldType: YieldType;

  /** 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: ChainId;

  /** Optional deadline for permit signature (defaults to 1 hour from now) */
  deadline?: bigint;

  /** Force specific authorization method (bypasses automatic detection) */
  forceMethod?: "permit" | "approval";
}
ParameterTypeRequiredDescription
yieldTypeYieldTypeYesYield strategy type (e.g., YieldType.CORE)
depositAssetAddressYesToken contract address to deposit
depositAmountstringYesAmount as decimal string (e.g., “100.25”)
toAddressYesRecipient address for vault shares
chainIdnumberYesBlockchain network ID
deadlinebigintNoPermit deadline (defaults to 1 hour)
forceMethod"permit" | "approval"NoOverride automatic detection

Return Type (Discriminated Union)

type DepositAuthorizationResult =
  | PermitAuthorizationResult
  | ApprovalAuthorizationResult
  | AlreadyApprovedAuthorizationResult;

Decision Logic

The function follows this priority order:
  1. Check forceMethod — If specified, use that method directly
  2. Detect smart wallet — If the address has deployed bytecode (Safe, EIP-4337, EIP-7702), route to APPROVAL so callers can batch approve + deposit atomically
  3. Check permit support — If the token supports EIP-2612, return permit signature data
  4. Check existing allowance — If sufficient, return ALREADY_APPROVED
  5. 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).
TokenAuthorization MethodNotes
USDCPermit (EIP-2612)Single-transaction gasless signature
USDGPermit (EIP-2612)Single-transaction gasless signature
pyUSDPermit (EIP-2612)Single-transaction gasless signature
USD₮0Permit (EIP-2612)Single-transaction gasless signature
USDTApproval (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 {
  /** Yield strategy type (e.g., YieldType.CORE) */
  yieldType: YieldType;

  /** 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: ChainId;

  /** 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 {
  prepareDepositAuthorization,
  prepareDeposit,
  isPermitAuth,
  isApprovalAuth,
  isAlreadyApprovedAuth,
  YieldType,
} from "@paxoslabs/amplify-sdk";

const params = {
  yieldType: YieldType.CORE,
  depositAsset: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as `0x${string}`, // 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 PatternDescriptionResolution
"SDK not initialized"SDK used before initCall initAmplifySDK() first
"No vault found for token..."No vault matches paramsVerify yieldType, token, chainId
"does not support EIP-2612 permit"Token doesn’t support permitsUse approval flow instead
"requires both signature and deadline"Missing permit paramsProvide signature and deadline for permit deposits