The unified deposit API handles three authorization paths automatically:
- Permit - Gas-efficient off-chain signature (EIP-2612)
- Approval - Standard ERC-20 approval transaction
- Already Approved - Direct deposit when allowance exists
Prerequisites
- Node.js 22+
- Amplify API key from Paxos Labs
- SDK initialized with
initAmplifySDK()
Installation
- Privy
- Wagmi
- Viem
Copy
Ask AI
pnpm add @paxoslabs/amplify-sdk @privy-io/react-auth viem @tanstack/react-query
Copy
Ask AI
pnpm add @paxoslabs/amplify-sdk wagmi viem @tanstack/react-query
Copy
Ask AI
pnpm add @paxoslabs/amplify-sdk viem
Imports
- Privy
- Wagmi
- Viem
Copy
Ask AI
// SDK imports
import {
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
// Privy imports
import { usePrivy, useWallets } from "@privy-io/react-auth";
// Viem imports
import { encodeFunctionData } from "viem";
import { mainnet } from "viem/chains";
Copy
Ask AI
// SDK imports
import {
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
// Wagmi imports
import { useAccount, useWriteContract, useSignTypedData } from "wagmi";
Copy
Ask AI
// SDK imports
import {
initAmplifySDK,
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
// Viem imports
import { createWalletClient, createPublicClient, custom, http } from "viem";
import { mainnet } from "viem/chains";
Complete Examples
- Privy
- Wagmi
- Viem
useDeposit Hook
Copy
Ask AI
// src/hooks/useDeposit.ts
import { useState, useCallback } from "react";
import { encodeFunctionData } from "viem";
import { mainnet } from "viem/chains";
import {
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
declare const usePrivy: () => { sendTransaction: (tx: any) => Promise<string> };
declare const useWallets: () => { wallets: Array<{ address: string; getEthereumProvider: () => Promise<any> }> };
interface DepositParams {
amount: string;
depositAsset: `0x${string}`;
yieldType: YieldType;
}
export function useDeposit() {
const { sendTransaction } = usePrivy();
const { wallets } = useWallets();
const [status, setStatus] = useState<string>("");
const [isLoading, setIsLoading] = useState(false);
const deposit = useCallback(
async ({ amount, depositAsset, yieldType }: DepositParams) => {
const wallet = wallets[0];
if (!wallet) {
throw new Error("Connect a wallet first");
}
setIsLoading(true);
const to = wallet.address as `0x${string}`;
try {
const params = {
yieldType,
depositAsset,
depositAmount: amount,
to,
chainId: mainnet.id,
};
// Step 1: Get authorization method
setStatus("Checking authorization...");
const auth = await prepareDepositAuthorization(params);
// Step 2: Handle based on method using type guards
if (isPermitAuth(auth)) {
setStatus("Please sign permit in your wallet...");
const provider = await wallet.getEthereumProvider();
const signature = (await provider.request({
method: "eth_signTypedData_v4",
params: [
to,
JSON.stringify({
domain: auth.permitData.domain,
types: auth.permitData.types,
primaryType: auth.permitData.primaryType,
message: auth.permitData.message,
}),
],
})) as `0x${string}`;
setStatus("Submitting deposit...");
const prepared = await prepareDeposit({
...params,
signature,
deadline: BigInt(auth.permitData.message.deadline),
});
await sendTransaction({
chainId: prepared.txData.chainId,
to: prepared.txData.address,
data: encodeFunctionData({
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
}),
});
} else if (isApprovalAuth(auth)) {
setStatus("Approving token spend...");
await sendTransaction({
chainId: mainnet.id,
to: auth.txData.address,
data: encodeFunctionData({
abi: auth.txData.abi,
functionName: auth.txData.functionName,
args: auth.txData.args,
}),
});
setStatus("Submitting deposit...");
const prepared = await prepareDeposit(params);
await sendTransaction({
chainId: prepared.txData.chainId,
to: prepared.txData.address,
data: encodeFunctionData({
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
}),
});
} else if (isAlreadyApprovedAuth(auth)) {
setStatus("Submitting deposit...");
const prepared = await prepareDeposit(params);
await sendTransaction({
chainId: prepared.txData.chainId,
to: prepared.txData.address,
data: encodeFunctionData({
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
}),
});
}
setStatus("Deposit successful!");
} catch (error) {
setStatus(`Error: ${error instanceof Error ? error.message : "Unknown"}`);
throw error;
} finally {
setIsLoading(false);
}
},
[wallets, sendTransaction]
);
return { deposit, status, isLoading };
}
Deposit Component
Copy
Ask AI
// src/components/DepositForm.tsx
import { useState } from "react";
import { YieldType } from "@paxoslabs/amplify-sdk";
import { useDeposit } from "../hooks/useDeposit";
const USDC_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as const;
export function DepositForm() {
const [amount, setAmount] = useState("100");
const { deposit, status, isLoading } = useDeposit();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await deposit({
amount,
depositAsset: USDC_ADDRESS,
yieldType: YieldType.CORE,
});
};
return (
<form onSubmit={handleSubmit}>
<label>
Amount (USDC):
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
disabled={isLoading}
min="0"
step="0.01"
/>
</label>
<button type="submit" disabled={isLoading}>
{isLoading ? "Processing..." : "Deposit"}
</button>
{status && <p>{status}</p>}
</form>
);
}
useDeposit Hook
Copy
Ask AI
// src/hooks/useDeposit.ts
import { useState, useCallback } from "react";
import { useAccount, useWriteContract, useSignTypedData } from "wagmi";
import {
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
interface DepositParams {
amount: string;
depositAsset: `0x${string}`;
yieldType: YieldType;
}
export function useDeposit() {
const { address, chainId } = useAccount();
const { writeContractAsync } = useWriteContract();
const { signTypedDataAsync } = useSignTypedData();
const [status, setStatus] = useState<string>("");
const [isLoading, setIsLoading] = useState(false);
const deposit = useCallback(
async ({ amount, depositAsset, yieldType }: DepositParams) => {
if (!address || !chainId) {
throw new Error("Connect a wallet first");
}
setIsLoading(true);
try {
const params = {
yieldType,
depositAsset,
depositAmount: amount,
to: address,
chainId,
};
// Step 1: Get authorization method
setStatus("Checking authorization...");
const auth = await prepareDepositAuthorization(params);
// Step 2: Handle based on method using type guards
if (isPermitAuth(auth)) {
setStatus("Please sign permit in your wallet...");
const signature = await signTypedDataAsync(auth.permitData);
setStatus("Submitting deposit...");
const prepared = await prepareDeposit({
...params,
signature,
deadline: BigInt(auth.permitData.message.deadline),
});
await writeContractAsync({
address: prepared.txData.address,
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
account: address,
});
} else if (isApprovalAuth(auth)) {
setStatus("Approving token spend...");
await writeContractAsync({
...auth.txData,
account: address,
});
setStatus("Submitting deposit...");
const prepared = await prepareDeposit(params);
await writeContractAsync({
address: prepared.txData.address,
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
account: address,
});
} else if (isAlreadyApprovedAuth(auth)) {
setStatus("Submitting deposit...");
const prepared = await prepareDeposit(params);
await writeContractAsync({
address: prepared.txData.address,
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
account: address,
});
}
setStatus("Deposit successful!");
} catch (error) {
setStatus(`Error: ${error instanceof Error ? error.message : "Unknown"}`);
throw error;
} finally {
setIsLoading(false);
}
},
[address, chainId, writeContractAsync, signTypedDataAsync]
);
return { deposit, status, isLoading };
}
Deposit Component
Copy
Ask AI
// src/components/DepositForm.tsx
import { useState } from "react";
import { useAccount } from "wagmi";
import { YieldType } from "@paxoslabs/amplify-sdk";
import { useDeposit } from "../hooks/useDeposit";
const USDC_ADDRESS = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as const;
export function DepositForm() {
const { isConnected } = useAccount();
const [amount, setAmount] = useState("100");
const { deposit, status, isLoading } = useDeposit();
if (!isConnected) {
return <p>Please connect your wallet</p>;
}
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
await deposit({
amount,
depositAsset: USDC_ADDRESS,
yieldType: YieldType.CORE,
});
};
return (
<form onSubmit={handleSubmit}>
<label>
Amount (USDC):
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
disabled={isLoading}
min="0"
step="0.01"
/>
</label>
<button type="submit" disabled={isLoading}>
{isLoading ? "Processing..." : "Deposit"}
</button>
{status && <p>{status}</p>}
</form>
);
}
Complete Script
This example uses pure viem without React, suitable for Node.js scripts or vanilla TypeScript applications.Copy
Ask AI
// deposit.ts
import { createWalletClient, createPublicClient, custom, http } from "viem";
import { mainnet } from "viem/chains";
import {
initAmplifySDK,
prepareDepositAuthorization,
prepareDeposit,
isPermitAuth,
isApprovalAuth,
isAlreadyApprovedAuth,
YieldType,
} from "@paxoslabs/amplify-sdk";
declare const window: { ethereum: any };
declare const process: { env: { AMPLIFY_API_KEY: string } };
// Configuration
const CONFIG = {
apiKey: process.env.AMPLIFY_API_KEY!,
depositAsset: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as `0x${string}`, // USDC
depositAmount: "1000",
yieldType: YieldType.CORE,
};
async function main() {
// Step 1: Initialize SDK
console.log("Initializing SDK...");
await initAmplifySDK(CONFIG.apiKey);
// Step 2: Connect wallet
console.log("Connecting wallet...");
const ethereum = window.ethereum;
if (!ethereum) {
throw new Error("No wallet found");
}
const [account] = (await ethereum.request({
method: "eth_requestAccounts",
})) as `0x${string}`[];
const walletClient = createWalletClient({
account,
chain: mainnet,
transport: custom(ethereum),
});
const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
});
// Step 3: Prepare deposit parameters
const params = {
yieldType: CONFIG.yieldType,
depositAsset: CONFIG.depositAsset,
depositAmount: CONFIG.depositAmount,
to: account,
chainId: mainnet.id,
};
// Step 4: Get authorization method
console.log("Checking authorization method...");
const auth = await prepareDepositAuthorization(params);
// Step 5: Handle based on method using type guards
if (isPermitAuth(auth)) {
console.log("Authorization method: permit");
console.log("Signing permit...");
const signature = await walletClient.signTypedData({
account,
domain: auth.permitData.domain,
types: auth.permitData.types,
primaryType: auth.permitData.primaryType,
message: auth.permitData.message,
});
console.log("Submitting deposit with permit...");
const prepared = await prepareDeposit({
...params,
signature,
deadline: BigInt(auth.permitData.message.deadline),
});
const permitHash = await walletClient.writeContract({
address: prepared.txData.address,
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
account,
});
console.log(`Deposit submitted: ${permitHash}`);
await publicClient.waitForTransactionReceipt({ hash: permitHash });
console.log("Deposit confirmed!");
} else if (isApprovalAuth(auth)) {
console.log("Authorization method: approval");
console.log(`Current allowance: ${auth.currentAllowance}`);
console.log("Sending approval transaction...");
const approvalHash = await walletClient.writeContract({
...auth.txData,
account,
});
console.log(`Approval submitted: ${approvalHash}`);
await publicClient.waitForTransactionReceipt({ hash: approvalHash });
console.log("Approval confirmed!");
console.log("Submitting deposit...");
const prepared = await prepareDeposit(params);
const depositHash = await walletClient.writeContract({
address: prepared.txData.address,
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
account,
});
console.log(`Deposit submitted: ${depositHash}`);
await publicClient.waitForTransactionReceipt({ hash: depositHash });
console.log("Deposit confirmed!");
} else if (isAlreadyApprovedAuth(auth)) {
console.log("Authorization method: already_approved");
console.log(`Existing allowance: ${auth.allowance}`);
console.log("Submitting deposit directly...");
const prepared = await prepareDeposit(params);
const directHash = await walletClient.writeContract({
address: prepared.txData.address,
abi: prepared.txData.abi,
functionName: prepared.txData.functionName,
args: prepared.txData.args,
account,
});
console.log(`Deposit submitted: ${directHash}`);
await publicClient.waitForTransactionReceipt({ hash: directHash });
console.log("Deposit confirmed!");
}
}
main().catch(console.error);
Running the Script
Copy
Ask AI
# Set environment variable
export AMPLIFY_API_KEY=pxl_your_api_key
# Run with tsx or ts-node
npx tsx deposit.ts
Expected Output
Copy
Ask AI
Initializing SDK...
Connecting wallet...
Checking authorization method...
Authorization method: permit
Signing permit...
Submitting deposit with permit...
Deposit submitted: 0x1234...
Deposit confirmed!
What the Code Does
- Checks authorization method - Determines if permit, approval, or already approved
- Handles permit flow - Signs typed data off-chain for gas-efficient authorization
- Handles approval flow - Sends approval transaction then deposit
- Handles pre-approved - Deposits directly if allowance exists
- Reports status - Updates UI with current operation status
Customization
Custom Slippage
Copy
Ask AI
const prepared = await prepareDeposit({
...params,
slippage: 100, // 1% instead of default 0.5%
});
Partner Code
Copy
Ask AI
const prepared = await prepareDeposit({
...params,
partnerCode: "your_partner_code",
});
Force Approval Flow
Copy
Ask AI
const auth = await prepareDepositAuthorization({
...params,
forceMethod: "approval", // Skip permit detection
});
Troubleshooting
| Issue | Solution |
|---|---|
| ”SDK not initialized” | Call initAmplifySDK() before using hooks |
| ”Connect a wallet first” | Ensure user has connected wallet |
| Permit signature fails | Token may not support EIP-2612, falls back to approval |
| Transaction reverts | Check token balance and allowance |