Skip to main content

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

npm install axios ethers

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