> ## Documentation Index
> Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Earn with Yield.xyz

> Learn how to discover, enter, manage, and exit yield opportunities using the Enclave MPC API.

Portal's Enclave MPC API provides comprehensive yield opportunities capabilities through the Yield.xyz integration. This guide covers discovering yield opportunities, entering positions, managing existing positions, and exiting yield opportunities.

## Overview

The yield functionality allows you to:

* **Get defaults** — Portal's curated list of recommended yield opportunities per chain and token, enriched with live data
* **Discover** available yield opportunities across different protocols and networks
* **Get validators** — fetch available validators for staking yields that require validator selection
* **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 (see [Create a client](./create-a-client))
* An active wallet with the required token(s) on the target network (see [Create a wallet](./create-a-wallet))
* Yield.xyz integration enabled in your Portal Dashboard (see [Yield.xyz Integration](../../../resources/integrations/yield-xyz))

## Default Yield Opportunities

Portal maintains a curated list of recommended yield opportunities for each supported chain and token. Use the `GET /api/v3/clients/me/integrations/yield-xyz/yields/defaults` endpoint to retrieve these defaults. By default, the response is lightweight — just yield IDs. Pass `includeOpportunities=true` to enrich with live data (APY, TVL, status, etc.) from Yield.xyz.

For complete API documentation, see the [Client API reference](../../client/reference#get-default-yield-opportunities).

```bash theme={null}
# Get all default yield IDs (lightweight)
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/defaults' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

# Include full opportunity details
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/defaults?includeOpportunities=true' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

You can filter by chain and/or token:

```bash theme={null}
# Filter by chain (Ethereum mainnet)
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/defaults?chainId=eip155:1' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

# Filter by token
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/defaults?token=USDC' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'

# Filter + enrich
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/defaults?chainId=eip155:1&token=ETH&includeOpportunities=true' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

The response `data` is an object keyed by `{caip2ChainId}:{tokenSymbol}`, so you can look up entries directly:

```typescript theme={null}
const defaults = response.data

// Direct lookup — no iteration needed
const ethYield = defaults['eip155:1:ETH']
console.log(ethYield.yieldId) // "ethereum-weth-gtweth-..."

// With includeOpportunities=true, opportunity contains live data
console.log(ethYield.opportunity?.rewardRate?.total) // e.g. 0.0267
```

Each entry contains:

* `yieldId` — the recommended Yield.xyz yield ID, or `null` if no recommendation exists
* `opportunity` — full yield opportunity details when `includeOpportunities=true` is passed, otherwise `null`

<Note>
  When using `includeOpportunities=true`, check `opportunity.status.enter` and `opportunity.status.exit` before initiating deposits or withdrawals — if either is `false`, the opportunity is temporarily unavailable.
</Note>

## Discovering Yield Opportunities

Use the `GET /api/v3/clients/me/integrations/yield-xyz/yields` endpoint to find available yield opportunities.

For complete API documentation, see the [Client API reference](../../client/reference#get-yield-opportunities).

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields?limit=10' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

<Tip>
  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`
</Tip>

## Getting Validators

Some yield opportunities (e.g. native staking) require selecting a validator. You can check this by looking at `mechanics.requiresValidatorSelection` in the yield opportunity response. Use the `GET /api/v3/clients/me/integrations/yield-xyz/yields/{yieldId}/validators` endpoint to fetch available validators.

For complete API documentation, see the [Client API reference](../../client/reference#get-yield-validators).

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/monad-testnet-mon-native-staking/validators?limit=10' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

You can filter validators by name, address, provider, status, or preferred flag:

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/monad-testnet-mon-native-staking/validators?preferred=true&status=active' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

<Note>
  When entering a yield that requires validator selection, pass the chosen validator's `address` as the `validatorAddress` argument in the enter action request body.
</Note>

## Entering Yield Positions

To enter a yield position, first discover the specific yield, then use the `POST /api/v3/clients/me/integrations/yield-xyz/actions/enter` endpoint to create the action and get transactions. You'll then sign and submit these transactions using the Enclave MPC API.

For complete API documentation, see the [Client API reference](../../client/reference#enter-yield-position).

For the example below, we will use the yield opportunity with the ID `"ethereum-sepolia-link-aave-v3-lending"`. You'll need both Sepolia `ETH` (for gas) and the Aave V3 Sepolia [`LINK` token](https://sepolia.etherscan.io/token/0xf8Fb3713D459D7C1018BD0A49D19b4C44290EBE5) (to deposit into the position) on your Portal client.

### Step 1: Fund Your Client (Sepolia testnet only)

On testnets, you can fund your Portal client directly via the `POST /api/v3/clients/me/fund` endpoint. Request `ETH` for gas and `LINK` for the Aave V3 deposit:

```bash theme={null}
# Fund with Sepolia ETH (for gas)
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/fund \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "chainId": "eip155:11155111",
  "token": "ETH",
  "amount": "0.01"
}'

# Fund with Sepolia LINK (the Aave V3 mock LINK accepted by the lending pool)
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/fund \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "chainId": "eip155:11155111",
  "token": "LINK",
  "amount": "1"
}'
```

### Step 2: Create the Enter Action

```bash theme={null}
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/actions/enter \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "address": "0xYourAddress",
  "arguments": {
    "amount": "1"
  },
  "yieldId": "ethereum-sepolia-link-aave-v3-lending"
}'
```

<Note>
  Take note of the `transactionId` and `unsignedTransaction` fields in the response's `data.rawResponse.transactions` array items. You will need to use these to track the transaction.
</Note>

### Step 3: Process and Sign Transactions

The response will include an array of transactions. Process them sequentially, sign each using the Enclave MPC API, track it, and wait for on-chain confirmation before proceeding to the next.

```bash theme={null}
# Example: Signing the first transaction from the enter action response
curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": { "from":"0xFromAddress", "to":"0xToAddress", "data":"0xData" },
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/11155111",
  "chainId": "eip155:11155111"
}'
```

### Step 4: Track Transaction

After signing and broadcasting, submit the transaction hash to Yield.xyz:

```bash theme={null}
curl --request PUT \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/transactions/[transactionId]/submit-hash \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "hash": "[transactionHash]"
}'
```

<Note>Learn more about processing these transactions sequentially in the [section below](#transaction-processing).</Note>

## Checking Yield Balances

Retrieve current yield positions and balances using the `POST /api/v3/clients/me/integrations/yield-xyz/yields/balances` endpoint.

For complete API documentation, see the [Client API reference](../../client/reference#get-yield-balances).

```bash theme={null}
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/balances \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "queries": [
    {
      "address": "0xYourAddress",
      "network": "eip155:11155111"
    }
  ]
}'
```

<Note>
  We recommend always specifying a `yieldId` on each balance query. When `yieldId` is provided, Yield.xyz can resolve balances directly, so you don't need to call the `track` endpoint after entering or exiting positions.

  ```json theme={null}
  {
    "queries": [
      {
        "address": "0xYourAddress",
        "network": "eip155:11155111",
        "yieldId": "ethereum-sepolia-link-aave-v3-lending"
      }
    ]
  }
  ```
</Note>

## Exiting Yield Positions

Use the `POST /api/v3/clients/me/integrations/yield-xyz/actions/exit` endpoint to create an exit action, then sign and submit the resulting transactions.

For complete API documentation, see the [Client API reference](../../client/reference#exit-yield-position).

```bash theme={null}
# Step 1: Create exit action
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/actions/exit \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "yieldId": "ethereum-sepolia-link-aave-v3-lending",
  "address": "0xYourAddress",
  "arguments": {
    "amount": "0.001"
  }
}'

# Step 2: Sign and submit transactions (same process as entering)
# Process each transaction from the response sequentially using the Enclave MPC API sign endpoint
```

## Managing Yield Positions

If your Portal client has entered into a yield balance, they may have a yield balance with available `pendingActions`. You can use the `POST /api/v3/clients/me/integrations/yield-xyz/actions/manage` endpoint 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 [Client API reference](../../client/reference#manage-yield-position).

```bash theme={null}
# First, get the balance to find pendingActions
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/yields/balances \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "queries": [
    {
      "address": "0xYourAddress",
      "network": "eip155:11155111"
    }
  ]
}'
```

```json theme={null}
// Example response:
{
  "data": {
    "rawResponse": {
      "items": [
        {
          "yieldId": "ethereum-sepolia-link-aave-v3-lending",
          "balances": [
            {
              "address": "0xYourAddress",
              "amount": "0.001000027202065699",
              "amountRaw": "1000027202065699",
              "type": "active",
              "token": {
                "address": "0x3FfAf50D4F4E96eB78f2407c090b72e86eCaed24",
                "symbol": "aEthLINK",
                "name": "Aave Ethereum LINK",
                "decimals": 18,
                "logoURI": "https://assets.stakek.it/tokens/alink.svg",
                "network": "eip155:11155111",
                "isPoints": false
              },
              "pendingActions": [
                {
                  "intent": "manage",
                  "type": "WITHDRAW",
                  // 👇 This is the "passthrough" value from the balance's pendingAction item that we will use to create the manage action.
                  "passthrough": "eyJhZGRyZXNzZXMiOnsiYWRkcmVzcyI6IjB4ZD...",
                  "arguments": null
                }
              ],
              "amountUsd": "0.000000",
              "isEarning": true
            }
          ]
        }
      ],
      "errors": []
    }
  }
}
```

```bash theme={null}
# Then create the manage action using the pendingAction's type and passthrough
curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/actions/manage \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "action": "WITHDRAW",
  "address": "0xYourAddress",
  "passthrough": "eyJhZGRyZXNzZXMiOnsiYWRkcmVzcyI6IjB4ZD...",
  "yieldId": "ethereum-sepolia-link-aave-v3-lending"
}'

# Finally, sign and submit transactions (same process as entering/exiting)
```

## Getting Historical Actions

Retrieve the history of yield actions for an address using the `GET /api/v3/clients/me/integrations/yield-xyz/actions` endpoint.

For complete API documentation, see the [Client API reference](../../client/reference#get-historical-actions).

```bash theme={null}
curl --request GET \
  --url 'https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/actions?address=0xYourAddress' \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]'
```

## Transaction Processing

Yield operations can require multiple transactions. Process them sequentially, sign each using the Enclave MPC API, track it, and wait for on-chain confirmation (e.g. using `eth_getTransactionReceipt`) before proceeding to the next.

For complete API documentation, see the [Client API reference](../../client/reference#submit-transaction-hash) and [get transaction details reference](../../client/reference#get-transaction-details).

<Tip>
  For account abstraction enabled Portal clients, use `eth_getUserOperationReceipt` instead of `eth_getTransactionReceipt` to wait for confirmation, since signing returns a *user operation hash*, not a transaction hash.

  If you don't specify a `yieldId` on your balance queries, you'll need to call the `PUT /api/v3/clients/me/integrations/yield-xyz/transactions/[transactionId]/submit-hash` endpoint after each transaction so Yield.xyz can attribute the position. Pass the **transaction hash** (extracted from `response.result.receipt.transactionHash` for AA clients), not the user operation hash.
</Tip>

### Example Transaction Processing Flow

Here's a complete example of processing transactions from an enter action:

```bash theme={null}
# 1. Create the enter action and get transactions
ENTER_RESPONSE=$(curl --request POST \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/actions/enter \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "address": "0xYourAddress",
  "arguments": {
    "amount": "1"
  },
  "yieldId": "ethereum-sepolia-link-aave-v3-lending"
}')

# Extract transactions from response (parse JSON)
# Sort by stepIndex and process in order

# 2. For each transaction with status "CREATED" and an unsignedTransaction:
#    a. Parse the unsignedTransaction JSON
#    b. Sign and submit using Enclave MPC API

curl --request POST \
  --url https://mpc-client.portalhq.io/v1/sign \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "share": "[share]",
  "method": "eth_sendTransaction",
  "params": { "from":"0xFromAddress", "to":"0xToAddress", "data":"0xData" },
  "rpcUrl": "https://api.portalhq.io/rpc/v1/eip155/11155111",
  "chainId": "eip155:11155111"
}'

# 3. Extract transaction hash from response and track it
curl --request PUT \
  --url https://api.portalhq.io/api/v3/clients/me/integrations/yield-xyz/transactions/[transactionId]/submit-hash \
  --header 'Authorization: Bearer [clientApiKey|clientSessionToken]' \
  --header 'Content-Type: application/json' \
  --data '{
  "hash": "0x..."
}'

# 4. Wait for transaction confirmation
#    Poll eth_getTransactionReceipt using a RPC request. Below we use Alchemy's RPC endpoint for Sepolia as an example.
curl --request POST \
  --url https://eth-sepolia.g.alchemy.com/v2/[alchemyApiKey] \
  --header 'Content-Type: application/json' \
  --data '{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "eth_getTransactionReceipt",
  "params": [
    "0xTransactionHash"
  ]
}'

# 5. Repeat steps 2-4 for each subsequent transaction
```

<Note>
  The `unsignedTransaction` field in the Yield.xyz response is a JSON string. Parse it and extract the transaction parameters before passing to the Enclave MPC API sign endpoint. Remove the gas parameters if you want Portal to estimate the gas for you.
</Note>

## 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. **Track all transactions** using the Yield.xyz submit-hash endpoint to maintain accurate state

## 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

* Learn about [signing Ethereum transactions](./sign-ethereum-transactions)
* Explore [sending tokens](./send-tokens)
* Check out the [Client API Yield.xyz endpoints](../../client/reference#yield-xyz-integration)
