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 withdraw from a DeFi yield strategy using the Deframe API with JavaScript/TypeScript. It includes both same-chain withdrawal and cross-chain withdrawal, where withdrawn funds are bridged to a different destination chain.
Overview
This example covers:
- Checking existing strategy positions
- Generating withdrawal transaction bytecode
- Withdrawing to the same chain
- Withdrawing cross-chain with
toChainId and toTokenAddress
- Executing the returned transactions
- Tracking cross-chain completion by ID
Prerequisites
- Node.js 18+
- Deframe API key
- Wallet with an existing position in the selected strategy
- RPC URL for the strategy chain
- Basic understanding of async/await
Installation
Environment Variables
Create a .env file:
DEFRAME_API_KEY=your-api-key
WALLET_ADDRESS=0x...
PRIVATE_KEY=0x...
ARBITRUM_RPC_URL=https://arb-mainnet.g.alchemy.com/v2/your-key
BASE_RPC_URL=https://base-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. Check Current Positions
const walletAddress = process.env.WALLET_ADDRESS
const { data: walletData } = await deframe.get(`/wallets/${walletAddress}`)
console.log('Open 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}`)
})
3. Generate Same-Chain Withdrawal Bytecode
const { data: result } = await deframe.get('/strategies/aave-usdc-arbitrum/bytecode', {
params: {
action: 'withdraw',
amount: '1000000',
wallet: walletAddress
}
})
console.log('ID:', result.id)
console.log('Cross-chain:', result.crossChain.isCrossChain) // false
console.log('Transactions to execute:', result.bytecode.length)
4. Generate Cross-Chain Withdrawal Bytecode
To withdraw from the strategy chain and bridge the proceeds to another chain, pass toChainId or chainIdOut plus toTokenAddress.
const { data: result } = await deframe.get('/strategies/aave-usdc-arbitrum/bytecode', {
params: {
action: 'withdraw',
amount: '1000000',
wallet: walletAddress,
toChainId: 8453,
toTokenAddress: '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)
console.log('Expected out:', result.quote.outputAmount.humanized, result.quote.outputAmount.symbol)
console.log('Minimum out:', result.quote.minimumOutputAmount.humanized, result.quote.minimumOutputAmount.symbol)
The amount is the amount to withdraw from the source strategy. For cross-chain withdrawals, Deframe returns origin-chain transaction bytecode and a quote describing the destination-chain output.
5. Execute Transactions
Run the returned transactions on the source chain. For the cross-chain example above, that is Arbitrum.
import { ethers } from 'ethers'
const provider = new ethers.JsonRpcProvider(process.env.ARBITRUM_RPC_URL)
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider)
const txHashes = []
for (const txData of result.bytecode) {
const tx = await wallet.sendTransaction({
to: txData.to,
data: txData.data,
value: txData.value || '0',
chainId: txData.chainId
})
console.log('Transaction sent:', tx.hash)
txHashes.push(tx.hash)
const receipt = await tx.wait()
console.log('Confirmed in block:', receipt.blockNumber)
}
6. Track Cross-Chain Withdrawal Status
Cross-chain withdrawals complete asynchronously after the origin-chain transactions are confirmed. Use the returned id to track completion.
const id = result.id
async function waitForWithdrawal (id) {
const terminalStatuses = ['SUCCESS', 'FAILED', 'REFUNDED', 'EXPIRED']
while (true) {
const { data: statusRecord } = await deframe.get(`/actions/${id}`)
console.log(`Status: ${statusRecord.status} (${statusRecord.transactions.length} tx)`)
if (terminalStatuses.includes(statusRecord.status)) return statusRecord
await new Promise(resolve => setTimeout(resolve, 5000))
}
}
const finalStatus = await waitForWithdrawal(id)
console.log('Final status:', finalStatus.status)
Same-chain withdrawals do not require polling because the withdrawal completes inline with the user’s signed transaction. You can still call GET /actions/:id with the returned id for record-keeping.
Running the Example
# Install dependencies
npm install
# Set environment variables
cp .env.example .env
# Edit .env with your values
# Run the example
node strategy-withdraw.js
Expected Output
1. Checking wallet positions...
Open positions:
aave-usdc-arbitrum: 25.00 USDC
2. Generating cross-chain withdrawal bytecode...
ID: 65f3a1c8e9b2d4f8a7c1d2e3
Bridge: CCTP
Source chain: 42161
Destination chain: 8453
Transactions: 1
3. Executing withdrawal transactions...
Transaction sent: 0x123...
Confirmed in block: 12345678
4. Tracking cross-chain withdrawal...
Status: PENDING (1 tx)
Status: SUCCESS (2 tx)
Final status: SUCCESS
Next Steps
Strategy Deposit
Deposit into yield strategies
Yield Withdrawal Guide
Review all withdrawal parameters and response shapes
Cross-Chain Swap
Execute cross-chain token swaps
API Reference
View complete API documentation