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

# Enso Earn

> Enso Earn is the Yield-as-a-Service layer for wallets, fintechs, custodians, and apps. Launch a curated Earn product with discovery, cross-chain execution, position tracking, and monetization controls.

export const date_0 = "2026-06-08"

# Ship a yield product in weeks, not quarters.

Enso Earn is the Yield-as-a-Service layer for wallets, fintechs, custodians, and apps. Production-grade integrations to the venues your risk team already trusts — Aave, Morpho, Maple, Pendle, Ondo, EtherFi — reachable from any chain your users already hold capital on. One integration. No five-vendor stitch-up.

**Who it's for:** wallets turning idle balances into positions, fintechs and neobanks launching stablecoin yield, custodians serving institutional clients, and asset managers distributing strategies — teams that want to own the customer relationship while outsourcing the protocol integration burden.

<CardGroup cols={3}>
  <Card title="Curated coverage" icon="circle-check">
    Yield from the protocols you'd actually approve — lending, vaults, RWAs, structured yield, and liquid staking that already pass institutional risk and policy review. Not a long tail of unaudited markets.
  </Card>

  <Card title="Cross-chain by default" icon="arrows-left-right">
    Reach yield wherever the user already holds capital. A user holding USDC on Base can enter a vault on Ethereum in a single signature — the chain becomes an implementation detail, not a dead end.
  </Card>

  <Card title="Partner-controlled monetization" icon="coins">
    Earn opens a partner-owned revenue line. Layer your fee model on top of execution so your economics sit alongside the deposit, in the same flow your team controls.
  </Card>
</CardGroup>

## Why Now

**Regulation forces yield out of the core product.** The GENIUS Act and MiCA prevent fintechs and neobanks from paying yield natively on stablecoins. Yield has to ship as a distinct, DeFi-routed product surface — and the teams winning the next cycle are buying the rails, not building them. Custody, execution, security, sourcing, audits, and reporting make up a stack that is too deep to assemble vendor-by-vendor before competitors ship.

Enso Earn is execution infrastructure, not a parallel compliance stack. KYC, eligibility, region rules, signing policy, and approval workflow stay inside the systems your risk team already operates — Enso plugs into them rather than asking you to migrate.

***

Enso Earn is the pattern for adding yield inside your application. A first Earn product does not need the full Enso API surface. It needs a curated list of yield destinations, the user's current balances, a route into the selected position, your fee on top of the deposit, and a refreshed balance view after the transaction lands. Execution safety is built in — every route is simulated and protected by Enso before it is returned.

Use this guide when you want to build an Earn tab, yield marketplace, wallet yield flow, or simple position migrator.

## Core Endpoints

The Earn path is built from these endpoints:

| Step | Endpoint                                                                                       | Use it for                                                                                                                                                                                |
| ---- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1    | [`GET /v1/tokens`](/api-reference/tokens/tokens)                                               | Build the approved yield catalog. This is where APY, TVL, protocol, underlying assets, decimals, symbols, names, and logos come from.                                                     |
| 2    | [`GET /v1/wallet/balances`](/api-reference/defi/wallet-balances)                               | Show the user's current assets and current DeFi positions before and after execution.                                                                                                     |
| 3    | [`POST /v1/shortcuts/route`](/api-reference/defi-shortcuts/optimal-route-between-two-tokens-1) | Quote and build the signer-ready transaction from the user's input asset or current position into the selected Earn destination. Pass `fee` + `feeReceiver` here to monetize the deposit. |
| 4    | [`GET /v1/wallet/approve`](/api-reference/defi-shortcuts/approve-enso-contract)                | Required only when the user is spending an ERC-20 through `routingStrategy: "router"` and allowance is not already high enough.                                                           |

Every route Enso returns is already simulated and protected under the hood, so there is no separate safety call to add to this flow. [Enso Quoter](/pages/quoter/overview) is available as a standalone API when you want to independently simulate or validate transactions generated *outside* Enso (for example, a payload from another aggregator before you sign it).

<Note>
  APY is not a separate endpoint. Read it from `GET /v1/tokens`.
  New balances are not returned by the route endpoint. After the transaction confirms,
  call `GET /v1/wallet/balances` again.
</Note>

## Build Flow

```mermaid theme={null}
flowchart LR
    A["Fetch approved yield positions"] --> B["Fetch user balances"]
    B --> C["User selects source asset"]
    A --> D["User selects Earn destination"]
    C --> E["Quote route + fee (auto-simulated)"]
    D --> E
    E --> F["Approve if needed"]
    F --> G["User signs route tx"]
    G --> H["Refetch balances"]
```

## End-To-End Example

This is the full Earn loop in one place: build the catalog, read the user's balances, route into the selected destination with your fee applied, approve if needed, submit the returned transaction, and refresh balances. The route is simulated and protected by Enso before it is returned — no extra safety call is required.

```typescript theme={null}
import { EnsoClient } from "@ensofinance/sdk";

const enso = new EnsoClient({ apiKey: process.env.ENSO_API_KEY });

const chainId = 8453;
const user = "0xd8da6bf26964af9d7eed9e03e53415d37aa96045";
const sourceToken = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; // USDC on Base
const earnDestination = "0x4e65fe4dba92790696d040ac24aa414708f5c0ab"; // Aave Base USDC
const amountIn = "100000000"; // 100 USDC
const feeReceiver = "0x220866B1A2219f40e72f5c628B65D54268cA3A9D"; // your revenue address

const catalog = await enso.getTokenData({
  chainId,
  type: "defi",
  includeMetadata: true,
  includeUnderlying: true,
  tvlFrom: 1_000_000,
});

const startingBalances = await enso.getBalances({
  chainId,
  eoaAddress: user,
  useEoa: true,
});

const route = await enso.getRouteData({
  chainId,
  fromAddress: user,
  receiver: user,
  spender: user,
  routingStrategy: "router",
  tokenIn: [sourceToken],
  tokenOut: [earnDestination],
  amountIn: [amountIn],
  slippage: "50",
  fee: ["20"], // 0.20% partner fee, in basis points
  feeReceiver, // required when fee is set
  referralCode: "EARN_BASE_USDC", // attribution for on-chain tracking
});

// Replace this with your allowance check. Native gas tokens do not need approval.
if (await needsApproval({ chainId, owner: user, token: sourceToken, amount: amountIn })) {
  const approval = await enso.getApprovalData({
    chainId,
    fromAddress: user,
    routingStrategy: "router",
    tokenAddress: sourceToken,
    amount: amountIn,
  });

  await wallet.sendTransaction(approval.tx);
}

await wallet.sendTransaction(route.tx);

const updatedBalances = await enso.getBalances({
  chainId,
  eoaAddress: user,
  useEoa: true,
});

const destinationMetadata = catalog.data.find((token) => token.address === earnDestination);
```

Use the first balance snapshot for the review screen and the second balance snapshot for the completed state.

## UI Fields

| UI moment           | Show this                                                                                                           | Source                                                              |
| ------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Catalog             | APY, base APY, reward APY, TVL, protocol, chain, underlying assets, token symbol, decimals, logo                    | `GET /v1/tokens`                                                    |
| User starting point | Spendable source assets and existing DeFi positions                                                                 | `GET /v1/wallet/balances`                                           |
| Route review        | Expected output, minimum output, estimated gas, price impact, selected route, your fee amount, approval requirement | `POST /v1/shortcuts/route` and conditional `GET /v1/wallet/approve` |
| Signing             | The returned approval `tx` if needed, then the returned route `tx` (already simulated by Enso)                      | Approval and route responses                                        |
| Completed state     | New Earn position, remaining source balance, APY, TVL, protocol, underlying assets, logo                            | Refreshed `GET /v1/wallet/balances` plus `GET /v1/tokens`           |

## 1. Build The Yield Catalog

Use `GET /v1/tokens` to fetch the positions your product is allowed to show.

For a normal Earn shelf, filter by chain, token type, APY, TVL, approved protocol, and underlying asset:

<CodeGroup>
  ```typescript TypeScript SDK theme={null}
  import { EnsoClient } from "@ensofinance/sdk";

  const enso = new EnsoClient({ apiKey: process.env.ENSO_API_KEY });

  const catalog = await enso.getTokenData({
    chainId: 1,
    type: "defi",
    protocolSlug: "yearn-v2",
    apyFrom: 3,
    tvlFrom: 1_000_000,
    includeMetadata: true,
    includeUnderlying: true,
  });

  const approvedDestinations = catalog.data.filter((position) => {
    return position.apy && position.tvl && position.symbol;
  });
  ```

  ```bash cURL theme={null}
  curl -X GET \
    -H "Authorization: Bearer $ENSO_API_KEY" \
    "https://api.enso.build/api/v1/tokens?chainId=1&type=defi&protocolSlug=yearn-v2&apyFrom=3&tvlFrom=1000000&includeMetadata=true&includeUnderlying=true" \
    | jq
  ```
</CodeGroup>

Filtering by `protocolSlug`, `apyFrom`, and `tvlFrom` is how you curate: ship only the destinations your risk and policy review already approved, rather than the full long tail. APY is point-in-time as of the response — surface it as a current rate, not a guarantee, and refetch on display.

For a yield migrator, start from the source position's exact underlying assets and show comparable destinations:

```typescript theme={null}
const targets = await enso.getTokenData({
  chainId: sourcePosition.chainId,
  type: "defi",
  underlyingTokensExact: sourcePosition.underlyingTokens.map((token) => token.address),
  includeMetadata: true,
  includeUnderlying: true,
});

const alternatives = targets.data
  .filter((position) => position.address !== sourcePosition.address && position.apy)
  .sort((a, b) => b.apy - a.apy);
```

Show these fields in the catalog:

* `name`, `symbol`, `logosUri`, `decimals`
* `project`, `protocolSlug`, `chainId`
* `underlyingTokens`
* `apy`, `apyBase`, `apyReward`
* `tvl`
* `address`

## 2. Show User Balances And Current Positions

Use `GET /v1/wallet/balances` for the user's starting point.

<CodeGroup>
  ```typescript TypeScript SDK theme={null}
  const balances = await enso.getBalances({
    chainId: 1,
    eoaAddress: user,
    useEoa: true,
  });
  ```

  ```bash cURL theme={null}
  curl -X GET \
    -H "Authorization: Bearer $ENSO_API_KEY" \
    "https://api.enso.build/api/v1/wallet/balances?chainId=1&eoaAddress=0xd8da6bf26964af9d7eed9e03e53415d37aa96045&useEoa=true" \
    | jq
  ```
</CodeGroup>

The balance response includes token address, amount, decimals, price, name, symbol, and logo. Use it to show deposit sources and existing positions.

To turn balances into current yield positions, look those balance token addresses up with `GET /v1/tokens` and `type=defi`:

```typescript theme={null}
const balanceTokenAddresses = balances
  .filter((balance) => Number(balance.price) > 0)
  .map((balance) => balance.token);

const positionTokens = await enso.getTokenData({
  chainId: 1,
  address: balanceTokenAddresses,
  type: "defi",
  includeMetadata: true,
  includeUnderlying: true,
});

const currentPositions = balances
  .map((balance) => ({
    balance,
    token: positionTokens.data.find((token) => token.address === balance.token),
  }))
  .filter((position) => position.token);
```

## 3. Quote The Earn Route

Use `POST /v1/shortcuts/route` when the user chooses a source asset and one final Earn destination. Route handles swaps, wraps, deposits, redeems, and position migrations underneath.

<CodeGroup>
  ```typescript TypeScript SDK theme={null}
  const route = await enso.getRouteData({
    chainId: 8453,
    fromAddress: user,
    receiver: user,
    spender: user,
    routingStrategy: "router",
    tokenIn: ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"], // USDC on Base
    tokenOut: ["0x4e65fe4dba92790696d040ac24aa414708f5c0ab"], // Aave Base USDC
    amountIn: ["100000000"], // 100 USDC
    slippage: "50",
  });
  ```

  ```bash cURL theme={null}
  curl -X POST \
    -H "Authorization: Bearer $ENSO_API_KEY" \
    -H "Content-Type: application/json" \
    "https://api.enso.build/api/v1/shortcuts/route" \
    --data '{
      "chainId": 8453,
      "fromAddress": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
      "receiver": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
      "spender": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
      "routingStrategy": "router",
      "tokenIn": ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"],
      "tokenOut": ["0x4e65fe4dba92790696d040ac24aa414708f5c0ab"],
      "amountIn": ["100000000"],
      "slippage": "50"
    }' | jq
  ```
</CodeGroup>

Show these route response fields on the review screen:

* `amountOut`: expected destination position amount.
* `minAmountOut`: the slippage-protected minimum output.
* `gas`: estimated gas.
* `priceImpact`: estimated price impact.
* `feeAmount`: your partner fee charged on this deposit (when `fee` is set — see below).
* `route`: the path Enso selected.
* `tx`: the transaction the user signs.

Always submit the returned `tx` as-is, including the returned `tx.to`.

## 4. Monetize The Deposit

Earn opens a partner-owned revenue line. Set your fee directly on the route call — it is collected as part of the same transaction, so your economics sit alongside the deposit rather than in a separate wrapper.

| Parameter      | Type      | Description                                                                                |
| -------------- | --------- | ------------------------------------------------------------------------------------------ |
| `fee`          | string\[] | Fee in basis points (1 bp = 0.01%, 100 bps = 1%), one value per `amountIn`.                |
| `feeReceiver`  | string    | Address that receives the collected fee. Required when `fee` is set.                       |
| `referralCode` | string    | Tags the transaction for on-chain attribution tracking (emits a `ShortcutExecuted` event). |

```typescript theme={null}
const route = await enso.getRouteData({
  chainId: 8453,
  fromAddress: user,
  receiver: user,
  spender: user,
  routingStrategy: "router",
  tokenIn: ["0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"], // USDC on Base
  tokenOut: ["0x4e65fe4dba92790696d040ac24aa414708f5c0ab"], // Aave Base USDC
  amountIn: ["100000000"], // 100 USDC
  slippage: "50",
  fee: ["20"], // 0.20% partner fee
  feeReceiver: "0x220866B1A2219f40e72f5c628B65D54268cA3A9D",
  referralCode: "EARN_BASE_USDC",
});
```

The response returns `feeAmount` (your fee) and `ensoFeeAmount` (Enso's platform fee) so you can show the user an itemized breakdown. For multi-step destination-chain logic, you can instead apply a [`fee` action](/pages/build/reference/actions) inside a Bundle. See [Request Tracking](/pages/build/examples/request-referral) for how to read `referralCode` attribution from on-chain events.

## Execution Safety Is Built In

You do not need to add a separate safety step. Every route Enso returns is simulated and protected before it reaches you: outputs are quoted with deterministic slippage bounds (`minAmountOut`), bundles settle atomically, and revert protection stops a partially executed workflow from stranding funds. Submit the returned `route.tx` as-is — the `amountOut`, `minAmountOut`, and `priceImpact` on the response are what you surface to the user on the review screen.

<Note>
  Enso Quoter is the same simulation-and-validation engine exposed as a standalone API for transactions generated **outside** Enso — for example, validating a payload from another aggregator before signing. For an Enso-routed Earn deposit it already runs in the background, so there is nothing extra to call. See [Enso Quoter](/pages/quoter/overview) if you also need to verify third-party transactions.
</Note>

## 5. Approve If Needed

If the source token is an ERC-20 and the route uses `routingStrategy: "router"`, the user must approve the Enso spender before signing the route transaction.

You can use the approval endpoint:

```typescript theme={null}
const approval = await enso.getApprovalData({
  chainId: 8453,
  fromAddress: user,
  routingStrategy: "router",
  tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  amount: "100000000",
});

await wallet.sendTransaction(approval.tx);
```

Then send the route transaction:

```typescript theme={null}
await wallet.sendTransaction(route.tx);
```

If the source token is native gas token, approval is not needed.

## 6. Show The New Balances

After the route transaction confirms, call balances again:

```typescript theme={null}
const updatedBalances = await enso.getBalances({
  chainId: 8453,
  eoaAddress: user,
  useEoa: true,
});
```

Compare `updatedBalances` with the balance snapshot from before execution:

* source asset decreased
* destination position increased
* any small dust or gas changes are visible

Use the destination token metadata from `GET /v1/tokens` to show the new position's APY, TVL, protocol, underlying assets, and logo.

## What You Can Build

Earn-shaped journeys from the full [Use Cases](/pages/use-cases/index) library:

<CardGroup cols={3}>
  <Card title="Embedded Yield" icon="layer-group" href="/pages/use-cases/yield-vaults/embedded-yield">
    The productized Earn surface for wallets, fintechs, and allocation products.
  </Card>

  <Card title="Cross-Chain Zap To Yield" icon="arrows-left-right" href="/pages/use-cases/wallet-flows/cross-chain-zap-to-yield">
    Take a source-chain asset into a destination-chain position in one signature.
  </Card>

  <Card title="Yield Migrator" icon="right-left" href="/pages/use-cases/yield-vaults/yield-migrator">
    Compare destinations and move users from one position into a better one.
  </Card>

  <Card title="Deposit & Withdraw" icon="piggy-bank" href="/pages/use-cases/deposits/withdrawal">
    Accept any token in and route the full exit path back out.
  </Card>

  <Card title="Stablecoin Issuers" icon="coins" href="/pages/use-cases/stablecoins-issuers/index">
    Route minting, distribution, and yield for stablecoin and RWA issuers.
  </Card>

  <Card title="Wallet Zap & Earn" icon="wallet" href="/pages/use-cases/wallets/zap-earn">
    Turn idle wallet balances into approved yield positions in-app.
  </Card>
</CardGroup>

## API & Safety Reference

<CardGroup cols={2}>
  <Card title="Route API" icon="route" href="/pages/build/get-started/route">
    Quote and execute direct entry into Earn destinations.
  </Card>

  <Card title="Balances" icon="wallet" href="/pages/build/get-started/balances">
    Show user assets and current DeFi positions before and after routing.
  </Card>

  <Card title="Protocol Data" icon="coins" href="/pages/build/get-started/protocol-data">
    Use token data for APY, TVL, metadata, and underlying assets.
  </Card>

  <Card title="Monetization & Attribution" icon="hand-holding-dollar" href="/pages/build/examples/request-referral">
    Apply partner fees and read referral attribution from on-chain events.
  </Card>

  <Card title="Enso Quoter" icon="shield" href="/pages/quoter/overview">
    Built into every Enso route — and available standalone to validate transactions generated outside Enso.
  </Card>
</CardGroup>

<div className="text-right text-xs gray-200 font-semibold w-full" style={{marginTop: '0'}}>
  <p style={{
        color: "#b2b2b2"  
    }}>Updated {date_0}</p>
</div>
