Skip to main content
A loop is: supply one asset as collateral, borrow another against it, swap back to the collateral asset and re-supply, n times. It turns a supply APY rs and a borrow cost rb into f(L) = L·rs − (L−1)·rb, linear in leverage L. This endpoint answers which pairs exist and roughly what they pay. It does not tell you how much leverage to run, and it does not publish a loop APY.
L follows from a risk budget, a gross-exposure cap, a health-factor floor and the rest of a book — none of which this API can see, and two consumers must be able to choose different L from the same row. f(L) additionally depends on whether an emission-priced reward counts, which is a judgement, not a venue fact. The API returns the frontier; the caller picks the point.

List Loopable Pairs

GET /loops One row per (collateral, debt) pair inside one lending pool, on one chain. The set is materialized by the daily sync and served from cache: no chain reads, and no pagination — the whole screen comes back in one response.

Query Parameters

number
Restrict to one chain, e.g. 143.
string
Instrument ID of the supplied leg.
string
Instrument ID of the borrowed leg.
Filters compose, and an empty match is [] rather than an error.

Request

Response

Reading the row

emission means the reward APY is valued at the emission schedule and the token’s quoted price, not at what a position could actually sell into. That is how the upstream number is built, and on a thin reward token the two diverge, and leverage multiplies the gap. The error is directional — it floats reward-heavy pairs to the top of any ranking — so discount the number rather than inherit it.none means neither leg pays a reward. traded is reserved for a reward APY derived from an executable quote and is not produced by this endpoint; a stream that could not be priced reports emission, never something more optimistic.
24h traded volume of the thinnest reward stream on the row, and null when any of them is unmeasured. null is unknown, not zero: the two must not be collapsed, because one is a reason to size down and the other is a reason to look again.Compare it with emissionUsdPerDay. A stream emitting more per day than its token trades per day has no exit at size, whatever the APY says.
basis: "defillama-pool-default" is a warning, not decoration: the figure carries no e-mode, no per-collateral factor and no per-market LLTV, and the gap between a default and an effective LTV is the gap between very different ceilings. Size the screen with it; read the effective figure on chain before anything is signed.
A cross-asset loop needs a swap at per-turn notional, so its cost grows with L and its quote can go stale. Its health factor also drifts with the collateral/debt price ratio, not only with interest: HF = (collateral × liqThreshold) / (debt × r), so liquidation arrives at r = HF₀ and the divergence budget is exactly HF₀ − 1. A same-asset loop at HF = 1.03 is fine; a cross-asset one at HF = 1.03 is three percent of price divergence from liquidation, and assets that are supposed to track each other have moved further than that.
  • Routes. Nothing here knows whether a swap route exists at per-turn notional. A pair can screen well on rates and have no venue that will fill the turns.
  • Oracles. Liquidation is decided by the pool’s oracle, not by market price.
  • Freshness. Rates go stale intraday by design. This endpoint decides what to look at.

How a row is built

The supply side of each pair is the collateral instrument’s own snapshot — the same numbers /instruments serves — and the borrow side comes from DeFiLlama’s /lendBorrow, joined on the pool id the two share. A reserve missing from /lendBorrow is not lending-shaped and is never paired. A pair whose debt leg is not a listed instrument is omitted rather than synthesised, and a collateral leg the venue gives no LTV (ltv = 0) can never start a loop however good its supply rate looks. loopId is deterministic from (chainId, pool, collateralInstrumentId, debtInstrumentId). The order of the legs is part of it: supplying USDC to borrow AUSD and supplying AUSD to borrow USDC are different trades, and on the measured snapshot one of them had a negative gradient. Leverage is deliberately not part of it — L is a request parameter, so there is one row per pair rather than one per (pair, L).

Build a Loop Bundle

GET /loops/:loopId/calldata The tier-2 read. The screen said a pair exists; this re-reads it on chain at a pinned quote block, builds every turn of the loop as one ordered batch for the account to sign, simulates the batch atomically, and reports the position the simulation left behind. It is the same envelope as /instruments/:id/calldatacalls, requires, leftovers, minOut, expiresAt, simulation — plus a leverage block (the venue fact) and a simulated block (the measurement). It still does not choose L. leverage is a request parameter, and the API builds whatever reachable leverage it is asked for.

Query Parameters

string
required
open supplies amount and levers it to leverage. adjust moves an open position to leverage with its equity unchanged — up or down. close unwinds fully, to zero debt, in one batch.
string
required
The smart account that supplies, borrows and receives.
string
Target collateral ÷ equity at the pool’s oracle, e.g. 4 or 3.25. Required for open and adjust; rejected for close.
string
Equity to supply, in raw units of the collateral token. Required for open, rejected otherwise. max is never accepted: every amount in a loop is hard-coded into the batch.
string
default:"auto"
auto picks the e-mode category that admits both legs with the highest LTV; none keeps the reserve’s default parameters; a number forces that category and is refused if it does not admit the pair. close ignores it and unwinds under the account’s current category.
number
default:"50"
Taken off each swap’s quote to size its exact output. What a swap does not spend stays in the wallet, listed in leftovers.
number
default:"100"
Refuse a route whose quote, at the loop’s cumulative notional, is further than this below the pool’s oracle.

Request

Response

A USDC/AUSD pair under e-mode, calls truncated:

Reading the bundle

ltv and liquidationThreshold are what the pool will apply to this pair after the bundle — the e-mode category’s where the account will be in one — read at the quote block. paramsBasis says which (emode:<id> or default). A pair whose effective parameters cannot be read fails closed rather than falling back to the screen’s pool default, and after simulating, the recipe reads the account’s LTV and threshold back from the pool: if they disagree with what it planned under, the bundle is refused.
Aave’s e-mode is set per account per pool, not per position. When this is true the bundle contains a set_account_config call, and every other position the account holds in that pool is re-priced by it — including an unlevered supply it has nothing to do with. Check the book before signing. A close that leaves no other debt in the pool clears the category back to 0.
Read back from the simulated block after the batch ran. collateral/debt and leverage are this pair’s; healthFactor and the total*Base figures are the pool’s own account-level accounting, so they include anything else the account holds there. depegBufferBps is (HF − 1) — the adverse move in the debt/collateral price ratio the position survives — for a cross-asset pair only. The requested leverage is hit on the position itself: swap costs come out of equity, not out of the health factor.
Each turn is borrow · swap · supply (borrow · supply for a same-asset pair; withdraw · swap · repay on the way down). Every amount is computed at the quote block and written into the calldata; every swap is exact-output, so the supply after it is known. Each borrow keeps 25 bps of headroom under the LTV and each intermediate withdrawal 50 bps above the liquidation threshold. A full unwind buys 10 bps more debt asset than the quote-block debt and repays with max, so interest accrued before it lands is cleared too.Swaps are quoted cumulatively through one pool fixed for the bundle: turn k is priced after the turns before it, and the route is chosen — Uniswap V3 or the pinned V4 pool, whichever fills the whole loop better — at the loop’s full notional, not at one turn of it.
  • 400leverage at or above the pair’s effective ceiling (named, with its basis); no liquid route at the loop’s size; an e-mode that does not admit the pair; open over existing debt on the pair, or close/adjust with none; a simulation that reverted or left debt after a full unwind.
  • 501 — no loop recipe for this venue. aave-v3-loop serves Aave V3 and its forks; Comet, Morpho Blue and Euler loops are separate recipes, not yet built.
  • 503 — chain state, the swap quote or the simulation was unavailable.