Skip to main content
Deframe allows apps to access diversified DeFi yield strategies across multiple protocols through a single API. Apps fetch strategies from Deframe and execute the returned transaction bytecodes using Privy wallets. This enables deposits into lending, staking, and protocol-native yield strategies without managing complex transaction flows.

Resources


Using Deframe with Privy

For this walkthrough, the examples use the Aave USDT strategy on Polygon. The same patterns work across all Deframe-supported strategies and networks—explore the complete list via the Deframe API.

Setup

Below is a minimal setup for the Privy provider. To customize the provider, follow the Privy Quickstart.
import {PrivyProvider} from '@privy-io/react-auth';

export function App() {
  return (
    <PrivyProvider appId="your-privy-app-id">{/* Your application components */}</PrivyProvider>
  );
}

Configure Deframe API access

Obtain your API credentials from the Deframe Dashboard:
const DEFRAME_API_URL = 'https://api.deframe.io';
const DEFRAME_API_KEY = 'your-deframe-api-key';

List available strategies

Fetch the yield strategies available for users:
const fetchStrategies = async () => {
  const response = await fetch(`${DEFRAME_API_URL}/strategies?limit=100`, {
    method: 'GET',
    headers: {
      'x-api-key': DEFRAME_API_KEY
    }
  });

  const {data: strategies} = await response.json();
  return strategies;
};
Each strategy includes fields like id, protocol, assetName, network, and availableActions.

Deposit into a yield strategy

1

1. Get the user's wallet address

import {useWallets} from '@privy-io/react-auth';

const {wallets} = useWallets();
const walletAddress = wallets[0]?.address;
2

2. Generate transaction bytecodes from Deframe

Request the bytecodes needed to execute a deposit action:
const strategyId = 'Aave-USDT-polygon';
const action = 'lend';
const amount = '1500000'; // 1.5 USDT (6 decimals)

const response = await fetch(
  `${DEFRAME_API_URL}/strategies/${strategyId}/bytecode?action=${action}&wallet=${walletAddress}&amount=${amount}`,
  {
    method: 'GET',
    headers: {
      'x-api-key': DEFRAME_API_KEY
    }
  }
);

const bytecodeResponse = await response.json();
The response contains an array of transactions to execute:
type DeframeBytecodeResponse = {
  feeCharged: string;
  metadata: {
    isCrossChain: boolean;
    isSameChainSwap: boolean;
    crossChainQuoteId: string;
  };
  bytecode: {
    to: string;
    value: string;
    data: string;
    chainId: string;
  }[];
};
3

3. Execute the transactions with Privy

Use Privy’s useSendTransaction to execute each bytecode:
import {useSendTransaction} from '@privy-io/react-auth';

const {sendTransaction} = useSendTransaction();

const executeDeframeStrategy = async (bytecodeResponse: DeframeBytecodeResponse) => {
  for (const tx of bytecodeResponse.bytecode) {
    await sendTransaction({
      to: tx.to as `0x${string}`,
      data: tx.data as `0x${string}`,
      value: BigInt(tx.value),
      chainId: Number(tx.chainId)
    });
  }
};

Check strategy position

Fetch the user’s current position and APY for a strategy:
const fetchPosition = async (strategyId: string, walletAddress: string) => {
  const response = await fetch(
    `${DEFRAME_API_URL}/strategies/${strategyId}?wallet=${walletAddress}`,
    {
      method: 'GET',
      headers: {
        'x-api-key': DEFRAME_API_KEY
      }
    }
  );

  const strategy = await response.json();
  return {
    apy: strategy.apy,
    avgApy: strategy.avgApy,
    position: strategy.position
  };
};

Withdraw from a strategy

To withdraw, use the withdraw action and execute the returned bytecodes:
import {useSendTransaction} from '@privy-io/react-auth';

const {sendTransaction} = useSendTransaction();

const withdrawFromStrategy = async (strategyId: string, walletAddress: string, amount: string) => {
  const response = await fetch(
    `${DEFRAME_API_URL}/strategies/${strategyId}/bytecode?action=withdraw&wallet=${walletAddress}&amount=${amount}`,
    {
      method: 'GET',
      headers: {
        'x-api-key': DEFRAME_API_KEY
      }
    }
  );

  const bytecodeResponse = await response.json();

  for (const tx of bytecodeResponse.bytecode) {
    await sendTransaction({
      to: tx.to as `0x${string}`,
      data: tx.data as `0x${string}`,
      value: BigInt(tx.value),
      chainId: Number(tx.chainId)
    });
  }
};

Deframe EarnWidget

For a faster integration, Deframe provides a pre-built EarnWidget component that handles strategy selection, deposits, and withdrawals with a built-in UI.

Install the Deframe SDK

npm install deframe-sdk @deframe-sdk/components @reduxjs/toolkit react-redux redux permissionless
If your app uses Vite, install the Node polyfills plugin and add it to vite.config.ts:
npm install --save-dev vite-plugin-node-polyfills
import {defineConfig} from 'vite';
import {nodePolyfills} from 'vite-plugin-node-polyfills';

export default defineConfig({
  plugins: [nodePolyfills()]
});

Configure the widget

import {DeframeProvider, EarnWidget} from 'deframe-sdk';
import {useSmartWallets} from '@privy-io/react-auth/smart-wallets';
import {usePrivy} from '@privy-io/react-auth';

const {user} = usePrivy();
const {client: smartWalletClient, getClientForChain} = useSmartWallets();

const config = {
  DEFRAME_API_URL: 'https://api.deframe.io',
  DEFRAME_API_KEY: 'your-deframe-api-key',
  walletAddress: smartWalletClient?.account.address,
  userId: user?.id,
  globalCurrency: 'USD',
  globalCurrencyExchangeRate: 1,
  theme: {mode: 'dark', preset: 'default'}
};

Implement the bytecode processor

The widget returns bytecode for the app to execute using Privy smart wallets:
import type {BytecodeTransaction, UpdateTxStatus} from 'deframe-sdk';

const processBytecode = async (
  payload: {clientTxId: string; bytecodes: BytecodeTransaction[]; simulateError?: boolean},
  ctx: {updateTxStatus: UpdateTxStatus}
) => {
  ctx.updateTxStatus({type: 'HOST_ACK', clientTxId: payload.clientTxId});

  const chainId = Number(payload.bytecodes[0].chainId);
  const chainClient = await getClientForChain({id: chainId});

  const calls = payload.bytecodes.map((b) => ({
    to: b.to as `0x${string}`,
    data: b.data as `0x${string}`,
    value: BigInt(b.value)
  }));

  ctx.updateTxStatus({type: 'SIGNATURE_PROMPTED', clientTxId: payload.clientTxId});
  const txHash = await chainClient.sendTransaction({calls});
  ctx.updateTxStatus({type: 'TX_SUBMITTED', clientTxId: payload.clientTxId, txHash});
};

Render the widget

<DeframeProvider config={config} processBytecode={processBytecode}>
  <EarnWidget autoHeight />
</DeframeProvider>
The EarnWidget requires Smart Wallets for transaction execution. Enable Smart Wallets in the Privy Dashboard under Wallet infrastructure.

Key integration tips

  1. Handle token decimals: The amount parameter must respect the token’s decimal places. USDT and USDC use 6 decimals; most other tokens use 18.
  2. Execute transactions in order: Deframe may return multiple bytecodes for a single action. Execute them sequentially.
  3. Verify available actions: Each strategy has an availableActions array. Check that the action exists before requesting bytecodes.
  4. Handle errors gracefully: Wrap transaction execution in try/catch blocks to handle user rejection, insufficient funds, and network issues.
For advanced use cases, refer to the Deframe Docs, or reach out in Slack.