Skip to main content
Portal’s React Native SDK provides comprehensive yield opportunities capabilities through the portal.yield.yieldxyz API. This guide covers discovering yield opportunities, entering positions, managing existing positions, and exiting yield opportunities.

Overview

The yield functionality allows users to:
  • Discover available yield opportunities across different protocols and networks
  • Enter yield positions by depositing tokens into yield opportunities
  • Manage existing positions (claim rewards, voting, etc.)
  • Exit yield positions to withdraw aggregated tokens and rewards
  • Track yield balances and historical yield actions

Prerequisites

Before using yield operations, ensure you have:
  • A properly initialized Portal client
  • An active wallet with the required token(s) on the target network (see Create a wallet)
  • Yield.xyz integration enabled in your Portal Dashboard (see Yield.xyz Integration)

Discovering Yield Opportunities

Use the discover method to find available yield opportunities. For complete API documentation, see the Yield.xyz API reference.
import type { YieldXyzGetYieldsRequest } from '@portal-hq/core'

const request: YieldXyzGetYieldsRequest = {
  offset: 0,
  limit: 10,
  network: 'eip155:11155111',
  // Optional: type, token, provider, hasCooldownPeriod, hasWarmupPeriod, search, sort
}

const response = await portal.yield.yieldxyz.discover(request)
const yieldOpportunities = response.data?.rawResponse?.items
Popular, high-quality USDC yield options with no lockups or limits:
  • USDC Aave V3 Lending: base-usdc-aave-v3-lending
  • USDC Fluid Vault: base-usdc-fusdc-0xf42f5795d9ac7e9d757db633d693cd548cfd9169-4626-vault
  • USDC Spark Savings Vault: ethereum-usdc-spusdc-0x28b3a8fb53b741a8fd78c0fb9a6b2393d896a43d-4626-vault

Entering Yield Positions

To enter a yield position, first discover the specific yield, then use the enter method. For complete API documentation, see the Yield.xyz enter yield reference. For the example below, we will use the yield opportunity with the ID "ethereum-sepolia-link-aave-v3-lending". Fund your Portal client with the required LINK token to enter the position.
import type { YieldXyzEnterRequest } from '@portal-hq/core'

const userAddress = await portal.getAddress('eip155')

const enterRequest: YieldXyzEnterRequest = {
  yieldId: 'ethereum-sepolia-link-aave-v3-lending',
  address: userAddress,
  amount: '1',
  // Optional: arguments (validatorAddress, inputToken, etc.)
}

const enterResponse = await portal.yield.yieldxyz.enter(enterRequest)
const transactions = enterResponse.data?.rawResponse?.transactions

await processTransactions(transactions)

Checking Yield Balances

Retrieve current yield positions and balances. For complete API documentation, see the Yield.xyz get balances reference.
import type { YieldXyzGetBalancesRequest } from '@portal-hq/core'

const userAddress = await portal.getAddress('eip155')

const balanceRequest: YieldXyzGetBalancesRequest = {
  queries: [
    {
      address: userAddress,
      network: 'eip155:11155111',
      // Optional: yieldId
    },
  ],
}

const balanceResponse = await portal.yield.yieldxyz.getBalances(balanceRequest)
const yieldPositions = balanceResponse.data?.rawResponse?.items

yieldPositions?.forEach((position) => {
  position.balances.forEach((balance) => {
    // Check balance.pendingActions for available management actions
  })
})

Exiting Yield Positions

Use the exit method to withdraw from yield positions. For complete API documentation, see the Yield.xyz exit yield reference.
import type { YieldXyzExitRequest } from '@portal-hq/core'

const userAddress = await portal.getAddress('eip155')

const exitRequest: YieldXyzExitRequest = {
  yieldId: 'ethereum-sepolia-link-aave-v3-lending',
  address: userAddress,
  amount: '0.001',
  // Optional: arguments (validatorAddress, etc.)
}

const exitResponse = await portal.yield.yieldxyz.exit(exitRequest)
const transactions = exitResponse.data?.rawResponse?.transactions

await processTransactions(transactions)

Managing Yield Positions

If your Portal client has entered into a yield balance, they may have a yield balance that has an available pendingActions. You can use the manage method to perform actions on existing yield positions. For example, if the balance has a pendingAction of WITHDRAW or CLAIM_REWARDS, you can use the manage method to withdraw or claim rewards from the yield balance. For complete API documentation, see the Yield.xyz manage yield reference.
import type { YieldXyzManageYieldRequest, YieldXyzActionType } from '@portal-hq/core'

const userAddress = await portal.getAddress('eip155')

const balanceResponse = await portal.yield.yieldxyz.getBalances({
  queries: [{ address: userAddress, network: 'eip155:11155111' }],
})

const pendingAction = balanceResponse.data?.rawResponse?.items?.[0]?.balances?.[0]?.pendingActions?.[0]

if (pendingAction) {
  const manageRequest: YieldXyzManageYieldRequest = {
    yieldId: 'ethereum-sepolia-link-aave-v3-lending',
    address: userAddress,
    action: pendingAction.type as YieldXyzActionType,
    passthrough: pendingAction.passthrough,
    // Optional: arguments (amount, etc.)
  }

  const manageResponse = await portal.yield.yieldxyz.manage(manageRequest)
  const transactions = manageResponse.data?.rawResponse?.transactions

  await processTransactions(transactions)
}

Getting Historical Actions

Retrieve the history of yield actions for an address. For complete API documentation, see the Yield.xyz get actions reference.
import type { YieldXyzGetHistoricalActionsRequest } from '@portal-hq/core'

const userAddress = await portal.getAddress('eip155')

const request: YieldXyzGetHistoricalActionsRequest = {
  address: userAddress,
  // Optional: offset, limit, status, intent, type, yieldId
}

const response = await portal.yield.yieldxyz.getHistoricalActions(request)
const pastActions = response.data?.rawResponse?.items

Transaction Processing

Yield operations can require multiple transactions. Process them sequentially, submit each, track it, and wait for on-chain confirmation (e.g. using eth_getTransactionReceipt) before proceeding to the next. For complete API documentation, see the Yield.xyz submit transaction hash reference and get transaction details reference.
For account abstraction enabled Portal clients, use eth_getUserOperationReceipt instead of eth_getTransactionReceipt since signing returns a user operation hash, not a transaction hash.Extract the transaction hash from response.result.receipt.transactionHash and use that transaction hash when calling the portal.yield.yieldxyz.track() method.
import type { YieldXyzActionTransaction } from '@portal-hq/core'

async function processTransactions(
  transactions: YieldXyzActionTransaction[] | undefined
): Promise<void> {
  if (!transactions?.length) return

  const sorted = [...transactions].sort((a, b) => a.stepIndex - b.stepIndex)

  for (const tx of sorted) {
    if (tx.unsignedTransaction && tx.status === 'CREATED') {
      const success = await signAndSubmitAndConfirm(tx)
      if (!success) break
    }
  }
}

async function signAndSubmitAndConfirm(
  transaction: YieldXyzActionTransaction
): Promise<boolean> {
  const txParams =
    typeof transaction.unsignedTransaction === 'string'
      ? JSON.parse(transaction.unsignedTransaction)
      : transaction.unsignedTransaction

  const sendResult = await portal.request({
    chainId: transaction.network,
    method: 'eth_sendTransaction',
    params: [
      {
        from: txParams.from || '',
        to: txParams.to || '',
        value: txParams.value || '0x0',
        data: txParams.data || '0x',
      },
    ],
  })

  const txHash = sendResult.result as string
  if (!txHash) return false

  await portal.yield.yieldxyz.track(transaction.id, txHash)

  return await waitForReceipt(txHash, transaction.network)
}

async function waitForReceipt(
  txHash: string,
  chainId: string,
  maxAttempts: number = 30,
  delayMs: number = 2000
): Promise<boolean> {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    await new Promise((resolve) => setTimeout(resolve, delayMs))

    const receiptResponse = await portal.request({
      chainId,
      method: 'eth_getTransactionReceipt',
      params: [txHash],
    })

    const receipt = receiptResponse.result as Record<string, any> | null
    if (receipt?.status === '0x1') return true
    if (receipt?.status === '0x0') return false
  }

  return false
}

Getting Transaction Details

You can retrieve details about a specific transaction using the getTransaction method:
const transactionId = 'transaction-id-from-enter-or-exit-response'

const txResponse = await portal.yield.yieldxyz.getTransaction(transactionId)
const transaction = txResponse.data?.rawResponse

Best Practices

  1. Always check yield availability before attempting to enter positions
  2. Process transactions sequentially as yield operations often require multiple steps and are dependent on previous transactions being mined successfully
  3. Handle network errors gracefully and provide user feedback
  4. Monitor transaction status and provide progress updates to users
  5. Validate user balances before initiating yield operations
  6. Check for pending actions in balances before calling the manage method
  7. Test on testnets first (e.g., Sepolia) before moving to mainnet

Supported Networks

The yield functionality supports various networks including:
  • Monad (eip155:143)
  • Monad Testnet (eip155:10143)
  • Arbitrum (eip155:42161)
  • Avalanche C (eip155:43114)
  • Base (eip155:8453)
  • Base Sepolia (eip155:84532)
  • Celo (eip155:42220)
  • Core (eip155:1116)
  • Ethereum (eip155:1)
  • Ethereum Sepolia (eip155:11155111)
  • Fantom (eip155:250)
  • Gnosis (eip155:100)
  • Harmony (eip155:1666600000)
  • Hyperevm (eip155:999)
  • Katana (eip155:747474)
  • Linea (eip155:59144)
  • Moonriver (eip155:1285)
  • Optimism (eip155:10)
  • Optimism Sepolia (eip155:11155420)
  • Plasma (eip155:9745)
  • Polygon (eip155:137)
  • Polygon Amoy (eip155:80002)
  • Sonic (eip155:146)
  • Unichain (eip155:130)
  • Viction (eip155:88)
  • zkSync (eip155:324)
  • Solana (solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp)
  • Solana Devnet (solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1)
  • Stellar (stellar:pubnet)
  • Stellar Testnet (stellar:testnet)
  • Tron (tron:mainnet)

Next Steps