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

# simulateBestPositions

Preview the best yield split for an amount before anyone signs anything. Give it an amount, a token, and a chain (or several), and it comes back with the pools it would route into, the blended APY, and ready-to-run transaction calldata for each position.

<Tip title="No wallet required">
  This is a pure simulation — read-only, no signing, no gas. It only needs your API key, so it's a great fit for calculators, previews, and "what would I earn" dashboards. Call it as often as you like as the user tweaks their inputs.
</Tip>

## Signature

```typescript theme={null}
simulateBestPositions(params: SimulateBestPositionsParams): Promise<SimulateBestPositionsResponse>
```

## Parameters

`params` is a single object:

| Field           | Type                             | Required | Description                                                                           |
| --------------- | -------------------------------- | :------: | ------------------------------------------------------------------------------------- |
| `amount`        | `number`                         |     ✅    | Amount to deploy, in human units (e.g. `3000` for 3,000 USDC) — not wei.              |
| `token`         | `string`                         |     ✅    | Asset symbol, e.g. `"USDC"`, `"WETH"`, `"EURC"`.                                      |
| `networks`      | `number \| number[]`             |     ✅    | A chain ID, or an array of them, e.g. `8453` or `[8453, 42161]`.                      |
| `strategy`      | `"conservative" \| "aggressive"` |     ✅    | `"conservative"` favors lower risk; `"aggressive"` chases higher yield.               |
| `minSplit`      | `number`                         |     ❌    | Minimum number of pools to spread the amount across.                                  |
| `protocols`     | `string[]`                       |     ❌    | Restrict candidates to these protocols, e.g. `["aave", "morpho"]`.                    |
| `pools`         | `string[]`                       |     ❌    | Restrict candidates to these exact pool names.                                        |
| `userPositions` | `UserPosition[]`                 |     ❌    | Positions the user already holds, so the simulation can account for them (see below). |

```typescript theme={null}
interface UserPosition {
  protocol: string;
  pool: string;
  tvl: number; // the user's position size in this pool — not the pool's total TVL
}
```

## Returns

Chain-keyed simulated positions, plus calldata to actually enter each one.

## Return Type

```typescript theme={null}
interface SimulateBestPositionsResponse {
  success: boolean;
  data: Record<string, SimulatedPosition[]>; // keyed by chain ID
  messages: Record<string, string>;          // per-chain notes, e.g. why a chain came back empty
}

interface SimulatedPosition {
  protocol: string;
  pool: string;
  simulated_apy: number;             // base APY, no rewards
  combined_apy: number;              // headline APY including rewards — use this one
  amount: number;                    // how much goes into this pool, human units
  amount_raw: string;                // the same amount, in the token's raw decimal units
  tvl: number;                       // pool's total TVL
  liquidity: number;                 // pool's available liquidity
  averageCombinedApy30Days: number;  // 30-day average, useful to confirm the APY isn't a spike
  url: string;                       // link to the pool
  calldata: SimulateCalldataItem[];
}

interface SimulateCalldataItem {
  contract_address: string;
  function_name: string;   // e.g. "approve", "deposit"
  parameters: string[];
  value: string;           // ETH value, usually "0"
  description: string;     // human-readable, e.g. "Approve 3000 USDC for Morpho"
}
```

<Warning title="Replace the receiver before sending">
  The `deposit` calldata contains a `"<RECEIVER>"` placeholder among its `parameters`. Swap it for the real receiving address (usually the user's Safe / smart wallet) before you send the transaction.
</Warning>

## Good to know

A few behaviors worth knowing before you build against this, confirmed by calling the live API directly:

* **`userPositions` is additive, not just contextual.** If the user already has $1,500 in a pool and you simulate depositing $3,000 more, the returned position is sized for the **combined** $4,500 — not $3,000. Pass it in whenever you know where the user already is.
* **`minSplit` divides the amount evenly** across that many pools. `minSplit: 3` on $5,000 returns three ~$1,666.67 positions, each with its own `calldata`.
* **A chain can come back empty on purpose.** If every candidate pool for a chain gets excluded (unstable APY, doesn't clear the strategy's risk bar, etc.), that chain's entry in `data` is `[]` and `messages[chainId]` explains why.
* **An unmatched `pools` filter isn't a dead end.** The call still returns `success: true` with an empty array for that chain, and `messages[chainId]` lists the pools that actually exist for that token/chain/strategy — handy for a "did you mean…" experience.
* Works for any supported chain/token combination — no special-casing needed for less common pairs.

## Examples

### Simplest call

```typescript theme={null}
const result = await sdk.simulateBestPositions({
  amount: 3000,
  token: "USDC",
  networks: 8453,
  strategy: "conservative",
});

console.log(result.data["8453"]);
// [{ protocol: "Morpho", pool: "Gauntlet USDC Prime", combined_apy: 4.15, ... }]
```

### Multiple chains, with a minimum split

```typescript theme={null}
const result = await sdk.simulateBestPositions({
  amount: 5000,
  token: "USDC",
  networks: [8453, 42161],
  strategy: "conservative",
  minSplit: 3,
});

const positions = Object.values(result.data).flat();
console.log(positions.map((p) => `${p.protocol}/${p.pool}: $${p.amount}`));
```

### Accounting for an existing position

```typescript theme={null}
await sdk.simulateBestPositions({
  amount: 3000,
  token: "USDC",
  networks: 8453,
  strategy: "conservative",
  userPositions: [
    { protocol: "aave", pool: "USDC", tvl: 1500 }, // the user's current position size
  ],
});
// Simulated against a $4,500 total, not $3,000.
```

### Blended APY across a split

```typescript theme={null}
const positions = Object.values(result.data).flat();
const total = positions.reduce((sum, p) => sum + p.amount, 0);
const blendedApy =
  positions.reduce((sum, p) => sum + p.amount * p.combined_apy, 0) / total;
```
