Documentation Index
Fetch the complete documentation index at: https://docs.deframe.io/llms.txt
Use this file to discover all available pages before exploring further.
This example demonstrates how to deposit funds into a DeFi yield strategy (e.g., Aave lending) using the Deframe API with JavaScript/TypeScript.
Overview
This example covers:
- Fetching available strategies
- Getting strategy details
- Requesting a quote
- Generating transaction bytecode
- Executing transactions
- Verifying the deposit
Prerequisites
- Node.js 18+
- Deframe API key
- Ethereum wallet with USDC balance
- Basic understanding of async/await
Installation
Environment Variables
Create a .env file:
DEFRAME_API_KEY=your-api-key
WALLET_ADDRESS=0x...
PRIVATE_KEY=0x...
ETHEREUM_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/your-key
POLYGON_RPC_URL=https://polygon-mainnet.g.alchemy.com/v2/your-key
Never commit your .env file to version control. Add it to .gitignore.
Step-by-Step Walkthrough
1. Initialize API Client
import axios from 'axios'
const deframe = axios.create({
baseURL: 'https://api.deframe.io',
headers: {
'x-api-key': process.env.DEFRAME_API_KEY,
'Content-Type': 'application/json'
}
})
2. Fetch Available Strategies
const { data: strategies } = await deframe.get('/strategies', {
params: { page: '1', limit: '10' }
})
console.log('Available strategies:')
strategies.data.forEach(strategy => {
console.log(`- ${strategy.id} (${strategy.protocol})`)
console.log(` APY: ${(strategy.apy * 100).toFixed(2)}%`)
})
3. Get Strategy Details
const strategyId = 'aave-usdc-polygon'
const { data: strategy } = await deframe.get(`/strategies/${strategyId}`)
console.log('Strategy:', strategy.id)
console.log('Protocol:', strategy.protocol)
console.log('Network:', strategy.network)
console.log('Asset:', strategy.assetName)
console.log('APY:', (strategy.apy * 100).toFixed(2) + '%')
console.log('Status:', strategy.paused ? 'Paused' : 'Active')
4. Generate Bytecode
const { data: result } = await deframe.get('/strategies/aave-usdc-polygon/bytecode', {
params: {
action: 'lend',
amount: '1000000000',
wallet: walletAddress
}
})
console.log('ID:', result.id)
console.log('Transactions to execute:', result.bytecode.length)
Same-Chain Swap + Deposit
If you hold a different token (e.g., WETH) and want to deposit into a USDC strategy, pass the fromTokenAddress parameter. The API will return swap transaction(s) followed by the deposit bytecode:
const { data: result } = await deframe.get('/strategies/aave-usdc-polygon/bytecode', {
params: {
action: 'lend',
amount: '1000000000000000000', // 1 WETH (amount is in fromTokenAddress units)
wallet: walletAddress,
fromChainId: 137,
fromTokenAddress: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619' // WETH on Polygon
}
})
console.log('Cross-chain:', result.crossChain.isCrossChain) // false
console.log('Transactions to execute:', result.bytecode.length) // e.g. 2 (swap + deposit)
When fromTokenAddress is provided, include fromChainId or chainIdIn. For same-chain swap + deposit, use the strategy chain. The amount parameter refers to the amount of that token to swap, not the strategy’s underlying asset.
Cross-Chain Deposit
If the funds start on a different chain, pass fromChainId or chainIdIn plus fromTokenAddress. Store result.id; it is used for asynchronous tracking.
const { data: result } = await deframe.get('/strategies/aave-usdc-arbitrum/bytecode', {
params: {
action: 'lend',
amount: '1000000',
wallet: walletAddress,
fromChainId: 8453,
fromTokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' // USDC on Base
}
})
console.log('ID:', result.id)
console.log('Bridge:', result.quote.bridge)
console.log('Source chain:', result.chainIdIn)
console.log('Destination chain:', result.chainIdOut)
5. Execute Transactions
import { ethers } from 'ethers'
const provider = new ethers.JsonRpcProvider(process.env.POLYGON_RPC_URL)
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
for (const tx of result.bytecode) {
const transaction = await wallet.sendTransaction({
to: tx.to,
data: tx.data,
value: tx.value || '0',
chainId: tx.chainId
})
console.log('Transaction sent:', transaction.hash)
const receipt = await transaction.wait()
console.log('Confirmed in block:', receipt.blockNumber)
}
import { createWalletClient, http } from 'viem'
import { polygon } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
const account = privateKeyToAccount(process.env.PRIVATE_KEY)
const client = createWalletClient({
account,
chain: polygon,
transport: http(process.env.POLYGON_RPC_URL)
})
for (const tx of result.bytecode) {
const hash = await client.sendTransaction({
to: tx.to,
data: tx.data,
value: tx.value ? BigInt(tx.value) : 0n,
chain: polygon
})
console.log('Transaction sent:', hash)
const receipt = await client.waitForTransactionReceipt({ hash })
console.log('Confirmed in block:', receipt.blockNumber)
}
6. Verify Deposit
// Wait for indexing
await new Promise(resolve => setTimeout(resolve, 5000))
const { data: walletData } = await deframe.get(`/wallets/${walletAddress}`)
console.log('Wallet positions:')
walletData.positions.forEach(position => {
console.log(`${position.strategy.id}:`)
console.log(` Balance: ${position.spotPosition.currentPosition.humanized} ${position.spotPosition.currentPosition.symbol}`)
console.log(` Value: $${position.spotPosition.underlyingBalanceUSD}`)
console.log(` APY: ${(position.spotPosition.apy * 100).toFixed(2)}%`)
})
console.log('Total portfolio value: $' + walletData.summary.totalUnderlyingBalanceUSD)
7. Track Cross-Chain Deposit Status (Cross-Chain Only)
If you made a cross-chain deposit, the bridge and the destination-chain deposit happen in separate transactions and complete asynchronously. Use the id returned in the bytecode response to poll /actions/:id until the status reaches a terminal state.
const id = result.id // returned from /strategies/:id/bytecode
// (Optional) preview the bridge & expected output before signing
if (result.crossChain.isCrossChain) {
console.log(`Bridging via ${result.quote.bridge}`)
console.log(`Expected out: ${result.quote.outputAmount.humanized} ${result.quote.outputAmount.symbol}`)
console.log(`Min out: ${result.quote.minimumOutputAmount.humanized} ${result.quote.minimumOutputAmount.symbol}`)
}
async function waitForDeposit (id) {
const TERMINAL = ['SUCCESS', 'FAILED', 'REFUNDED', 'EXPIRED']
while (true) {
const { data: statusRecord } = await deframe.get(`/actions/${id}`)
console.log(`Status: ${statusRecord.status} (${statusRecord.transactions.length} tx)`)
if (TERMINAL.includes(statusRecord.status)) return statusRecord
await new Promise(resolve => setTimeout(resolve, 5000))
}
}
const finalStatus = await waitForDeposit(id)
console.log('Final transactions:')
finalStatus.transactions.forEach(tx => {
console.log(` ${tx.chain}: ${tx.txHash} (${tx.status})`)
})
8. Track Cross-Chain Deposit Status (Cross-Chain Only)
If you made a cross-chain deposit (you passed fromChainId in Step 5), the bridge and the destination-chain deposit happen in separate transactions and complete asynchronously. Use the id returned in the bytecode response to poll /actions/:id until the action reaches a terminal state.
const actionId = result.id // returned from /strategies/:id/bytecode
// (Optional) preview the bridge & expected output before signing
if (result.crossChain.isCrossChain) {
console.log(`Bridging via ${result.quote.bridge}`)
console.log(`Expected out: ${result.quote.outputAmount.humanized} ${result.quote.outputAmount.symbol}`)
console.log(`Min out: ${result.quote.minimumOutputAmount.humanized} ${result.quote.minimumOutputAmount.symbol}`)
}
async function waitForDeposit (actionId) {
const TERMINAL = ['SUCCESS', 'FAILED', 'REFUNDED', 'EXPIRED']
while (true) {
const { data: action } = await deframe.get(`/actions/${actionId}`)
console.log(`Status: ${action.status} (${action.transactions.length} tx)`)
if (TERMINAL.includes(action.status)) return action
await new Promise(resolve => setTimeout(resolve, 5000))
}
}
const finalAction = await waitForDeposit(actionId)
console.log('Final transactions:')
finalAction.transactions.forEach(tx => {
console.log(` ${tx.chain}: ${tx.txHash} (${tx.status})`)
})
Same-chain deposits do not require polling — the deposit completes inline with the user’s signed transaction. You can still call GET /actions/:id with the returned id for record-keeping.
Error Handling
The example includes comprehensive error handling:
try {
// Your code here
} catch (error) {
if (error.response?.data?.error) {
const apiError = error.response.data.error
console.error('API Error:', apiError.code)
console.error('Message:', apiError.message)
// Handle specific errors
if (apiError.code === 'STRATEGY_NOT_FOUND') {
console.log('Strategy does not exist or is not available')
} else if (apiError.code === 'INSUFFICIENT_BALANCE') {
console.log('Wallet does not have enough tokens')
}
} else {
console.error('Unexpected error:', error.message)
}
}
Running the Example
# Install dependencies
npm install
# Set environment variables
cp .env.example .env
# Edit .env with your values
# Run the example
node strategy-deposit.js
Expected Output
1️⃣ Fetching available strategies...
✅ Available strategies:
- Aave-USDC-polygon (Aave)
APY: 4.50%
- Morpho-BTC-base (Morpho)
APY: 3.20%
2️⃣ Getting details for Aave-USDC-polygon...
✅ Strategy details:
Strategy: Aave-USDC-polygon
Protocol: Aave
Network: polygon
Asset: USDC
APY: 4.50%
Status: ✅ Active
4️⃣ Generating deposit bytecode...
✅ Bytecode generated:
ID: 65f3a1c8e9b2d4f8a7c1d2e3
Transactions: 2
5️⃣ Executing deposit transactions...
Executing transaction 1/2...
Transaction sent: 0x123...
✅ Transaction confirmed in block 12345678
Executing transaction 2/2...
Transaction sent: 0x456...
✅ Transaction confirmed in block 12345679
6️⃣ Verifying deposit...
✅ Wallet positions:
Aave-USDC-polygon:
Balance: 1000.00 USDC
Value: $1000.00
APY: 4.17%
Total Portfolio Value: $1000.00
🎉 Strategy deposit completed successfully!
Next Steps
Strategy Withdrawal
Withdraw from strategies, including cross-chain withdrawals
Cross-Chain Swap
Execute cross-chain token swaps
Check Positions
Track wallet positions
API Reference
View complete API documentation