This example demonstrates a complete deposit flow using pure viem without React, suitable for Node.js scripts or vanilla TypeScript applications.
This example uses the unified deposit API which automatically detects the optimal authorization method (permit vs approval).
Prerequisites
- Node.js 18+
- viem 2+
- Amplify API key from Paxos Labs
Installation
pnpm add @paxoslabs/amplify-sdk viem
Complete Example
// deposit.ts
import { createWalletClient, createPublicClient, custom, http } from "viem";
import { mainnet } from "viem/chains";
import {
initAmplifySDK,
prepareDepositAuthorization,
prepareDepositTxData,
prepareDepositWithPermitTxData,
DepositAuthMethod,
YieldType,
} from "@paxoslabs/amplify-sdk";
// Configuration
const CONFIG = {
apiKey: process.env.AMPLIFY_API_KEY!,
depositToken: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" as `0x${string}`, // USDC
depositAmount: "1000",
yieldType: YieldType.PRIME,
};
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 as any).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,
depositToken: CONFIG.depositToken,
depositAmount: CONFIG.depositAmount,
recipientAddress: account,
chainId: mainnet.id,
};
// Step 4: Get authorization method
console.log("Checking authorization method...");
const auth = await prepareDepositAuthorization(params);
console.log(`Authorization method: ${auth.method}`);
// Step 5: Handle based on method
switch (auth.method) {
case DepositAuthMethod.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 permitTx = await prepareDepositWithPermitTxData({
...params,
signature,
deadline: BigInt(auth.permitData.message.deadline),
});
const permitHash = await walletClient.writeContract({
address: permitTx.address,
abi: permitTx.data.abi,
functionName: permitTx.data.functionName,
args: permitTx.data.args,
account,
});
console.log(`Deposit submitted: ${permitHash}`);
await publicClient.waitForTransactionReceipt({ hash: permitHash });
console.log("Deposit confirmed!");
break;
}
case DepositAuthMethod.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 depositTx = await prepareDepositTxData(params);
const depositHash = await walletClient.writeContract({
...depositTx,
account,
});
console.log(`Deposit submitted: ${depositHash}`);
await publicClient.waitForTransactionReceipt({ hash: depositHash });
console.log("Deposit confirmed!");
break;
}
case DepositAuthMethod.ALREADY_APPROVED: {
console.log(`Existing allowance: ${auth.allowance}`);
console.log("Submitting deposit directly...");
const directTx = await prepareDepositTxData(params);
const directHash = await walletClient.writeContract({
...directTx,
account,
});
console.log(`Deposit submitted: ${directHash}`);
await publicClient.waitForTransactionReceipt({ hash: directHash });
console.log("Deposit confirmed!");
break;
}
}
}
main().catch(console.error);
What This Code Does
- Initializes the SDK - Required before any SDK calls
- Connects to wallet - Uses injected provider (MetaMask, etc.)
- Checks authorization - Determines permit, approval, or already approved
- Signs permit if supported - Off-chain signature for gas efficiency
- Sends transactions - Approval and/or deposit
- Waits for confirmation - Uses
waitForTransactionReceipt
Key Features
- No React required - Pure TypeScript/JavaScript
- Full transaction lifecycle - From authorization to confirmation
- Console logging - Clear progress indicators
- Error handling - Proper async/await with catch
Running the Script
# Set environment variable
export AMPLIFY_API_KEY=pxl_your_api_key
# Run with tsx or ts-node
npx tsx deposit.ts
Expected Output
Initializing SDK...
Connecting wallet...
Checking authorization method...
Authorization method: permit
Signing permit...
Submitting deposit with permit...
Deposit submitted: 0x1234...
Deposit confirmed!
Customization
Custom Slippage
const depositTx = await prepareDepositTxData({
...params,
slippage: 100, // 1% instead of default 0.5%
});
Partner Code
const depositTx = await prepareDepositTxData({
...params,
partnerCode: "your_partner_code",
});
Force Approval Flow
const auth = await prepareDepositAuthorization({
...params,
forceMethod: "approval", // Skip permit detection
});
Troubleshooting
| Issue | Solution |
|---|
| ”No wallet found” | Ensure MetaMask or similar is installed |
| ”SDK not initialized” | Call initAmplifySDK() first |
| Transaction reverts | Check token balance and allowance |
| Permit fails | Token may not support EIP-2612 |
For more details, see Deposits.