# 1delta — full reference for language models This file is generated from the OpenAPI spec and the documentation source. It contains the complete API surface as plain text: every endpoint, every parameter, every response field, and a representative example for each. Nothing here requires JavaScript to read. Generated from OpenAPI 3.1.0, API version 1.0.0. --- ## Overview Unified API for DeFi data and actions. ## Machine-readable spec | Artefact | URL | | --- | --- | | OpenAPI 3.1 (enriched, what this site renders) | [`https://docs.1delta.io/openapi.json`](https://docs.1delta.io/openapi.json) | | OpenAPI 3.1 (raw, from the API server) | [`https://portal.1delta.io/v1/openapi.json`](https://portal.1delta.io/v1/openapi.json) | | Endpoint index for LLMs | [`https://docs.1delta.io/llms.txt`](https://docs.1delta.io/llms.txt) | | Full flattened reference for LLMs | [`https://docs.1delta.io/llms-full.txt`](https://docs.1delta.io/llms-full.txt) | If you are pointing a coding agent at this API, give it `llms-full.txt` — it carries every endpoint, parameter, field and example as plain text, with no JavaScript required. ## Authentication & rate limits Every endpoint is public. Send an API key as the `x-api-key` header to raise your rate limit; get one at [auth.1delta.io](https://auth.1delta.io/). Unauthenticated traffic is limited per IP — treat `429` as retryable with exponential backoff rather than assuming a fixed budget. There is no authentication *failure* mode: an unrecognised key is ignored rather than rejected, so a request never fails with `401` because of a bad key. ## Response Envelope Every endpoint returns a consistent JSON envelope. Integrators can rely on the same top-level shape regardless of the endpoint called. ### Success ```json { "success": true, "data": { ... }, "actions": { "transactions": [...], "permissions": [...] } | null } ``` - **`data`** — Informational payload (market data, quotes, simulation results, user positions, etc.). Present on all responses; `null` when the endpoint only produces transaction calldata with no additional info. - **`actions`** — Transaction calldata and approval/permission transactions that the caller should execute on-chain. Only populated by action endpoints; `null` on data endpoints. - `actions.transactions` — Array of `{ to, data, value }` objects ready to be sent as EVM transactions. - `actions.permissions` — Envelope-level array of approval/permission transactions (ERC-20 approves, credit delegations) that must be executed **before** the main transactions. Each entry has a human-readable `description`. > **Note on `permissions` vs `permissionTxns`:** the envelope exposes a single deduplicated `actions.permissions` array. Inside richer action responses (e.g. loop alternatives), each individual quote also carries its own `permissionTxns` — the per-quote subset needed if that specific alternative is executed. Most integrators only need `actions.permissions`. ### Error ```json { "success": false, "error": { "code": "MISSING_PARAM", "message": "marketUid is required" } } ``` - **`error.code`** — Machine-readable error code (e.g. `MISSING_PARAM`, `INVALID_PARAM`, `ACTION_FAILED`, `NOT_FOUND`, `ORIGIN_FAILED`). - **`error.message`** — Human-readable description. The envelope is the same for every failure, so `success` is the only field you need to branch on. Note that a missing or malformed required parameter currently surfaces as HTTP `502` with `error.code = ORIGIN_FAILED` rather than a `400` — branch on `success`, not on the status code. See [Errors & retries](/errors). --- ## Identifiers Most endpoints address a market with a **`marketUid`**: `lender:chainId:address`, e.g. `AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`. The `lender` segment comes from the `LenderId` set and `address` is the underlying asset, not the receipt token. See [Market identifiers](/market-identifiers). --- ## Data (`/v1/data/*`) Cacheable market data, prices, yields, and user positions. These endpoints always return `actions: null` — only the `data` field is populated. ## Actions (`/v1/actions/*`) Transaction builders organized by category: - **Lending** — deposit, withdraw, borrow, repay, mode, enable-collateral, repay-with-atoken - **Loop** — leverage, close, collateral-swap, debt-swap, migrate (cross-lender), refinance (see also *Data › Loop* for range calculations) - **Swap** — spot (same-chain meta-aggregator), x-chain (bridge aggregation) - **Allocate** — batch operations All action endpoints support **GET** (query parameters only) and **POST** (query parameters + JSON body for post-trade simulation). The `allocate` endpoint is POST-only. For loop and swap operations, omit `account` for a **quote-only** response (`data` contains quotes, `actions` is `null`), or include it to build full transaction calldata (`actions` is populated with ready-to-send transactions). Action endpoints never sign or broadcast anything. They return calldata; your wallet or signer sends it. Execute `actions.permissions` first, then one transaction from `actions.transactions` (or exactly one entry from `actions.alternatives` where present). See the [Quickstart](/quickstart). ## Simulation (POST) POST the same query parameters as GET, plus a JSON body with the user's current `balanceData` and `aprData`. The response includes the standard fields plus a `simulation` object in `data` with projected post-trade health factor, borrow capacity, and APR data. ## Execution Modes (lending only) - **direct** (default): Raw protocol interaction (deposit/withdraw/borrow/repay only) - **proxy**: Routes through 1delta composer contracts --- ## Servers - `https://portal.1delta.io` — Production - `https://portal-staging.1delta.io` — Staging - `http://localhost:8787` — Local Development --- ## Lender identifiers Accepted by the `lender` parameter and used as the first segment of a `marketUid`. ``` AAVE_V3 AAVE_V3_PRIME AAVE_V3_ETHER_FI AAVE_V3_HORIZON AAVE_V2 AURELIUS LENDLE LENDLE_CMETH LENDLE_SUSDE LENDLE_PT_CMETH MERIDIAN TAKOTAKO TAKOTAKO_ETH HANA YLDR MAGSIN SPARK NEREUS KINZA GRANARY LORE LENDOS IRONCLAD MOLEND SEISMIC POLTER AGAVE MOOLA XLEND KLAP RHOMBUS RMM KLAYBANK SAKE SAKE_ASTAR LAYERBANK_V3 COLEND COLEND_LSTBTC PAC VALAS HYPERLEND HYPURRFI HYPERYIELD MOONCAKE PHIAT RADIANT_V2 FATHOM U235 QUOKKA_LEND PRIME_FI PLOUTOS YEI YEI_SOLV NEVERLAND KONA_LEND EDEL VOLTAGE_LENDING AQUALOAN BETTER_BANK BETTER_BANK_ATROPA DTRINITY ZONA ZEROLEND ZEROLEND_STABLECOINS_RWA ZEROLEND_ETH_LRTS ZEROLEND_BTC_LRTS ZEROLEND_CROAK ZEROLEND_FOXY LENDLE_SUSDE_USDT LENDLE_METH_WETH LENDLE_METH_USDE LENDLE_CMETH_WETH LENDLE_CMETH_USDE LENDLE_CMETH_WMNT LENDLE_FBTC_WETH LENDLE_FBTC_USDE LENDLE_FBTC_WMNT LENDLE_WMNT_WETH LENDLE_WMNT_USDE AVALON AVALON_SOLVBTC AVALON_SWELLBTC AVALON_PUMPBTC AVALON_UNIBTC AVALON_EBTC_LBTC AVALON_USDA AVALON_SKAIA AVALON_LORENZO AVALON_INNOVATION AVALON_UBTC AVALON_OBTC AVALON_BEETS AVALON_UNIIOTX AVALON_BOB AVALON_STBTC AVALON_WBTC AVALON_LBTC AVALON_XAUM AVALON_LISTA AVALON_USDX COMPOUND_V2 VENUS VENUS_ETH VENUS_BNB VENUS_BTC VENUS_MEME VENUS_DEFI VENUS_GAMEFI VENUS_STABLE VENUS_TRON VENUS_ETHENA VENUS_CURVE SEGMENT ENCLABS ENCLABS_LST ENCLABS_PT_USD ENCLABS_PT_ETH ENCLABS_SONIC_ECO TAKARA UNITUS BENQI BENQI_AVALANCHE_ECOSYSTEM KEOM OVIX MOONWELL LODESTAR ORBITER_ONE MENDI SUMER TECTONIC TECTONIC_VENO TECTONIC_DEFI KINETIC KINETIC_FXRP KINETIC_JOULE SHOEBILL DFORCE TENDER FLUX_FINANCE WE_PIGGY GAMMA CREAM_FINANCE CAPY_FI COMPOUND_V3_USDC COMPOUND_V3_USDT COMPOUND_V3_USDE COMPOUND_V3_USDBC COMPOUND_V3_USDCE COMPOUND_V3_USDS COMPOUND_V3_WETH COMPOUND_V3_WRON COMPOUND_V3_AERO COMPOUND_V3_WSTETH COMPOUND_V3_WBTC INIT MORPHO_BLUE LISTA_DAO MORPHO_MIDNIGHT TERM_FINANCE EXACTLY LIQUITY_V2 USDAF FELIX NERITE QUILL ENOSYS_LOANS SONETA EBISU RIVER TELLER INVERSE SKY FRANKENCOIN USDD TERMMAX LLAMALEND RESUPPLY CURVANCE FRAXLEND FLUID GEARBOX_V3 SILO_V2 SILO_V3 EULER_V2 DOLOMITE SWAYLEND_USDC ``` --- ## Supported chains Chain ids are decimal strings. | chainId | Name | | --- | --- | | `1` | Ethereum | | `10` | OP | | `14` | Flare | | `25` | Cronos | | `40` | Telos EVM | | `50` | XDC | | `56` | BNB | | `100` | Gnosis | | `130` | Unichain | | `137` | Polygon | | `143` | Monad | | `146` | Sonic | | `169` | Manta Pacific | | `196` | X Layer | | `250` | Fantom Opera | | `324` | zkSync | | `369` | PulseChain | | `988` | Stable | | `999` | HyperEVM | | `1088` | Metis Andromeda | | `1116` | Core | | `1135` | Lisk | | `1329` | Sei | | `1672` | Pharos | | `1868` | Soneium | | `2741` | Abstract | | `2818` | Morph | | `4326` | MegaETH | | `4663` | Robinhood | | `5000` | Mantle | | `8217` | Kaia | | `8453` | Base | | `9745` | Plasma | | `34443` | Mode | | `42161` | Arbitrum One | | `42220` | Celo | | `43111` | Hemi | | `43114` | Avalanche | | `57073` | Ink | | `59144` | Linea | | `60808` | BOB | | `80094` | Berachain | | `81457` | Blast | | `98866` | Plume | | `167000` | Taiko | | `534352` | Scroll | | `747474` | Katana | --- ## Guides ### What is 1delta Source: https://docs.1delta.io/ Universal lending aggregation One API for every DeFi lending protocol — query, aggregate, and execute complex positions atomically across chains. Start integrating Explore the API 185protocols unified 47chains supported 1 txatomic migrations Quickstart Zero to a signed transaction in four calls 1delta API Data, prices, yields & transaction builders Lending concepts Normalized risk model across protocols Looping guide Build leveraged positions in one tx Smart contracts Composer entry points & operations --- ## Why Lending Aggregation Matters DeFi lending has grown to billions in TVL across dozens of protocols. But this fragmentation creates real problems for users and developers. --- ## The Current State: Fragmented Lending Today's DeFi lending ecosystem looks like this: ### The Confusion Problem Consider a user wanting to supply USDC for yield. They face: | Protocol | Supply APY | Risk Factors | |----------|-----------|--------------| | Aave V3 | 5.2% | Battle-tested, insurance fund | | Compound V3 | 4.8% | Single-collateral model, proven security | | Morpho Blue | 6.1% | Higher rates, market-specific risk | | Silo V2 | 5.5% | Isolated markets, newer protocol | **Questions the user must answer:** 1. Which APY is actually best after accounting for gas costs? 2. How do the risk parameters compare? 3. What's my liquidation threshold on each? 4. How liquid is each market if I need to exit quickly? 5. Do I need to monitor multiple positions? **For developers, it's even worse:** - 5 different APIs to integrate - 5 different data formats - 5 different transaction formats - 5 different risk models to understand - Constant maintenance as protocols upgrade --- ## The 1delta Solution: Unified Aggregation --- ## Real-World Scenario: Finding the Best USDC Yield ### Without 1delta (Manual Approach) **Step 1: Check Aave V3** - Navigate to app.aave.com → Connect wallet → Find USDC market - Note: 5.2% APY, 82.5% LTV | Gas to deposit: ~$15 **Step 2: Check Compound V3** - Navigate to compound.finance → Connect wallet → Find USDC market - Note: 4.8% APY, 90% LTV | Gas to deposit: ~$12 **Step 3: Check Morpho Blue** - Navigate to morpho.org → Connect wallet → Find USDC markets (multiple!) - Compare rates across markets - Note: 5.5-6.5% APY depending on market | Gas to deposit: ~$18 **Step 4: Make decision** - Compare rates → Evaluate risks manually → Execute transaction [The Manual Process] | | | |---|---| | **Time** | 30+ minutes | | **Mental overhead** | High | | **Missed opportunity** | Better rate launched on Silo while you were checking | ### With 1delta API One request returns every market for the asset, across every protocol, in one shape: ```bash curl "https://portal.1delta.io/v1/data/lending/pools?chainId=1" ``` ```json { "success": true, "data": { "items": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "lenderKey": "AAVE_V3", "name": "Aave V3 WETH", "depositRate": 1.41624773, "variableBorrowRate": 2.0744452, "utilization": 0.8005563978698457, "totalLiquidityUsd": 705855814.4854279 } ] }, "actions": null } ``` Sort by `depositRate`, then hand the winning `marketUid` straight to an action endpoint to get signable calldata back: ```bash curl "https://portal.1delta.io/v1/actions/lending/deposit\ ?marketUid=AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\ &amount=1000000000000000000\ &operator=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" ``` ```json { "success": true, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037…", "value": "0" } ], "permissions": [ { "to": "0xc02aaa39…", "data": "0x095ea7b3…", "value": "0", "description": "Approve for AAVE_V3" } ] } } ``` Send the approval, then the transaction. Full walkthrough in the [Quickstart](/quickstart). [Result] | | | |---|---| | **Time** | 30 seconds | | **Mental overhead** | Minimal | | **Always optimal** | Yes | --- ## Quantified Benefits ### For Users | Metric | Manual | With 1delta | Improvement | |--------|--------|-------------|-------------| | Time to find best rate | 30+ min | Instant | 99%+ | | Transactions for looping | 5-10 | 1 | 80-90% | | Missed yield opportunities | Common | None | 100% | | Risk of partial execution | Yes | No | Eliminated | ### For Developers | Aspect | Direct Integration | 1delta API | Benefit | |--------|-------------------|------------|---------| | Protocols to integrate | 5+ | 1 | 80% less code | | APIs to maintain | 5+ | 1 | 80% less maintenance | | Data formats | 5+ different | 1 unified | Simplified logic | | Transaction builders | 5+ | 1 | Faster development | | Time to market | Months | Days | 10x faster | --- ## Risk Aggregation: Comparing Apples to Apples One of the biggest challenges in DeFi lending is comparing risk across protocols. Each protocol uses different terminology and metrics. ### The Problem: Inconsistent Risk Metrics | Protocol | Collateral Term | Liquidation Term | Penalty Term | |----------|----------------|------------------|--------------| | Aave | LTV | Liquidation Threshold | Liquidation Bonus | | Compound | Collateral Factor | Liquidate Borrow | Close Factor | | Morpho | LLTV | LLTV | Liquidation Incentive | **Same concepts, different names, different calculations.** ### The Solution: Normalized Risk Metrics 1delta normalizes all risk parameters into a consistent format: Every lender's markets come back through the same endpoint, with the same field names and the same units — so comparing Aave against Compound against Morpho is sorting an array, not writing three adapters: ```bash curl "https://portal.1delta.io/v1/data/lending/pools?chainId=1" ``` Each item carries its own `marketUid`, its rates as percentages, and its utilization and risk parameters as fractions between 0 and 1. Field-by-field detail is in the [endpoint reference](/1delta-api/get-lending-pools) and in [`llms-full.txt`](https://docs.1delta.io/llms-full.txt). --- ## Protocol Migration Made Easy **Scenario:** User has a 3x leveraged wstETH position on Aave V3 but Compound V3 just launched better rates. ### Manual Migration (Without 1delta) 1. Obtain funds to repay debt (where from?) 2. Repay debt on Aave 3. Withdraw collateral from Aave 4. Deposit collateral to Compound 5. Borrow from Compound 6. Return borrowed funds [Manual Migration Cost] | | | |---|---| | **Transactions** | 6+ | | **Risk** | Price movement between steps could cause issues | | **Time** | 30+ minutes | | **Complexity** | High (need temporary capital) | ### 1delta Migration (Single Transaction) With our stack, such an operation can be executed in a single transaction without any currency conversions. [1delta Migration Result] | | | |---|---| | **Transactions** | 1 (atomic) | | **Risk** | None (atomic execution, no swaps needed) | | **Time** | Single block | | **Complexity** | Handled by 1delta | --- ## Summary: The Aggregation Advantage **Key Benefits:** 1. **Single integration point** - One API for all protocols 2. **Normalized data** - Consistent formats and risk metrics 3. **Optimal rates** - Always find the best opportunity 4. **Atomic execution** - No partial execution risk 5. **Gas efficiency** - Complex operations in single transactions 6. **Future-proof** - New protocols added without code changes --- ## Get Started Ready to simplify your DeFi lending integration? Start here Quickstart → Four calls from nothing to a mined transaction Reference 1delta API → Query data and build lending transactions Reference Market identifiers → marketUid, lender ids, chain ids, units Guide Looping Guide → Build leveraged positions atomically [Integrating with an AI coding assistant?] Point it at [`llms-full.txt`](https://docs.1delta.io/llms-full.txt) — every endpoint, parameter and example as plain text. The interactive endpoint pages render their schemas in the browser, so fetching their HTML shows prose only. --- ### Contract Addresses Source: https://docs.1delta.io/contract-addresses # Contract Addresses These are the deployment addresses for the 1delta composer smart contracts. [Immutable contracts] The composers listed below are **immutable**: each is a transparent proxy whose upgrade admin has been **renounced** (the `ProxyAdmin` owner is set to `address(0)`), so its logic can never be upgraded, paused, or replaced. These addresses are permanent entry points. Only the chains listed here are frozen. **Newly added chains follow the same lifecycle** — a composer is first deployed upgradeable, iterated during an initial rollout, then frozen by renouncing the admin. So a recently added chain may remain upgradeable until its ownership is renounced and it appears here. ## Composer contract The addresses below are the composer **proxy** addresses — the stable entry points to call. The underlying logic is frozen (see the note above). | Chain | Chain ID | Address | | ----------------------- | -------- | -------------------------------------------- | | ETHEREUM_MAINNET | 1 | `0x8e24cfc19c6c00c524353cb8816f5f1c2f33c201` | | OP_MAINNET | 10 | `0xCDef0A216fcEF809258aA4f341dB1A5aB296ea72` | | FLARE_MAINNET | 14 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | CRONOS_MAINNET | 25 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | TELOS_EVM_MAINNET | 40 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | XDC_NETWORK | 50 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | BNB_SMART_CHAIN_MAINNET | 56 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | GNOSIS | 100 | `0xcb6eb8df68153cebf60e1872273ef52075a5c297` | | UNICHAIN | 130 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | POLYGON_MAINNET | 137 | `0xFd245e732b40b6BF2038e42b476bD06580585326` | | MONAD_MAINNET | 143 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | SONIC_MAINNET | 146 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | MANTA_PACIFIC_MAINNET | 169 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | X_LAYER_MAINNET | 196 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | FANTOM_OPERA | 250 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | ZKSYNC_MAINNET | 324 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | PULSECHAIN | 369 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | STABLE_MAINNET | 988 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | HYPEREVM | 999 | `0xcb6eb8df68153cebf60e1872273ef52075a5c297` | | METIS_ANDROMEDA_MAINNET | 1088 | `0xCe434378adacC51d54312c872113D687Ac19B516` | | CORE_BLOCKCHAIN_MAINNET | 1116 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | LISK | 1135 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | MOONBEAM | 1284 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | SEI_NETWORK | 1329 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | PHAROS_MAINNET | 1672 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | SONEIUM | 1868 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | ABSTRACT | 2741 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | MORPH | 2818 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | MEGAETH_MAINNET | 4326 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | ROBINHOOD_CHAIN | 4663 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | MANTLE | 5000 | `0x5c019a146758287c614fe654caec1ba1caf05f4e` | | KAIA_MAINNET | 8217 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | BASE | 8453 | `0xB7ea94340e65CC68d1274aE483dfBE593fD6f21e` | | PLASMA_MAINNET | 9745 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | MODE | 34443 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | ARBITRUM_ONE | 42161 | `0x05f3f58716a88A52493Be45aA0871c55b3748f18` | | CELO_MAINNET | 42220 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | HEMI_NETWORK | 43111 | `0x79f4061BF049c5c6CAC6bfe2415c2460815F4ac7` | | AVALANCHE_C_CHAIN | 43114 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | INK | 57073 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | LINEA | 59144 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | BOB | 60808 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | BERACHAIN | 80094 | `0xcB6Eb8df68153cebF60E1872273Ef52075a5C297` | | BLAST | 81457 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | PLUME_MAINNET | 98866 | `0x816EBC5cb8A5651C902Cb06659907A93E574Db0B` | | TAIKO_ALETHIA | 167000 | `0x594cE4B82A81930cC637f1A59afdFb0D70054232` | | SCROLL | 534352 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | | KATANA | 747474 | `0x8E24CfC19c6C00c524353CB8816f5f1c2F33c201` | ## Call forwarder contract | Chain | Address | | ---------- | -------------------------------------------- | | ALL CHAINS | `0xfCa1154C643C32638AEe9a43eeE7f377f515c801` | --- ### Errors & retries Source: https://docs.1delta.io/errors # Errors & retries ## Branch on `success`, not on the status code Every failure — validation, upstream, rate limiting — returns the same envelope: ```json { "success": false, "error": { "code": "MISSING_PARAM", "message": "marketUid is required", "details": null } } ``` | Field | Use | | --- | --- | | `error.code` | Stable and machine-readable. Branch on this. | | `error.message` | For humans and logs. Wording may change; do not parse it. | | `error.details` | Optional extra context; shape varies by code. | The HTTP status is **not** a reliable signal. A missing required parameter currently comes back as `502` with `ORIGIN_FAILED`, not as `400`: ```bash curl -i "https://portal.1delta.io/v1/data/lending/pools" # no chainId ``` ``` HTTP/2 502 ``` ```json { "success": false, "error": { "code": "ORIGIN_FAILED", "message": "All origins failed", "details": [ { "origin": 0, "status": 500, "details": "{\"ok\":false,\"error\":\"chainId is required\"}" } ] } } ``` So the only correct check is: ```ts const body = await res.json(); if (!body.success) { throw new Error(`${body.error.code}: ${body.error.message}`); } ``` Checking `res.ok` first will mislabel a validation mistake as an outage. ## Codes | Code | Meaning | Retry? | | --- | --- | --- | | `MISSING_PARAM` | A required parameter was absent. | No — fix the request. | | `INVALID_PARAM` | Present but malformed: bad `marketUid`, unknown lender, non-integer amount. | No — fix the request. | | `NOT_FOUND` | No such market, pool, or position. | No. | | `VALIDATION_FAILED` | A pre-flight on-chain check could not be confirmed. | Sometimes — often an RPC hiccup. | | `ACTION_FAILED` | The transaction could not be built: no route, insufficient liquidity, unsupported path. | Sometimes — retry with different amounts or slippage. | | `ORIGIN_FAILED` | An upstream data source or protocol origin failed. Also what a missing parameter currently produces. | Yes, if the request itself is valid. | ## Statuses you should handle | Status | Meaning | Handling | | --- | --- | --- | | `200` | Success. Still check `success` in the body. | — | | `400` | Validation error. | Fix the request. | | `404` | No such resource. | Fix the request. | | `429` | Rate limited. | Back off exponentially, then retry. | | `500` | Server error. | Retry with backoff. | | `502` | Upstream origin failed — **or** a bad parameter. Inspect `error.code`. | Retry only if the request is valid. | ## Rate limits Requests are limited per IP when unauthenticated. Send an API key to raise the limit: ```bash curl -H "x-api-key: YOUR_KEY" "https://portal.1delta.io/v1/data/chains" ``` Get a key at [auth.1delta.io](https://auth.1delta.io/). An unrecognised key is **ignored, not rejected** — a bad key never causes a `401`, it just leaves you on the unauthenticated limit. If you are being throttled while sending a key, verify the key is actually valid rather than assuming the header is being read. Treat `429` as retryable with exponential backoff and jitter rather than coding against a fixed budget. ```ts async function call(url: string, attempt = 0): Promise { const res = await fetch(url, { headers: { "x-api-key": process.env.ONEDELTA_KEY! } }); if (res.status === 429 || res.status >= 500) { if (attempt >= 4) throw new Error(`giving up after ${attempt} retries: ${res.status}`); const backoff = 2 ** attempt * 500 + Math.random() * 250; await new Promise((r) => setTimeout(r, backoff)); return call(url, attempt + 1); } const body = await res.json(); if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`); return body; } ``` Note this still retries a `502` caused by a bad parameter. Inspect `error.code === "ORIGIN_FAILED"` versus a validation code if you want to avoid burning retries on a request that can never succeed. ## Failures that happen on-chain, not in the API A `200` with calldata does not guarantee the transaction succeeds. The usual causes of a revert after a successful build: - An approval from `actions.permissions` was not mined before the action was sent. - More than one entry from `actions.alternatives` was executed. - The quote went stale — rates and routes move every block. - `slippage` was too tight for the route, or was passed as a percentage instead of [basis points](/market-identifiers#basis-points). - The position's health factor would drop below the liquidation threshold. Simulate first where the endpoint supports it: `POST` the same parameters with the user's current `balanceData` and `aprData`, or pass `simulate=true` on lending actions, and inspect the projected health factor before signing. ## Related - [Quickstart](/quickstart) - [Market identifiers](/market-identifiers) --- ### Lending Source: https://docs.1delta.io/lending ## Lending Aggregation 1delta aggregates multiple DeFi lending protocols into a unified interface. Instead of integrating with each protocol separately, developers can use a single API to query data and build transactions across all supported lending markets. --- ## The Problem DeFi lending is fragmented across many protocols: - **Aave** (V2, V3) - The largest lending protocol - **Compound** (V2, V3) - Pioneer of algorithmic money markets - **Morpho Blue** - Permissionless lending markets - **Silo** - Isolated lending markets - And more... Each protocol has: - Different smart contract interfaces - Different data structures and return formats - Different risk parameters and terminology - Different transaction patterns **Result:** Building applications that work across protocols requires significant integration effort and ongoing maintenance. --- ## The Solution 1delta provides two core capabilities: ### 1. Unified Data API Query lending market data across all protocols with consistent response formats: ```bash curl "https://portal.1delta.io/v1/data/lending/pools?chainId=1" ``` Every protocol comes back through one endpoint in one shape — supply and borrow rates, total liquidity, utilization, and risk parameters, with the same field names and units regardless of which lender produced them: ```json { "success": true, "data": { "items": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "lenderKey": "AAVE_V3", "name": "Aave V3 WETH", "depositRate": 1.41624773, "variableBorrowRate": 2.0744452, "utilization": 0.8005563978698457, "totalDepositsUsd": 4033189395.3983254, "totalLiquidityUsd": 705855814.4854279 } ] }, "actions": null } ``` Add `&lender=AAVE_V3` to narrow to one protocol. Full parameter list: [`GET /v1/data/lending/pools`](/1delta-api/get-lending-pools). **Use cases:** - Find the best yield across protocols - Compare risk parameters - Monitor positions across protocols - Build yield aggregators and dashboards ### 2. Transaction Building Build lending transactions for any supported protocol through a unified interface. Switching protocols means changing the `marketUid` — nothing else: ```bash # Deposit 1 WETH to Aave V3 curl "https://portal.1delta.io/v1/actions/lending/deposit\ ?marketUid=AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\ &amount=1000000000000000000&operator=$ACCOUNT" # The same call against Compound V3 curl "https://portal.1delta.io/v1/actions/lending/deposit\ ?marketUid=COMPOUND_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\ &amount=1000000000000000000&operator=$ACCOUNT" ``` Both return the same envelope: `actions.permissions` (approvals to mine first) and `actions.transactions` (the calldata to send). Amounts are raw integers in the token's smallest unit. See the [Quickstart](/quickstart) for the full execution flow. **Supported operations:** | Operation | Endpoint | | --- | --- | | Deposit — supply assets to earn yield | [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) | | Withdraw — remove supplied assets | [`/v1/actions/lending/withdraw`](/1delta-api/lending-withdraw) | | Borrow — take loans against collateral | [`/v1/actions/lending/borrow`](/1delta-api/lending-borrow) | | Repay — pay back borrowed assets | [`/v1/actions/lending/repay`](/1delta-api/lending-repay) | --- ## Composer Contract For advanced use cases, 1delta provides the **Composer** contract - a smart contract that can execute complex multi-step operations atomically. The Composer enables: - **Batched operations** - Multiple actions in one transaction - **Flash loan integration** - Borrow without collateral for atomic operations - **Cross-protocol operations** - Interact with multiple protocols atomically - **Looping** - Create leveraged positions in a single transaction You rarely encode Composer calls yourself — the action endpoints return the encoded calldata ready to send. See the [Composer entry point](/smart-contract-api/entrypoint) for the on-chain interface, and [Looping](/looping) for what these operations do under the hood. --- ## Supported Protocols 185 protocol deployments across 47 chains are supported, including the Aave, Compound, Morpho, Silo, Euler, Fluid, Spark and ZeroLend families. The list changes as deployments are added, so read it from the API rather than from a table: ```bash curl "https://portal.1delta.io/v1/data/lender-ids" ``` Note that a protocol usually has several deployments with distinct ids — `AAVE_V3`, `AAVE_V3_PRIME`, `AAVE_V3_ETHER_FI` and `AAVE_V3_HORIZON` are four separate markets with different rates and risk parameters. See [Market identifiers](/market-identifiers). --- ## Next Steps - [Quickstart](/quickstart) - Four calls from nothing to a mined transaction - [Market identifiers](/market-identifiers) - marketUid, lender ids, units - [Looping](/looping) - Learn how to create leveraged positions - [Example Operations](/smart-contract-api/example-operations/leverage) - View code examples --- ### Looping Source: https://docs.1delta.io/looping ## Looping In Crypto Looping (also known as leveraging or recursive borrowing) is a strategy that enables investors to amplify their exposure to digital assets by using lending protocols. It works by depositing collateral, borrowing against it, and reinvesting the borrowed funds to increase the position size. For example, if you have $1,000 worth of ETH and want 3x exposure, you would: 1. Deposit $1,000 ETH as collateral 2. Borrow ~$800 worth of stablecoins (at 80% LTV) 3. Swap stablecoins back to ETH 4. Deposit the new ETH as additional collateral 5. Repeat until reaching 3x exposure (~$3,000 ETH collateral, ~$2,000 debt) The key metric to monitor is the **health factor** - a measure of how close your position is to liquidation. When the health factor drops below 1, the position becomes eligible for liquidation. --- ## Looping In DeFi (The Manual Way) Opening a leveraged position manually in DeFi is a tedious, multi-step process. Here's what it takes to open a 4x leveraged ETH position starting with $1,000: ### Round 1 1. Approve ETH spending 2. Supply **$1,000 ETH** to Aave 3. Borrow **$800 USDC** 4. Approve USDC for swap 5. Swap $800 USDC → ETH (~$800 ETH) 6. Supply **$800 ETH** to Aave ### Round 2 1. Borrow **$640 USDC** 2. Approve USDC for swap 3. Swap $640 USDC → ETH (~$640 ETH) 4. Supply **$640 ETH** to Aave ### Round 3 1. Borrow **$512 USDC** 2. Approve USDC for swap 3. Swap $512 USDC → ETH (~$512 ETH) 4. Supply **$512 ETH** to Aave *...continue until target leverage is reached...* [Final Position (22+ transactions later)] | | | |---|---| | **Total Collateral** | ~$4,000 ETH | | **Total Debt** | ~$3,000 USDC | | **Leverage** | 4x | **Problems with manual looping:** - **22+ transactions** required for a single position - **High gas costs** - each transaction costs gas - **Price movement risk** - ETH price can change between transactions - **Time consuming** - takes 30+ minutes to execute - **Error prone** - easy to make mistakes in the process --- ## How 1delta Automates The Flow 1delta reduces the entire looping process to a **single atomic transaction** by leveraging flash loans. Here's how it works: [Final Position (achieved atomically)] | | | |---|---| | **Total Collateral** | $4,000 ETH | | **Total Debt** | $3,000 USDC | | **Leverage** | 4x | ### The Flash Loan Advantage Flash loans allow borrowing any amount without collateral, as long as the loan is repaid within the same transaction. 1delta uses this to: 1. **Borrow the full leverage amount upfront** via flash loan 2. **Execute all swaps and deposits** in one transaction 3. **Borrow from the lending protocol** to repay the flash loan 4. **Complete atomically** - if any step fails, everything reverts ### Architecture Flow Under the hood, the 1delta Composer orchestrates all participants in a single call — sourcing liquidity via a flash loan provider, routing through a DEX for token swaps, and interacting with the lending protocol for deposits and borrows. --- ## Comparison: Manual vs 1delta | Aspect | Manual Looping | 1delta Looping | |--------|---------------|----------------| | **Transactions** | 22+ | 1 | | **Gas Cost** | ~$200+ | ~$40 | | **Execution Time** | 30+ minutes | Single block | | **Price Risk** | High (price moves between txs) | None (atomic) | | **Partial Execution** | Possible | Impossible | | **Complexity** | High | Low | --- ## Doing this through the API Each operation below is one HTTP call that returns signable calldata. Omit `account` to get a quote without building anything; include it to get the transaction. ```bash # Price a 1,000 USDC-debt leveraged WETH position — quote only, no wallet needed curl "https://portal.1delta.io/v1/actions/loop/leverage\ ?marketUidIn=AAVE_V3:1:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\ &marketUidOut=AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\ &debtAmount=1000000000&slippage=50" ``` `marketUidIn` is the **debt** side and `marketUidOut` the **collateral** side. `slippage` is in basis points (`50` = 0.5%). Adding `&account=0x…` populates `actions` with `permissions` (approvals and borrow delegations to mine first) and `alternatives` (competing aggregator routes, best output first — execute exactly one). The full execution flow is in the [Quickstart](/quickstart). | Operation | Endpoint | | --- | --- | | Open a leveraged position | [`/v1/actions/loop/leverage`](/1delta-api/leverage-loop) | | Close a position | [`/v1/actions/loop/close`](/1delta-api/close-margin-position) | | Swap collateral | [`/v1/actions/loop/collateral-swap`](/1delta-api/collateral-swap) | | Swap debt | [`/v1/actions/loop/debt-swap`](/1delta-api/debt-swap) | | Migrate across lenders | [`/v1/actions/loop/migrate`](/1delta-api/loop-migrate) | | Safe leverage range for a pair | [`/v1/data/loop/range/leverage`](/1delta-api/max-leverage-range) | --- ## Supported Operations 1delta supports various looping-related operations: ### Opening Positions (Leverage) Create leveraged long or short positions in a single transaction. → See [Leverage Example](/smart-contract-api/example-operations/leverage) ### Closing Positions Unwind your leveraged position atomically by repaying debt and withdrawing collateral. → See [Close Example](/smart-contract-api/example-operations/close) ### Collateral Swaps Change your collateral type without closing the position (e.g., ETH → WBTC). → See [Collateral Swap Example](/smart-contract-api/example-operations/collateral-swap) ### Debt Swaps Change your debt type without affecting collateral (e.g., USDC → USDT). → See [Debt Swap Example](/smart-contract-api/example-operations/debt-swap) ### Protocol Migration Move your entire position from one protocol to another in a single transaction. → See [Migration Example](/smart-contract-api/example-operations/migration) --- ## Risk Considerations When using looping strategies, be aware of: 1. **Liquidation Risk** - If collateral value drops or debt value rises, your position may be liquidated 2. **Smart Contract Risk** - Lending protocols and DEXs carry smart contract risk 3. **Oracle Risk** - Price oracle failures can trigger unexpected liquidations 4. **Interest Rate Risk** - Variable borrow rates can increase over time Always monitor your **health factor** and maintain adequate buffer above 1.0. --- ### Market identifiers Source: https://docs.1delta.io/market-identifiers # Market identifiers Almost every endpoint addresses a lending market with a **`marketUid`**. Getting this string right is most of the work of integrating. ## Format ``` lender:chainId:address ``` ``` AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 │ │ └─ the underlying asset, not the receipt token │ └─── EVM chain id, decimal └─────────── protocol identifier, upper snake case ``` | Segment | Rules | | --- | --- | | `lender` | Upper snake case, from the `LenderId` set. `AAVE_V3`, not `aave-v3`, `Aave V3`, or `aaveV3`. | | `chainId` | Decimal chain id. `1` for Ethereum, `8453` for Base. | | `address` | Case-insensitive hex. Responses return it lowercase; you may send it checksummed. | ### Which address? The last segment is **not** always the token users hold. It depends on the protocol's own model: | Lender family | `address` is | | --- | --- | | Aave V2/V3/V4, Morpho, Compound V3 | the underlying asset (e.g. WETH) | | Compound V2 family | the cToken | | Init Capital | the pool | Do not construct a `marketUid` by hand from a token address and hope. Read it from a `/v1/data/lending/pools` response, where every item carries its own `marketUid` verbatim. ## Lender ids 185 protocol identifiers are supported. The canonical list is available three ways: ```bash curl "https://portal.1delta.io/v1/data/lender-ids" ``` ```json { "success": true, "data": ["AAVE_V3", "AAVE_V3_PRIME", "AAVE_V2", "SPARK", "ZEROLEND", "..."], "actions": null } ``` It is also published as the **`LenderId`** schema in [`openapi.json`](https://docs.1delta.io/openapi.json), so a generated client gets it as a typed enum, and listed in full in [`llms-full.txt`](https://docs.1delta.io/llms-full.txt). Many protocols have several deployments with distinct ids — `AAVE_V3`, `AAVE_V3_PRIME`, `AAVE_V3_ETHER_FI` and `AAVE_V3_HORIZON` are four separate markets with different rates and risk parameters. Treat them as unrelated. ## Chain ids 47 chains are supported. Chain ids are sent and returned as **decimal strings**, not numbers — `"1"`, not `1`. ```bash curl "https://portal.1delta.io/v1/data/chains" ``` ```json { "success": true, "data": { "items": [ { "chainId": "1", "name": "Ethereum" }, { "chainId": "10", "name": "OP" }, { "chainId": "8453", "name": "Base" } ] }, "actions": null } ``` Published as the **`ChainId`** schema in the spec, with each value's chain name attached. ## Amounts Every amount crossing the API is a **raw integer in the token's smallest unit, encoded as a string**: | Intent | Send | | --- | --- | | 1 WETH (18 decimals) | `"1000000000000000000"` | | 10 USDC (6 decimals) | `"10000000"` | | 0.5 WBTC (8 decimals) | `"50000000"` | Decimals come from the market data (`decimals` on the asset). Never send a human-readable decimal string — `"1.0"` is not a valid amount. Rates, by contrast, are returned as human-scaled **percentages** (`1.416…` = 1.42% APR), and ratios such as `utilization` and `ltv` are fractions between 0 and 1. ## Basis points `slippage` and similar tolerances are in **basis points**: | Value | Meaning | | --- | --- | | `1` | 0.01% | | `50` | 0.5% | | `100` | 1% | Passing `0.5` expecting half a percent gives you 0.005% and a reverting transaction. ## Related - [Quickstart](/quickstart) — the four-call integration path - [Errors & retries](/errors) --- ### Quickstart Source: https://docs.1delta.io/quickstart # Quickstart Four HTTP calls take you from nothing to a mined deposit. Every request below is real and runnable as-is — no SDK, no API key, no wallet connection needed until the last step. [There is no 1delta SDK] The API is plain HTTP + JSON. Use `fetch`, `curl`, `requests`, or anything else that speaks HTTP. Any code you see referencing an `onedelta` or `@1delta/sdk` package is not real. ## The shape of every response Before anything else, learn the envelope — it is identical on all 100+ endpoints. ```json { "success": true, "data": { }, "actions": { "transactions": [], "permissions": [] } } ``` | Field | Meaning | | --- | --- | | `data` | Information: market data, quotes, simulations, positions. `null` when an endpoint only produces calldata. | | `actions` | Work for you to do on-chain. `null` on every `/v1/data/*` endpoint. | | `actions.permissions` | Approvals that must be **mined first**. Already filtered against on-chain state, so anything returned is genuinely missing. | | `actions.transactions` | The transactions to send after the approvals. | | `actions.alternatives` | Present on loop and swap endpoints: competing DEX routes, best output first. **Pick exactly one.** | On failure: ```json { "success": false, "error": { "code": "MISSING_PARAM", "message": "marketUid is required" } } ``` Branch on `success`, never on the HTTP status code — see [Errors & retries](/errors). --- ## 1. Find a market Markets are addressed by a **`marketUid`**, formatted `lender:chainId:address`. List the pools on a chain for one lender: ```bash curl "https://portal.1delta.io/v1/data/lending/pools?chainId=1&lender=AAVE_V3" ``` ```json { "success": true, "data": { "start": 0, "count": 45, "items": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "chainId": "1", "lenderKey": "AAVE_V3", "name": "Aave V3 WETH", "depositRate": 1.41624773, "variableBorrowRate": 2.0744452, "utilization": 0.8005563978698457, "totalDepositsUsd": 4033189395.3983254, "totalLiquidityUsd": 705855814.4854279 } ] }, "actions": null } ``` Rates are **percentages** (`1.416…` is 1.42% APR), and `utilization` is a fraction between 0 and 1. Drop the `lender` parameter to compare every protocol on the chain at once — that comparison is the whole point of the aggregation layer, and the response shape is identical for all 185 of them. ## 2. Build the transaction Pass the `marketUid`, a raw on-chain `amount`, and the address that will sign: ```bash curl "https://portal.1delta.io/v1/actions/lending/deposit\ ?marketUid=AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\ &amount=1000000000000000000\ &operator=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" ``` `amount` is always in the token's smallest unit — `1000000000000000000` is 1 WETH at 18 decimals. Never send a decimal string. ```json { "success": true, "data": { "simulation": { "pre": { "healthFactor": 1000000000000000000, "borrowCapacity": 0 }, "post": { "healthFactor": 1000000000000000000, "borrowCapacity": 1499.1354 } } }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa960450000000000000000000000000000000000000000000000000000000000000000", "value": "0" } ], "permissions": [ { "to": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "data": "0x095ea7b300000000000000000000000087870bca3f3fd6335c3f4ce8392d69350b4fa4e20000000000000000000000000000000000000000000000000de0b6b3a7640000", "value": "0", "description": "Approve for AAVE_V3", "type": "ERC20" } ] } } ``` The API **never signs and never broadcasts**. It hands you calldata; sending it is your job. ## 3. Execute, in order `permissions` first — each one mined — then the entries in `transactions`. Sending the deposit before the approval is mined is the single most common integration bug, and it reverts. ```ts const BASE = "https://portal.1delta.io"; const res = await fetch( `${BASE}/v1/actions/lending/deposit?` + new URLSearchParams({ marketUid: "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", amount: "1000000000000000000", operator: account.address, }) ); const body = await res.json(); if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`); const client = createWalletClient({ account, chain: mainnet, transport: http() }); // Approvals must be mined before the action transaction is sent. for (const permission of body.actions.permissions ?? []) { const hash = await client.sendTransaction({ to: permission.to, data: permission.data, value: BigInt(permission.value), }); await client.waitForTransactionReceipt({ hash }); } for (const tx of body.actions.transactions ?? []) { await client.sendTransaction({ to: tx.to, data: tx.data, value: BigInt(tx.value), }); } ``` `to`, `data` and `value` are already encoded. Pass them straight through — do not re-encode, re-pack, or "fix" the calldata. ## 4. Read the position back ```bash curl "https://portal.1delta.io/v1/data/lending/user-positions\ ?chainId=1&account=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" ``` --- ## Quote first, then build Loop and swap endpoints have two modes, selected by whether you send `account`: | `account` | Result | | --- | --- | | omitted | **Quote only.** `data.quotes` holds routes and price impact; `actions` is `null`. Nothing is built. | | provided | **Full build.** `actions` is populated with calldata ready to send. | So you can price a leveraged position without a wallet: ```bash curl "https://portal.1delta.io/v1/actions/loop/leverage\ ?marketUidIn=AAVE_V3:1:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48\ &marketUidOut=AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\ &debtAmount=1000000000&slippage=50" ``` `marketUidIn` is the **debt** side, `marketUidOut` the **collateral** side. `slippage` is in basis points — `50` means 0.5%. When you add `account`, the response carries `actions.alternatives`: several aggregator routes, sorted best-output-first. Execute **one**. Sending two is sending the position twice. --- ## Rules that will save you a debugging session 1. **Branch on `success`,** not on the HTTP status. A missing parameter currently surfaces as `502`, not `400`. 2. **Amounts are raw integers as strings.** `10 USDC` is `"10000000"`, not `"10"`. 3. **Chain ids are decimal strings.** `"1"`, not `1`. 4. **Lender ids are upper snake case.** `AAVE_V3`, never `aave-v3` — see [Market identifiers](/market-identifiers). 5. **`slippage` is basis points.** `50` = 0.5%. Passing `0.5` means 0.005%, and your transaction will revert. 6. **Approvals before actions**, each one mined. 7. **Exactly one of `alternatives`.** 8. **Quotes go stale.** Rates and routes move per block. Build, then send promptly; re-request rather than reusing a quote from minutes ago. --- ## Feeding this API to a coding agent The endpoint pages on this site render their parameters and schemas in the browser, so fetching the HTML does not reveal them. Point tooling at these instead — they are static, complete, and need no JavaScript: | File | Contents | | --- | --- | | [`/llms.txt`](https://docs.1delta.io/llms.txt) | Index of every page and endpoint, ~16 KB. | | [`/llms-full.txt`](https://docs.1delta.io/llms-full.txt) | Every endpoint, parameter, field and example as plain text. | | [`/openapi.json`](https://docs.1delta.io/openapi.json) | OpenAPI 3.1 — generate a typed client from it. | ## Next - [Market identifiers](/market-identifiers) — `marketUid`, lender ids, chain ids - [Errors & retries](/errors) — codes, status mismatches, backoff - [Looping](/looping) — what the leverage endpoints do under the hood - [API reference](/api) — all 106 endpoints --- ### across Source: https://docs.1delta.io/smart-contract-api/bridge/across ## Across Bridge [Operations](../operations.md) → [External Call Operations](../external-call.md) → [Bridge Operations](./bridge.md) → Across Bridge _(Call Forwarder)_ Across is a cross-chain bridge protocol optimized for fast and efficient asset transfers. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------- | | 0 | 20 | spokePool | | 20 | 20 | depositor | | 40 | 20 | inputTokenAddress | | 60 | 32 | receivingAssetId | | 92 | 16 | amount | | 108 | 16 | FixedFee | | 124 | 4 | FeePercentage | | 128 | 4 | destinationChainId | | 132 | 32 | receiver | | 164 | 2 | message.length: msgLen | | 166 | msgLen | message | ### Parameter Details - **`spokePool`**: Across spoke pool contract address (20 bytes) - **`depositor`**: Address making the deposit (20 bytes) - **`inputTokenAddress`**: Address of the input token (20 bytes) - **`receivingAssetId`**: Asset ID on destination chain (32 bytes) - **`amount`**: Amount to bridge (16 bytes). High bit flag indicates using contract balance if amount = 0 - **`FixedFee`**: Fixed fee for the bridge (16 bytes) - **`FeePercentage`**: Fee percentage in basis points (4 bytes) - **`destinationChainId`**: Destination chain ID (4 bytes) - **`receiver`**: Receiver address on destination chain (32 bytes) - **`message`**: Optional message to include with the bridge (variable length) ### Encoding Example ```solidity bytes memory acrossBridge = abi.encodePacked( uint8(ComposerCommands.BRIDGING), uint8(BridgeIds.ACROSS), address(spokePool), // Across spoke pool address(depositor), // depositor address address(inputToken), // input token address bytes32(receivingAssetId), // destination asset ID uint128(amount), // amount to bridge uint128(fixedFee), // fixed fee uint32(feePercentage), // fee percentage uint32(destinationChainId), // destination chain bytes32(abi.encodePacked(receiver)), // receiver address uint16(message.length), // message length message // message bytes ); ``` ## Complete Usage Example **Important**: Across bridge operations must be executed through the Call Forwarder. Here's the complete calling structure: ```solidity // 1. Create Across bridge operation for Call Forwarder bytes memory acrossOp = abi.encodePacked( uint8(ComposerCommands.BRIDGING), uint8(BridgeIds.ACROSS), address(acrossSpokePool), // Across spoke pool contract address(msg.sender), // depositor address address(USDC), // input token (USDC) bytes32(destinationAssetId), // destination asset ID uint128(amountToBridge), // amount to bridge uint128(fixedBridgeFee), // fixed fee for bridging uint32(fee), // fee percentage uint32(destinationChainId), // destination chain ID bytes32(abi.encodePacked(receiver)), // receiver address uint16(message.length), // message length message // optional message bytes ); // 2. Wrap in EXT_CALL to Call Forwarder bytes memory callForwarderOp = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(callForwarder), // Call Forwarder address uint128(0), // No native fee needed for Across uint16(acrossOp.length), // Bridge operation length acrossOp // Bridge operation data ); // 3. Execute on main composer composer.deltaCompose(callForwarderOp); ``` --- ### bridge Source: https://docs.1delta.io/smart-contract-api/bridge/bridge ## BRIDGING Operations [Operations](../operations.md) → [External Call Operations](../external-call.md) → Bridge Operations _(Call Forwarder)_ Execute cross-chain bridge operations through supported bridge protocols. ### Supported Bridges | Bridge | ID | Description | | ---------------------------- | ------ | --------------------------- | | [Stargate V2](./stargate.md) | `0x00` | Stargate V2 bridge protocol | | [Across](./across.md) | `0x0A` | Across bridge protocol | #### `BridgeIds` Enum | Value | Name | Description | | ------ | ------------- | --------------------------- | | `0x00` | `STARGATE_V2` | Stargate V2 bridge protocol | | `0x0A` | `ACROSS` | Across bridge protocol | ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------------- | | 0 | 1 | bridgeId `uint8` | | 1 | Variable | bridge-specific parameters | ### Encoding Example ```solidity bytes memory bridgeOp = abi.encodePacked( uint8(ComposerCommands.BRIDGING), uint8(BridgeIds.STARGATE_V2), // Stargate V2 specific parameters... ); ``` ## Usage Context **Important**: Bridge operations can only be executed through the Call Forwarder and require a two-layer calling structure: ### Example ```solidity // 1. Create the bridge operation for Call Forwarder bytes memory bridgeOp = abi.encodePacked( uint8(ComposerCommands.BRIDGING), uint8(BridgeIds.STARGATE_V2), // ... bridge parameters ); // 2. Wrap in EXT_CALL to Call Forwarder bytes memory fullCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(callForwarder), // Call Forwarder address uint128(0), // No native value for Call Forwarder uint16(bridgeOp.length), // Bridge operation length bridgeOp // Bridge operation data ); // 3. Execute on main composer composer.deltaCompose(fullCall); ``` --- ### stargate Source: https://docs.1delta.io/smart-contract-api/bridge/stargate ## Stargate V2 Bridge [Operations](../operations.md) → [External Call Operations](../external-call.md) → [Bridge Operations](./bridge.md) → Stargate V2 Bridge _(Call Forwarder)_ Stargate V2 is a cross-chain bridge protocol that enables seamless asset transfers across multiple blockchain networks. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ----------------------- | | 0 | 20 | tokenAddress | | 20 | 20 | stargate pool | | 40 | 4 | dstEid | | 44 | 32 | receiver | | 76 | 20 | refundReceiver | | 96 | 16 | amount | | 112 | 4 | slippage | | 116 | 16 | fee | | 132 | 1 | isBusMode | | 133 | 2 | composeMsg.length: cl | | 135 | 2 | extraOptions.length: el | | 137 | cl | composeMsg | | 137+cl | el | extraOptions | ### Parameter Details - **`tokenAddress`**: The address of the token to bridge (20 bytes) - **`stargate pool`**: The Stargate pool address for the token (20 bytes) - **`dstEid`**: Destination endpoint ID (4 bytes) - **`receiver`**: Receiver address on destination chain (32 bytes) - **`refundReceiver`**: Address to receive refunds (20 bytes) - **`amount`**: Amount to bridge (16 bytes). High bit flag indicates using contract balance if amount = 0 - **`slippage`**: Maximum allowed slippage in basis points (4 bytes) - **`fee`**: Native fee for the bridge transaction (16 bytes) - **`isBusMode`**: Boolean flag for bus mode (1 byte) - **`composeMsg`**: Optional composition message for cross-chain calls (variable length) - **`extraOptions`**: Additional options for the bridge (variable length) ### Encoding Example ```solidity bytes memory stargateBridge = abi.encodePacked( uint8(ComposerCommands.BRIDGING), uint8(BridgeIds.STARGATE_V2), address(tokenAddress), // token to bridge address(stargatePool), // Stargate pool uint32(dstEid), // destination chain ID bytes32(abi.encodePacked(receiver)), // receiver address address(refundReceiver), // refund receiver uint128(amount), // amount to bridge uint32(slippageBps), // slippage tolerance uint128(fee), // native fee uint8(isBusMode), // bus mode flag uint16(composeMsg.length), // compose message length uint16(extraOptions.length), // extra options length composeMsg, // compose message bytes extraOptions // extra options bytes ); ``` ## Complete Usage Example **Important**: Stargate V2 bridge operations must be executed through the Call Forwarder. Here's the complete calling structure: ```solidity // 1. Create Stargate V2 bridge operation for Call Forwarder bytes memory stargateOp = abi.encodePacked( uint8(ComposerCommands.BRIDGING), uint8(BridgeIds.STARGATE_V2), address(USDC), // token to bridge address(stargatePool), // Stargate pool uint32(destinationChainId), // destination endpoint ID bytes32(abi.encodePacked(receiver)), // receiver address address(msg.sender), // refund receiver uint128(amountToBridge), // amount to bridge uint32(slippage), // slippage tolerance uint128(bridgeFee), // native fee for bridge uint8(0), // bus mode (0 = regular) uint16(composeMsg.length), // compose message length uint16(extraOptions.length), // extra options length composeMsg, // compose message bytes extraOptions // extra options bytes ); // 2. Wrap in EXT_CALL to Call Forwarder bytes memory callForwarderOp = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(callForwarder), // Call Forwarder address uint128(bridgeFee), // Send native fee to Call Forwarder uint16(stargateOp.length), // Bridge operation length stargateOp // Bridge operation data ); // 3. Execute on main composer composer.deltaCompose(callForwarderOp); ``` --- ### entrypoint Source: https://docs.1delta.io/smart-contract-api/entrypoint # Contract Entry Point The 1delta protocol provides a single unified entry point for executing DeFi operations through our composer contracts. ## Main Entry Point: `deltaCompose(bytes)` ### Function Signature ```solidity function deltaCompose(bytes calldata data) external payable ``` The `deltaCompose` function is the primary interface for executing batched operations. It accepts compact, byte-encoded operation sequences that are processed atomically within a single transaction. ### Key Characteristics - **Atomic Execution**: All operations in a batch either succeed together or fail together - **Gas Efficient**: Compact encoding minimizes transaction costs - **Composable**: Operations can be chained and nested arbitrarily - **Stateless**: Other than the approval and entry flags, the contract is stateless - **Payable**: Can receive native tokens for operations requiring them ## Operation Encoding Structure ### Reference Enums For enum definitions used in the examples below, see: - [TransferIds](./transfers.md#transferids-enum) and [SweepType](./transfers.md#sweeptype-enum) ### Composer Commands Operations are categorized using the following command identifiers: ```typescript enum ComposerCommands { SWAPS; // swap paths EXT_CALL; // external calls (`deltaForwardCompose`) EXT_TRY_CALL; // external call with fallback (callForwarder only) LENDING; // any lending operation (deposit, borrow, withdraw, repay) TRANSFERS; // pulling, sending and approving PERMIT; // execute token or lender permit FLASH_LOAN; // execute flash loans on common targets ERC4626; // vault operations GEN_2025_SINGELTONS; // balancer V3 and Uniswap V4 operations BRIDGING; // bridge execution (callForwarder only) } ``` ### Encoding Format All operations follow a consistent encoding pattern: ``` [command: uint8][operation-specific data: bytes] ``` ## Composable Operation Flow ### Sequential Execution Operations are executed in the order they appear in the encoded data. ``` operation 1 -> operation 2 -> ... ``` ### Nested Operations Complex operations can contain sub-operations, enabling DeFi strategies: ``` Flash Loan Operation { Inner Operations: [ Swap Operation, Lending Operation, Transfer Operation ] } ``` ## Simple Example This example shows how to encode a simple transfer operation. The operation structure follows the standard pattern of `[command: uint8][operation-specific data: bytes]`. ### Operation Data Structure | Offset | Length (bytes) | Description | Value Example | | ------ | -------------- | ---------------- | ------------------ | | 0 | 1 | Command ID | `0x40` (TRANSFERS) | | 1 | 1 | Operation ID | `1` (SWEEP) | | 2 | 20 | Token address | `0xA0b8...` | | 22 | 20 | Receiver address | `0xd8dA...` | | 42 | 1 | Sweep type | `1` (AMOUNT) | | 43 | 16 | Amount (uint128) | `1000000` | ### Solidity Example ```solidity function transferTokens() external { address token = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address receiver = 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045; uint256 amount = 1000000; // Encode the transfer operation directly bytes memory transferOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), // 0x40 - Transfer command uint8(TransferIds.SWEEP), // 1 - SWEEP operation ID token, // Token address receiver, // Receiver address uint8(SweepType.AMOUNT), // 1 - AMOUNT sweep type uint128(amount) // Amount to transfer ); composer.deltaCompose(transferOp); } ``` ### TypeScript Example ```typescript function encodeTransfer(): `0x${string}` { const TRANSFERS = 0x40 // ComposerCommands.TRANSFERS const SWEEP = 1 // TransferIds.SWEEP const AMOUNT = 1 // SweepType.AMOUNT const tokenAddress = "0xA0b86a33E6441e88b5f6f1FcD8c7d4d0d9e4b8C3" const receiver = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" const amount = 1000000 return encodePacked(["uint8", "uint8", "address", "address", "uint8", "uint128"], [TRANSFERS, SWEEP, tokenAddress, receiver, AMOUNT, amount]) } ``` ### Development Note In practice, operations are most often created using helper libraries to avoid manual encoding: - **Solidity**: Use `CalldataLib` functions like `encodeSweep()` for complex operations - **TypeScript**: Use the 1delta SDK which provides high-level functions for operation creation Manual encoding is shown to demonstrate the underlying structure. --- ### close Source: https://docs.1delta.io/smart-contract-api/example-operations/close # Close Operation (Withdraw & Repay) This section provides a detailed guide for implementing the close operation, which allows users to exit leveraged positions efficiently. ## Overview The close operation enables users to exit a leveraged position by: 1. Withdrawing collateral assets 2. Swapping the withdrawn assets for the debt token 3. Repaying the outstanding debt 4. Refunding any excess assets to the user This process maintains capital efficiency by executing all operations within a single transaction using a flash loan wrapper. ## Example Scenario We'll demonstrate how to switch debt in a leveraged position on **Aave V3** without de-leveraging. Our example: - **Initial Position**: 3 WETH collateral with 8,000 USDC debt - **Operation**: Withdraw ~2 WETH, swap to USDC, repay debt - **Flash Loan Provider**: Morpho Blue (optimal for Ethereum and Base) - **Swap Provider**: 1inch Aggregation Router > **Important**: The mechainc has a fail-safe so that in case the swap does not return enough funds to repay the entire debt, it will only repay the available amounts. ## Implementation ### Integration Checklist - [ ] Protocol withdrawal permissions configured - [ ] Debt repayment approvals set - [ ] Swap quotes validated for sufficient output - [ ] Health factor monitoring implemented - [ ] Slippage protection configured - [ ] Gas optimization strategies applied - [ ] Error handling and fallback mechanisms - [ ] Position state tracking enabled ### Constants and Setup Define the necessary addresses and amounts for the operation: ```solidity // Core parameters uint256 USER_AMOUNT = 2.0e18; // Amount of WETH to swap // Protocol addresses address CALL_FORWARDER = 0xfCa1154C643C32638AEe9a43eeE7f377f515c801; // Default forwarder IComposer composer = IComposer(0x...); // 1delta composer // Aave V3 addresses address AAVE_V3_POOL = address(0x...); address AAVE_V3_USDC_V_TOKEN = address(0x...); // Variable debt token address AAVE_V3_A_TOKEN_WETH = address(0x...); // Collateral aToken // External protocols address oneInchAggregationRouter = address(0x111...); // Swap router address MORPHO_BLUE = address(0xbbb...); // Flash loan provider ``` ### Step 1: Repay Operation Configure the repayment of USDC debt to Aave V3. Setting the amount to `0` ensures we repay the minimum of received funds and outstanding debt. ```solidity bytes memory repay = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.REPAY), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(USDC), // Asset to repay uint128(0), // 0 = use all available funds address(user), // Beneficiary of the repayment uint8(2), // Variable rate mode address(AAVE_V3_USDC_V_TOKEN), // Variable debt token address(AAVE_V3_POOL) // Pool address ); // Safety sweep for excess funds bytes memory transferToUser = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDC), address(user), uint128(0) // Transfer any remaining balance ); // Combine operations bytes memory repayOperation = abi.encodePacked(repay, transferToUser); ``` ### Step 2: Withdraw Operation Withdraw collateral and distribute it between the swap forwarder and user. This approach eliminates an extra transfer step and ensures no dust remains. ```solidity // Withdraw entire collateral balance bytes memory withdraw = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.WITHDRAW), uint16(LenderIds.UP_TO_AAVE_V3 - 1), address(WETH), // Collateral asset uint128(0), // 0 = withdraw all address(COMPOSER_ADDRESS), // Initial receiver for splitting address(AAVE_V3_A_TOKEN_WETH), // aToken address address(AAVE_V3_POOL) ); // Transfer swap amount to forwarder bytes memory transferToForwarder = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(WETH), address(CALL_FORWARDER), uint128(USER_AMOUNT) // Exact amount for swap ); // Transfer remainder to user bytes memory transferToUser = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(WETH), address(user), uint128(0) // Transfer remaining balance ); // Combine operations bytes memory withdrawOperation = abi.encodePacked( withdraw, transferToForwarder, transferToUser ); ``` ### Step 3: Configure Approvals Set up one-time approvals for all protocols. The composer automatically approves maximum amounts, and subsequent calls skip redundant approvals to save gas. ```solidity // Approve Aave V3 for USDC repayment bytes memory approvePool = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), address(AAVE_V3_POOL) ); // Approve Morpho for WETH flash loan (uses transferFrom) bytes memory approveMorpho = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(WETH), address(MORPHO_BLUE) ); ``` ### Step 4: Meta Swap Configuration Set up the swap operation through the forwarder. This follows the pattern described in the [External Call](../external-call.md) documentation, but skips manual transfers since funds are already positioned. ```solidity // Configure 1inch router call bytes memory callForwarderCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(oneInchAggregationRouter), uint128(0), // No ETH value for ERC20 swap uint16(data.length), data // 1inch swap calldata ); // Approve 1inch to spend WETH bytes memory approve1inch = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(WETH), address(oneInchAggregationRouter) ); // Set slippage protection (expecting 8,000 USDC) uint256 amountExpected = 8000.0e6; bytes memory sweepAndCheckSlippage = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDC), address(receiver), uint8(SweepType.AMOUNT), amountExpected // Revert if less than expected ); // Combine swap operations callForwarderCall = abi.encodePacked( approve1inch, callForwarderCall, sweepAndCheckSlippage ); // Wrap in composer call bytes memory metaSwap = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(CALL_FORWARDER), // Must use forwarder at composer level uint128(0), uint16(callForwarderCall.length), callForwarderCall ); ``` ### Step 5: Assemble Complete Transaction Combine all operations within a flash loan wrapper for atomic execution: ```solidity uint128 amount = uint128(2.0e18); // Flash loan amount (2 WETH) // Inner operations: swap → repay → withdraw bytes memory innerOperation = abi.encodePacked( metaSwap, repayOperation, withdrawOperation ); // Wrap in flash loan bytes memory flashLoan = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(WETH), address(MORPHO_BLUE), amount, uint16(innerOperation.length + 1), uint8(0), // Morpho Blue pool ID 0 innerOperation ); // Place approvals outside flash loan callback for gas optimization bytes memory composerOps = abi.encodePacked( approvePool, approveMorpho, flashLoan ); // Execute the complete operation composer.deltaCompose(composerOps); ``` ## Key Considerations 1. **Permissions**: Ensure `ERC20(AAVE_V3_A_TOKEN_WETH).approve(...)` is called before execution 2. **Slippage Protection**: Always set minimum expected amounts to prevent unfavorable swaps 3. **Gas Optimization**: Keep operations outside the flash loan callback when possible 4. **Error Handling**: The transaction will revert if: - Insufficient collateral to withdraw - Swap returns less than debt amount - Flash loan cannot be repaid ## Related Documentation - [Margin Operations](../margin.md) - Architecture overview - [Flash Loan Operations](../flash-loan.md) - Provider details - [External Call Patterns](../external-call.md) - Swap integration - [Lending Operations](../lending.md) - Protocol interactions - [Approval Management](../transfers.md#approve-operation) - Permission setup --- ### collateral-swap Source: https://docs.1delta.io/smart-contract-api/example-operations/collateral-swap # Collateral Swap (Withdraw & Deposit) This guide covers collateral swaps, which allow users to exchange their collateral assets without closing positions or repaying debt. ## Overview Collateral swaps differ from leverage operations in one key way: you can withdraw your **entire** collateral balance. Since collateral balances change with each block due to interest accrual, the exact amount isn't always predictable when querying off-chain. This creates challenges when working with swap aggregators, which typically require exact input amounts for quotes. ## Example Scenario We'll demonstrate switching collateral on **Aave V3** from WETH to USDT while maintaining a leveraged position. The process involves: 1. Withdrawing WETH collateral 2. Swapping WETH to USDT via 1inch 3. Depositing USDT as new collateral We'll wrap this entire sequence in a [Flash Loan](../flash-loan.md) using **Morpho Blue** as the flash loan provider. **Starting Position:** - Collateral: 3 WETH - Debt: 8,000 USDC **Target:** - Convert 3 WETH to 12,000 USDT as new collateral --- ## Constants ```solidity // The collateral amount to exchange uint256 USER_AMOUNT = 3.0e18; // Default forwarder address address CALL_FORWARDER = 0xfCa1154C643C32638AEe9a43eeE7f377f515c801; // 1delta composer IComposer composer = IComposer(0x...); // Aave V3 pool address address AAVE_V3_POOL = address(0x...); // Aave V3 WETH collateral token address AAVE_V3_A_TOKEN_WETH = address(0x...); // 1inch aggregation router address oneInchAggregationRouter = address(0x111...); // Morpho Blue flash loan source address MORPHO_BLUE = address(0xbbb...); ``` --- ## Operation Sequence ### Integration Checklist - [ ] Collateral withdrawal permissions configured - [ ] New collateral deposit approvals set - [ ] Swap quotes validated for sufficient output - [ ] Health factor impact assessed - [ ] Slippage protection configured - [ ] Cross-protocol compatibility verified - [ ] Gas optimization strategies applied - [ ] Error handling and fallback mechanisms - [ ] Position value tracking enabled ### 1. Deposit New Collateral After receiving USDT from the swap, we deposit it into Aave V3. Setting the amount to `0` deposits whatever USDT balance the contract holds. **Important:** Ensure all required approvals are granted beforehand (see Approvals section). ```solidity bytes memory deposit = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.DEPOSIT), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(USDT), // Asset to deposit uint128(0), // 0 = deposit full contract balance address(user), // Deposit recipient address(AAVE_V3_POOL) // Aave V3 pool address ); ``` ### 2. Withdraw Original Collateral We withdraw the entire WETH collateral balance and split it between the swap operation and any remainder for the user. ```solidity bytes memory withdraw = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.WITHDRAW), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(WETH), // Asset to withdraw uint128(0), // 0 = withdraw full balance address(COMPOSER_ADDRESS), // Temporary recipient for splitting address(AAVE_V3_A_TOKEN_WETH), // Collateral token address address(AAVE_V3_POOL) // Aave V3 pool address ); // Send exact swap amount to forwarder bytes memory transferToForwarder = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(WETH), // Asset to transfer address(CALL_FORWARDER), // Recipient (swap forwarder) uint128(USER_AMOUNT) // Exact quoted amount ); // Send any remainder to user bytes memory transferToUser = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(WETH), // Asset to transfer address(user), // Recipient uint128(0) // Send remaining balance ); // Combine all withdrawal operations withdraw = abi.encodePacked( withdraw, transferToForwarder, transferToUser ); ``` ### 3. Approvals Required approvals for the operation to succeed: ```solidity // Approve Aave V3 pool to spend USDT for deposit bytes memory approvePool = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDT), // Asset to approve address(AAVE_V3_POOL) // Spender ); // Approve Morpho Blue to pull WETH for flash loan repayment bytes memory approveMorpho = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(WETH), // Asset to approve address(MORPHO_BLUE) // Spender ); ``` ### 4. Meta Swap Configuration The swap operation uses the external call pattern described in [External Call](../external-call.md): ```solidity // Configure the forwarder call to 1inch bytes memory callForwarderCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(oneInchAggregationRouter), // Target contract uint128(0), // No ETH value for ERC20 swap uint16(data.length), // Call data length data // 1inch swap call data ); // Approve 1inch to spend WETH bytes memory approve1inch = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(WETH), // Asset to approve address(oneInchAggregationRouter) // Spender ); // Verify minimum output and transfer to recipient uint256 amountExpected = 12000.0e6; // Expected USDT amount (6 decimals) bytes memory sweepAndCheckSlippage = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDT), // Asset to sweep address(receiver), // Final recipient uint8(SweepType.AMOUNT), amountExpected // Minimum required amount ); // Combine forwarder operations callForwarderCall = abi.encodePacked( approve1inch, callForwarderCall, sweepAndCheckSlippage ); // Create meta swap call through forwarder bytes memory metaSwap = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), callForwarderAddress, // Forwarder contract uint128(0), // No ETH value uint16(callForwarderCall.length), // Call data length callForwarderCall // Forwarder operations ); ``` --- ## Complete Operation Assembly Putting it all together with the flash loan wrapper: ```solidity uint128 flashLoanAmount = uint128(3.0e18); // Amount to flash loan // Inner operations executed within flash loan callback bytes memory innerOperation = abi.encodePacked( withdraw, // Withdraw WETH collateral metaSwap, // Swap WETH to USDT deposit // Deposit USDT as new collateral ); // Flash loan wrapper bytes memory flashLoan = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(WETH), // Flash loan asset address(MORPHO_BLUE), // Flash loan provider flashLoanAmount, // Flash loan amount uint16(innerOperation.length + 1), // Callback data length uint8(0), // Morpho Blue pool ID innerOperation // Operations to execute ); // Complete operation sequence bytes memory composerOps = abi.encodePacked( approvePool, // Pre-approve Aave pool approveMorpho, // Pre-approve Morpho Blue flashLoan // Execute flash loan with inner operations ); // Execute the complete collateral swap composer.deltaCompose(composerOps); ``` --- ## Key Considerations 1. **Exact Amounts:** When withdrawing the entire collateral balance, split transfers ensure the swap gets exactly the quoted amount while the user receives any remainder. 2. **Permissions:** The operation requires prior approval of the WETH collateral token: `IERC20(AAVE_V3_A_TOKEN_WETH).approve(composer, type(uint256).max)` 3. **Slippage Protection:** The sweep operation with `SweepType.AMOUNT` ensures you receive at least the expected minimum output from the swap. 4. **Gas Optimization:** Using the forwarder pattern eliminates unnecessary token transfers between operations. ## Related Documentation - [Margin Operations](../margin.md) - Architecture overview - [Flash Loan Operations](../flash-loan.md) - Provider details - [External Call Patterns](../external-call.md) - Swap integration - [Lending Operations](../lending.md) - Protocol interactions --- ### debt-swap Source: https://docs.1delta.io/smart-contract-api/example-operations/debt-swap # Debt Swap (Borrow & Repay) This guide covers debt swaps, which allow users to change their debt composition without closing positions or affecting collateral balances. ## Overview Debt swaps involve borrowing a new asset, swapping it for the currency needed to repay existing debt, then repaying the original debt. This maintains your leveraged position while switching between debt assets (e.g., from USDC debt to USDT debt). The entire operation is wrapped in a flash loan to ensure atomicity and capital efficiency. ## Example Scenario We'll demonstrate switching debt on **Aave V3** from USDC to USDT while maintaining the same collateral position. The process involves: 1. Flash loan USDT 2. Swap USDT to USDC via 1inch 3. Repay existing USDC debt 4. Borrow new USDT debt to repay flash loan 5. Refund any excess to user **Starting Position:** - Collateral: 3 WETH - Debt: 8,000 USDC **Target:** - Same collateral: 3 WETH - New debt: 8,000 USDT We'll use **Morpho Blue** as our flash loan provider for optimal rates. --- ## Constants ```solidity // The debt amount to swap uint256 DEBT_AMOUNT = 8000.0e6; // Default forwarder address address CALL_FORWARDER = 0xfCa1154C643C32638AEe9a43eeE7f377f515c801; // 1delta composer IComposer composer = IComposer(0x...); // Aave V3 pool address address AAVE_V3_POOL = address(0x...); // Aave V3 variable debt tokens address AAVE_V3_USDC_V_TOKEN = address(0x...); address AAVE_V3_USDT_V_TOKEN = address(0x...); // 1inch aggregation router address oneInchAggregationRouter = address(0x111...); // Morpho Blue flash loan source address MORPHO_BLUE = address(0xbbb...); ``` --- ## Operation Sequence ### Integration Checklist - [ ] Debt delegation permissions configured - [ ] Protocol borrowing approvals set - [ ] Swap quotes validated for sufficient output - [ ] Health factor impact assessed - [ ] Slippage protection configured - [ ] Cross-protocol compatibility verified - [ ] Gas optimization strategies applied - [ ] Error handling and fallback mechanisms - [ ] Position rate tracking enabled ### 1. Repay Existing Debt After receiving USDC from the swap, we repay the existing USDC debt. Setting amount to `0` repays up to the contract's balance or total debt, whichever is smaller. **Important:** Ensure all required approvals are granted beforehand (see Approvals section). ```solidity bytes memory repay = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.REPAY), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(USDC), // Asset to repay uint128(0), // 0 = repay up to balance/debt address(user), // Debt owner uint8(2), // Variable rate mode address(AAVE_V3_USDC_V_TOKEN), // Variable debt token address(AAVE_V3_POOL) // Aave V3 pool address ); // Refund any excess USDC to user bytes memory transferToUser = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDC), // Asset to transfer address(user), // Recipient uint128(0) // Send remaining balance ); // Combine repay with refund bytes memory repayAndRefund = abi.encodePacked( repay, transferToUser ); ``` ### 2. Borrow New Debt We borrow exactly the flash loan amount (plus any fees) in USDT. The borrowed funds go directly to the forwarder to minimize transfers. ```solidity bytes memory borrow = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.BORROW), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(USDT), // Asset to borrow uint128(DEBT_AMOUNT), // Flash loan repayment amount address(CALL_FORWARDER), // Send directly to forwarder uint8(2), // Variable rate mode address(AAVE_V3_POOL) // Aave V3 pool address ); ``` ### 3. Approvals Required approvals for the operation to succeed: ```solidity // Approve Aave V3 pool to spend USDC for debt repayment bytes memory approvePool = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), // Asset to approve address(AAVE_V3_POOL) // Spender ); // Approve Morpho Blue to pull USDT for flash loan repayment bytes memory approveMorpho = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDT), // Asset to approve address(MORPHO_BLUE) // Spender ); ``` ### 4. Meta Swap Configuration The swap operation converts borrowed USDT to USDC for debt repayment. Since funds are already at the forwarder from the borrow operation, we skip manual transfers. ```solidity // Configure the forwarder call to 1inch bytes memory callForwarderCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(oneInchAggregationRouter), // Target contract uint128(0), // No ETH value for ERC20 swap uint16(data.length), // Call data length data // 1inch swap call data ); // Approve 1inch to spend USDT bytes memory approve1inch = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDT), // Asset to approve address(oneInchAggregationRouter) // Spender ); // Verify minimum output and transfer to composer uint256 amountExpected = 8000.0e6; // Expected USDC amount bytes memory sweepAndCheckSlippage = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDC), // Asset to sweep address(composer), // Send to composer for repay uint8(SweepType.AMOUNT), amountExpected // Minimum required amount ); // Combine forwarder operations callForwarderCall = abi.encodePacked( approve1inch, callForwarderCall, sweepAndCheckSlippage ); // Create meta swap call through forwarder bytes memory metaSwap = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(CALL_FORWARDER), // Forwarder contract uint128(0), // No ETH value uint16(callForwarderCall.length), // Call data length callForwarderCall // Forwarder operations ); ``` --- ## Complete Operation Assembly Putting it all together with the flash loan wrapper: ```solidity uint128 flashLoanAmount = uint128(DEBT_AMOUNT); // Amount to flash loan // Inner operations executed within flash loan callback bytes memory innerOperation = abi.encodePacked( borrow, // Borrow USDT and send to forwarder metaSwap, // Swap USDT to USDC via forwarder repayAndRefund // Repay USDC debt and refund excess ); // Flash loan wrapper bytes memory flashLoan = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(USDT), // Flash loan asset address(MORPHO_BLUE), // Flash loan provider flashLoanAmount, // Flash loan amount uint16(innerOperation.length + 1), // Callback data length uint8(0), // Morpho Blue pool ID innerOperation // Operations to execute ); // Complete operation sequence bytes memory composerOps = abi.encodePacked( approvePool, // Pre-approve Aave pool for USDC approveMorpho, // Pre-approve Morpho Blue for USDT flashLoan // Execute flash loan with inner operations ); // Execute the complete debt swap composer.deltaCompose(composerOps); ``` --- ## Key Considerations 1. **Debt Delegation:** The operation requires prior debt delegation approval: `IDebtToken(AAVE_V3_USDT_V_TOKEN).approveDelegation(composer, type(uint256).max)` 2. **Flash Loan Fees:** The borrow amount must account for any flash loan fees to ensure complete repayment. 3. **Slippage Protection:** The sweep operation with `SweepType.AMOUNT` ensures you receive sufficient USDC to repay the debt. 4. **Gas Optimization:** - Approvals are placed outside the flash loan callback to reduce callback data size - Direct transfers to the forwarder eliminate unnecessary token movements - One-time approvals with maximum amounts reduce future gas costs 5. **Atomic Execution:** The entire operation succeeds or fails as one transaction, preventing partial execution risks. 6. **Excess Handling:** Any excess USDC from the swap is automatically refunded to the user, ensuring no funds are stuck. ## Related Documentation - [Margin Operations](../margin.md) - Architecture overview - [Flash Loan Operations](../flash-loan.md) - Provider details - [External Call Patterns](../external-call.md) - Swap integration - [Lending Operations](../lending.md) - Protocol interactions --- ### leverage Source: https://docs.1delta.io/smart-contract-api/example-operations/leverage # Leveraging (Borrow & Deposit) This guide covers leveraging operations, which allow users to increase their position size by borrowing against deposited collateral and reinvesting the borrowed funds. ## Overview Leveraging involves borrowing assets against your collateral, swapping the borrowed assets for more collateral, then depositing the additional collateral. This amplifies your exposure to the collateral asset while maintaining efficient capital usage through flash loans. The entire operation is atomic, ensuring that either all steps succeed or the transaction reverts completely. ## Example Scenario We'll demonstrate creating a leveraged WETH position on **Aave V3** using borrowed USDC. The process involves: 1. Flash loan USDC 2. Swap USDC to WETH via 1inch 3. Deposit user's ETH + swapped WETH as collateral 4. Borrow USDC to repay flash loan **Starting Capital:** - User contribution: 1 ETH **Target Position:** - Total collateral: 3 WETH (1 from user + 2 from leverage) - Debt: 8,000 USDC We'll use **Morpho Blue** as our flash loan provider for optimal rates. --- ## Constants ```solidity // User's initial contribution uint256 USER_AMOUNT = 1.0e18; // Default forwarder address address CALL_FORWARDER = 0xfCa1154C643C32638AEe9a43eeE7f377f515c801; // 1delta composer IComposer composer = IComposer(0x...); // Aave V3 pool address address AAVE_V3_POOL = address(0x...); // 1inch aggregation router address oneInchAggregationRouter = address(0x111...); // Morpho Blue flash loan source address MORPHO_BLUE = address(0xbbb...); // WETH contract address address WETH = address(0xC02...); ``` --- ## Operation Sequence ### Integration Checklist - [ ] Protocol permissions configured - [ ] Token approvals set - [ ] Health factor validated - [ ] Slippage parameters configured - [ ] Gas optimization applied - [ ] Error handling implemented - [ ] Position monitoring enabled ### 1. Pull User Funds First, we transfer the user's ETH and efficiently convert it to WETH in a single operation. ```solidity bytes memory transferIn = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.TRANSFER_FROM), address(0), // Transfer ETH (address(0)) address(WETH), // Convert to WETH directly uint128(USER_AMOUNT) // Amount: 1 ETH ); ``` ### 2. Deposit Total Collateral We deposit all available WETH (user's contribution plus swapped amount) into Aave V3. Setting amount to `0` deposits the contract's entire WETH balance. **Important:** Ensure all required approvals are granted beforehand (see Approvals section). ```solidity bytes memory deposit = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.DEPOSIT), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(WETH), // Asset to deposit uint128(0), // 0 = deposit entire balance address(user), // Deposit recipient address(AAVE_V3_POOL) // Aave V3 pool address ); ``` ### 3. Borrow Against Collateral We borrow exactly the flash loan repayment amount (plus any fees) in USDC. The borrowed funds go directly to the forwarder to minimize transfers. ```solidity bytes memory borrow = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.BORROW), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(USDC), // Asset to borrow uint128(8000.0e6), // Flash loan repayment amount address(CALL_FORWARDER), // Send directly to forwarder uint8(2), // Variable rate mode address(AAVE_V3_POOL) // Aave V3 pool address ); ``` ### 4. Approvals Required approvals for the operation to succeed: ```solidity // Approve Aave V3 pool to spend WETH for collateral deposit bytes memory approvePool = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(WETH), // Asset to approve address(AAVE_V3_POOL) // Spender ); // Approve Morpho Blue to pull USDC for flash loan repayment bytes memory approveMorpho = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), // Asset to approve address(MORPHO_BLUE) // Spender ); ``` ### 5. Meta Swap Configuration The swap operation converts flash-loaned USDC to WETH for additional collateral. Since funds are already at the forwarder from the flash loan, we skip manual transfers. ```solidity // Configure the forwarder call to 1inch bytes memory callForwarderCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(oneInchAggregationRouter), // Target contract uint128(0), // No ETH value for ERC20 swap uint16(data.length), // Call data length data // 1inch swap call data ); // Approve 1inch to spend USDC bytes memory approve1inch = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), // Asset to approve address(oneInchAggregationRouter) // Spender ); // Verify minimum output and transfer to composer uint256 amountExpected = 2.0e18; // Expected 2 WETH from swap bytes memory sweepAndCheckSlippage = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(WETH), // Asset to sweep address(composer), // Send to composer for deposit uint8(SweepType.AMOUNT), amountExpected // Minimum required amount ); // Combine forwarder operations callForwarderCall = abi.encodePacked( approve1inch, callForwarderCall, sweepAndCheckSlippage ); // Create meta swap call through forwarder bytes memory metaSwap = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(CALL_FORWARDER), // Forwarder contract uint128(0), // No ETH value uint16(callForwarderCall.length), // Call data length callForwarderCall // Forwarder operations ); ``` --- ## Complete Operation Assembly Putting it all together with the flash loan wrapper: ```solidity uint128 flashLoanAmount = uint128(8000.0e6); // USDC amount to flash loan // Inner operations executed within flash loan callback bytes memory innerOperation = abi.encodePacked( metaSwap, // Swap flash-loaned USDC to WETH deposit, // Deposit all WETH as collateral borrow // Borrow USDC to repay flash loan ); // Flash loan wrapper bytes memory flashLoan = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(USDC), // Flash loan asset address(MORPHO_BLUE), // Flash loan provider flashLoanAmount, // Flash loan amount uint16(innerOperation.length + 1), // Callback data length uint8(0), // Morpho Blue pool ID innerOperation // Operations to execute ); // Complete operation sequence bytes memory composerOps = abi.encodePacked( transferIn, // Pull user's ETH and convert to WETH approvePool, // Pre-approve Aave pool for WETH approveMorpho, // Pre-approve Morpho Blue for USDC flashLoan // Execute flash loan with inner operations ); // Execute the complete leverage operation composer.deltaCompose{value: USER_AMOUNT}(composerOps); ``` --- ## Key Considerations 1. **Debt Delegation:** The operation requires prior debt delegation approval for borrowing: `IDebtToken(AAVE_V3_USDC_V_TOKEN).approveDelegation(composer, type(uint256).max)` 2. **Flash Loan Fees:** The borrow amount must account for any flash loan fees to ensure complete repayment. 3. **Slippage Protection:** The sweep operation with `SweepType.AMOUNT` ensures you receive sufficient WETH to make the leverage worthwhile. 4. **Efficient ETH Handling:** The `TRANSFER_FROM` operation with WETH as the target efficiently converts ETH to WETH without separate wrapping steps. 5. **Gas Optimization Strategies:** - User fund transfers and approvals are placed outside the flash loan callback - Direct transfers to the forwarder eliminate unnecessary token movements - Maximum approvals reduce future transaction costs 6. **Risk Management:** - The entire operation is atomic - partial execution is impossible - Minimum output requirements protect against excessive slippage - Flash loans eliminate the need for upfront borrowing capital 7. **Position Health:** Ensure the final position maintains a healthy collateralization ratio based on Aave V3's risk parameters for WETH/USDC. 8. **ETH Value Attachment:** The `{value: USER_AMOUNT}` ensures the user's ETH is sent with the transaction for the initial collateral contribution. ## Related Documentation - [Margin Operations](../margin.md) - Architecture overview - [Flash Loan Operations](../flash-loan.md) - Provider details - [External Call Patterns](../external-call.md) - Swap integration - [Approval Management](../transfers.md#approve-operation) - Permission setup --- ### migration Source: https://docs.1delta.io/smart-contract-api/example-operations/migration # Position Migration Position migrations enable seamless movement of leveraged positions between lending protocols while maintaining the same collateral and debt composition. This allows users to optimize for better rates, features, or risk profiles without closing and reopening positions. ## Overview The migration process follows this atomic sequence: 1. **Flash Loan**: Borrow debt asset for repayment 2. **Repay**: Clear debt on source protocol 3. **Withdraw**: Remove collateral from source protocol 4. **Deposit**: Add collateral to target protocol 5. **Borrow**: Take debt from target protocol 6. **Repay**: Return flash loan funds 7. **Refund**: Refund any leftover to the user All operations execute atomically - complete success or full revert. ## Example Scenario **Starting Position (Aave V3):** - Collateral: 3 WETH - Debt: 8,000 USDC **Target Position (Compound V3):** - Collateral: 3 WETH - Debt: 8,000 USDC --- ### Constants ```solidity // Flash loan amount (slightly higher than debt to ensure full repayment) uint256 FLASH_LOAN_AMOUNT = 8000.1e6; // 8,000.1 USDC (0.1 USDC buffer) // Default forwarder address address CALL_FORWARDER = 0xfCa1154C643C32638AEe9a43eeE7f377f515c801; // 1delta composer IComposer composer = IComposer(0x...); // Protocol addresses address AAVE_V3_POOL = address(0x...); address COMPOUND_V3_COMET = address(0x...); // USDC market comet address AAVE_V3_A_TOKEN_WETH = address(0x...); address AAVE_V3_USDC_V_TOKEN = address(0x...); // Flash loan source address MORPHO_BLUE = address(0xbbb...); // Asset addresses address WETH = address(0xC02...); address USDC = address(0xA0b...); ``` ## Integration Checklist - [ ] Source protocol permissions configured - [ ] Target protocol permissions set - [ ] Health factor validation passed - [ ] Protocol compatibility verified - [ ] Flash loan provider selected - [ ] Error handling implemented - [ ] Migration cost estimated --- ## Operation Sequence ### 1. Repay Aave V3 Debt Use the flash-loaned USDC to completely repay the existing Aave V3 debt. Using `amount=0xffffffffffffffffffffffffffff` ensures we repay the minimum of contract balance and actual debt. ```solidity bytes memory repayAave = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.REPAY), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(USDC), // Asset to repay uint128(0xffffffffffffffffffffffffffff), // Repay full debt or balance address(user), // Debt owner uint8(2), // Variable rate mode address(AAVE_V3_USDC_V_TOKEN), // Variable debt token address(AAVE_V3_POOL) // Aave V3 pool ); ``` ### 2. Withdraw Aave V3 Collateral Withdraw the entire WETH collateral from Aave V3. The collateral goes directly to the composer for the next operation. ```solidity bytes memory withdrawAave = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.WITHDRAW), uint16(LenderIds.UP_TO_AAVE_V3 - 1), // Aave V3 identifier address(WETH), // Asset to withdraw uint128(0xffffffffffffffffffffffffffff), // Withdraw full balance address(composer), // Temporary recipient address(AAVE_V3_A_TOKEN_WETH), // Collateral token address(AAVE_V3_POOL) // Aave V3 pool ); ``` ### 3. Deposit to Compound V3 Deposit the withdrawn WETH collateral into Compound V3. Using `amount=0` deposits the contract's entire WETH balance. ```solidity bytes memory depositCompound = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.DEPOSIT), uint16(LenderIds.UP_TO_COMPOUND_V3 - 1), // Compound V3 identifier address(WETH), // Asset to deposit uint128(0), // Deposit entire balance address(user), // Deposit recipient address(COMPOUND_V3_COMET) // Compound V3 comet address ); ``` ### 4. Borrow from Compound V3 Borrow enough USDC from Compound V3 to repay the flash loan plus any fees. ```solidity bytes memory borrowCompound = abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.BORROW), uint16(LenderIds.UP_TO_COMPOUND_V3 - 1), // Compound V3 identifier address(USDC), // Asset to borrow uint128(FLASH_LOAN_AMOUNT), // Exact flash loan repayment amount address(composer), // Temporary recipient address(COMPOUND_V3_COMET) // Compound V3 comet address ); ``` ### 5. Refund Excess USDC Transfer any remaining USDC balance back to the user after flash loan repayment. ```solidity bytes memory refundExcess = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDC), // Asset to sweep address(user), // Recipient uint128(0) // Send remaining balance ); ``` ### 6. Required Approvals Set up all necessary approvals for the operation: ```solidity // Approve Aave V3 pool to spend USDC for repayment bytes memory approveAavePool = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), address(AAVE_V3_POOL) ); // Approve Compound V3 comet to spend WETH for collateral deposit bytes memory approveCompoundComet = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(WETH), address(COMPOUND_V3_COMET) ); // Approve Morpho Blue for flash loan repayment bytes memory approveMorpho = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), address(MORPHO_BLUE) ); ``` --- ## Complete Migration Assembly Putting it all together with the flash loan wrapper: ```solidity // Inner operations executed within flash loan callback bytes memory innerOperation = abi.encodePacked( repayAave, // Repay existing Aave V3 debt withdrawAave, // Withdraw Aave V3 collateral depositCompound, // Deposit collateral to Compound V3 borrowCompound, // Borrow from Compound V3 to repay flash loan refundExcess // Refund any excess USDC to user ); // Flash loan wrapper bytes memory flashLoan = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(USDC), // Flash loan asset address(MORPHO_BLUE), // Flash loan provider uint128(FLASH_LOAN_AMOUNT), // Flash loan amount with buffer uint16(innerOperation.length + 1), // Callback data length uint8(0), // Morpho Blue pool ID innerOperation // Operations to execute ); // Complete migration sequence bytes memory migrationOps = abi.encodePacked( approveAavePool, // Pre-approve Aave pool approveCompoundComet, // Pre-approve Compound comet approveMorpho, // Pre-approve Morpho Blue flashLoan // Execute migration with flash loan ); // Execute the complete position migration composer.deltaCompose(migrationOps); ``` ## Key Considerations ### 1. **Dust Management** The borrow-repay process will leave dust since we must use a fixed flash loan amount larger than the exact Aave V3 debt to ensure complete repayment. The excess is automatically refunded to the user. ### 2. **Flash Loan Buffer** To ensure we can repay the flash loan completely, we borrow the Aave V3 debt amount plus a safety margin (e.g., 0.1 USDC buffer). This accounts for: - Interest accrual between quote and execution - Flash loan fees (if any) - Rounding differences in debt calculations ### 3. **Protocol Permissions** The operation requires pre-approval on both protocols: - **Aave V3:** Approve composer for collateral withdrawal: `IERC20(AAVE_V3_A_TOKEN_WETH).approve(composer, type(uint256).max)` - **Compound V3:** Allow composer for operations: `IComet(COMPOUND_V3_COMET).allow(composer, true)` ### 4. **Market Compatibility** Ensure the target Compound V3 market accepts the same collateral asset and allows borrowing the same debt asset. Compound V3 markets are isolated and each supports specific asset combinations. ### 5. **Risk Parameter Changes** Different protocols have different: - Loan-to-value ratios - Liquidation thresholds - Interest rate models Verify the position remains healthy after migration and adjust if necessary. ### 6. **Atomic Execution** The entire migration is atomic - either all steps succeed or the transaction reverts, ensuring no partial migrations that could leave positions in an inconsistent state. ### 7. **Gas Optimization** - All approvals are performed outside the flash loan callback - Using `amount=0` and max values reduces the need for exact balance calculations - Direct transfers between operations minimize intermediate steps ## Related Documentation - [Margin Operations](../margin.md) - Architecture overview - [Flash Loan Operations](../flash-loan.md) - Provider details - [Lending Operations](../lending.md) - Protocol interactions --- ### external-call Source: https://docs.1delta.io/smart-contract-api/external-call # Call Forwarder Operations The Call Forwarder (`CallForwarder.sol`) extends the composer's functionality by providing a secure execution environment for complex operations. The main composer first validates calls, then forwards them to the Call Forwarder which can execute external calls. ## Overview The Call Forwarder supports the following operations: | Operation | Command ID | Description | | ----------------------------------------- | ---------- | ----------------------------------------- | | [`EXT_CALL`](#ext_call-operation) | `0x20` | External calls with safety checks | | [`EXT_TRY_CALL`](#ext_try_call-operation) | `0x21` | External calls with error handling | | [`TRANSFERS`](#transfers-operations) | `0x40` | Transfer operations (pull, send, approve) | | [`BRIDGING`](#bridging-operations) | `0x90` | Cross-chain bridge operations | ## Security Model The external calls are facilitated by the call forwarder, while this approach seems to be inefficien, it is necessary to prevent malicious callers to execute bad calldata on the `composer` (e.g. trying to execute `transferFrom` from a prior caller that approved the `composer`), also external calls to `permit2` contract are blocked by the composer for the same reason. ## Entry Point ```solidity function deltaForwardCompose(bytes calldata data) external payable ``` All operations are encoded in the `data` parameter and executed atomically. ## Hierarchical Calling Structure The system uses a **two-layer architecture** for secure external interactions: ### Call Architecture Summary - **Main Composer** - Issues `EXT_CALL` operations. - Calls the `Call Forwarder` contract via `deltaForwardCompose`. - **Call Forwarder** - Receives and executes forwarded calls. - Supports operations: - `EXT_CALL` - any smart contract call (`permit2` target is prohibited and so is the `transferFrom` selector) - `EXT_TRY_CALL` - any call that will enter a fallback operation in case of an error - Token `TRANSFERS` - Cross-chain `BRIDGING` - Provides controlled execution to avoid exposing the Composer directly to malicious calls. - **External Contracts** - Arbitrary selectors can be targeted. - Ensures flexibility while safeguarding Composer from unsafe external interactions. ### Example Structure ```solidity // Step 1: Encode operations for Call Forwarder bytes memory callForwarderOperations = abi.encodePacked( // Call Forwarder operations here uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), assetAddress, receiverAddress, uint8(SweepType.AMOUNT), uint128(amount) ); // Step 2: Wrap in EXT_CALL to Call Forwarder bytes memory composerCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), callForwarderAddress, // Call Forwarder as target uint128(0), // No native value needed uint16(callForwarderOperations.length), callForwarderOperations // Operations for Call Forwarder ); // Step 3: Execute on main composer composer.deltaCompose(composerCall); ``` ## EXT_CALL Operation Execute external calls with built-in safety checks. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ------------------- | | 0 | 20 | target `address` | | 20 | 16 | value `uint128` | | 36 | 2 | dataLength `uint16` | | 38 | dataLength | data `bytes` | ### Notes - **`value`** is the native currency amount to attach - **`value`** has a high bit flag indicating whether to use `selfbalance()` - **Security**: Main composer prevents calls to Permit2 and `transferFrom` selector - **Execution**: Reverts on failure with the original error ### Encoding Example ```solidity bytes memory callForwarderOperations = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), // Operation for Call Forwarder targetAddress, uint128(nativeValue), uint16(callData.length), callData ); bytes memory composerCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), // EXT_CALL to Call Forwarder callForwarderAddress, // Call Forwarder as target uint128(0), // No native value for Call Forwarder uint16(callForwarderOperations.length), callForwarderOperations ); ``` ## EXT_TRY_CALL Operation Execute external calls with error handling and fallback options. ### Parameters | Offset | Length (bytes) | Description | | ------------- | --------------- | ------------------------ | | 0 | 20 | target `address` | | 20 | 16 | value `uint128` | | 36 | 2 | dataLength `uint16` | | 38 | dataLength | data `bytes` | | 38+dataLength | 1 | catchHandling `uint8` | | 39+dataLength | 2 | catchDataLength `uint16` | | 41+dataLength | catchDataLength | catchData `bytes` | ### Notes - **`catchHandling`**: Controls error handling behavior - `0`: Revert on failure (default) - `1`: Exit function on failure - `2+`: Continue execution after catch - **`catchData`**: Operations to execute if the external call fails ### Encoding Example ```solidity // With error handling - e.g. sweep tokens back to user on failure bytes memory catchOperations = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(USDC), // asset to sweep address(user), // receiver (user who initiated the call) uint8(SweepType.VALIDATE), // validate balance before sweeping uint128(0) // amount = 0 means sweep entire balance ); bytes memory tryCall = abi.encodePacked( uint8(ComposerCommands.EXT_TRY_CALL), targetAddress, uint128(nativeValue), uint16(callData.length), callData, // the calldata that should be executed uint8(1), // catchHandling: exit on failure uint16(catchOperations.length), catchOperations // the calldata to execute in case of error ); ``` ## TRANSFERS Operations All transfer operations are supported in the Call Forwarder. See the [Transfers documentation](./transfers.md) for detailed information about: - **TRANSFER_FROM**: Pull funds from caller - **SWEEP**: Send funds from contract - **APPROVE**: Approve token spending - **UNWRAP_WNATIVE**: Unwrap native tokens - **PERMIT2_TRANSFER_FROM**: Permit2 transfers ### Usage in Call Forwarder ```solidity bytes memory transferOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), assetAddress, receiverAddress, uint8(SweepType.AMOUNT), uint128(amount) ); ``` ## BRIDGING Operations Execute cross-chain bridge operations through supported bridge protocols. See the [detailed bridge documentation](./bridge/bridge.md) for comprehensive information about all supported bridge protocols. ### Basic Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------------- | | 0 | 1 | bridgeId `uint8` | | 1 | Variable | bridge-specific parameters | ### Encoding Example ```solidity bytes memory bridgeOp = abi.encodePacked( uint8(ComposerCommands.BRIDGING), // Bridge-specific parameters... ); ``` For detailed information about each bridge protocol, including parameter layouts and encoding examples, see: - [Bridge Operations Overview](./bridge/bridge.md) - [Stargate V2 Bridge](./bridge/stargate.md) - [Across Bridge](./bridge/across.md) ## Example: 1inch Meta-Aggregation Here we illustrate the complete two-layer calling structure for a swap from `USDC` to `WETH` using 1inch. ### Two-Layer Security Flow ``` Main Composer ↓ EXT_CALL validation Call Forwarder ↓ deltaForwardCompose validation ↓ TRANSFERS (approve) + EXT_CALL (to 1inch) + TRANSFERS (sweep) External Contracts (Arbitrary selectors allowed) ``` ### Complete Process 1. **Main Composer** validates the EXT_CALL (blocks transferFrom/Permit2) 2. **Call Forwarder** receives validated call via `deltaForwardCompose` 3. **Call Forwarder** executes operations with additional security: - Approve 1inch router (TRANSFERS with security checks) - Call 1inch swap (EXT_CALL with security checks) - Sweep received WETH (TRANSFERS with security checks) ```solidity uint256 swapAmount = 4000.0e6; // this is the default forwarder address address callForwarderAddress = 0xfCa1154C643C32638AEe9a43eeE7f377f515c801; // create the call for the forwarder // the target can e.g. be the 1inch aggregation router bytes memory callForwarderCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), address(oneInchAggregationRouter), uint128(0), // ERC20 has no value uint16(data.length), data ); // we need to approve the 1inch router on the callForwarder level // note that the approval is skipped if it was already done in the past bytes memory approve1inch = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), address(USDC), address(oneInchAggregationRouter) ); // expect to receive 1 WETH // revert if we receive less uint256 amountExpected = 1.0e18; // in case the aggregators does not transfer directly to the user bytes memory sweepAndCheckSlippage = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(WETH), address(receiver), // this is the receiver of the WETH uint8(SweepType.AMOUNT), amountExpected ); // combine the operations callForwarderCall = abi.encodePacked( approve1inch, callForwarderCall, sweepAndCheckSlippage ); // prepare the composer call // this executes callForwader.deltaForwardCompose(callForwarderCall) bytes memory composerCall = abi.encodePacked( uint8(ComposerCommands.EXT_CALL), callForwarderAddress, // it is important to use the forwarder on the composer level uint128(value), uint16(callForwarderCall.length), callForwarderCall ); // we need to make sure that teh callForwarder receives the funds directly bytes memory transferToForwarder = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.TRANSFER_FROM), address(USDC), callForwarderAddress, uint128(swapAmount) ); // combine the call to the composer composerCall = abi.encodePacked( transferToForwarder, composerCall ); // execute the operations composer.deltaCompose(composerCall); ``` --- ### flash-loan Source: https://docs.1delta.io/smart-contract-api/flash-loan # Flash Loans [Operations](./operations.md) → Flash Loans _(Composer)_ Lead type: `ComposerCommands.FLASH_LOAN`. The sub types are defined by the following enum: `FlashLoanIds` Enum | Value | Name | Description | | ----- | ------------- | --------------------------- | | 0 | `MORPHO` | Morpho Blue flash loans | | 1 | `BALANCER_V2` | Balancer V2 (covers Swaap) | | 2 | `AAVE_V3` | Aave V3 (covers many forks) | | 3 | `AAVE_V2` | Aave V2 (covers many forks) | To encode an operation, the caller has to append this data to the call. ```solidity abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.[FlashLoanProvider]), ...params ) ``` Alternative sources can be Uniswap V4 and Balancer V3. These are triggered via the lead type: `ComposerCommands.GEN_2025_SINGELTONS`. We elaborate on these later. ## Specific lenders - [Accepted sources](./flash-loan/accepted-sources.md) - [Standard providers](./flash-loan/standardized-interface.md) - [Singletons](./flash-loan/singletons.md) --- ### accepted-sources Source: https://docs.1delta.io/smart-contract-api/flash-loan/accepted-sources # Accepted Flash-Loan Sources [Operations](../operations.md) → [Flash Loans](../flash-loan.md) → Accepted Sources _(Composer)_ A flash-loan callback hands control back to the composer while funds are in flight, so the composer **hardcode-trusts** a fixed set of contracts as the only valid callback callers. Because the composers are [immutable](../../on-chain-addresses.mdx), this trusted set is frozen. ## Trust model A source is accepted only if it falls into one of these categories: 1. **Immutable by construction** — a canonical singleton or a `CREATE2`-derived pool whose address an attacker cannot occupy. No governance judgement is required. 2. **Original Aave** — a canonical Aave DAO deployment. 3. **Strongly-governed fork** — a reputable fork that is not upgradeable by a single EOA (real multisig / timelock / DAO), or, in rare cases, the dominant lender of its chain. Forks that are single-EOA upgradeable, anonymously governed, unaudited, defunct, or previously exploited are **excluded from code generation** and are never trusted as a callback source. ## Trustless sources (immutable / re-derived) | Source | Basis | | ------ | ----- | | **Morpho Blue** | Canonical immutable singleton; callback only fires on `msg.sender` | | **Morpho Blue forks** (Lista / Moolah) | Canonical singleton, `msg.sender`-only callback | | **Morpho Midnight** | Canonical instance, ERC-3156; callback hardened with `initiator == address(this)` | | **Uniswap V4** (PoolManager) | Canonical singleton; unlock callback fires on `msg.sender` | | **Balancer V3** (Vault) | Canonical singleton; unlock callback fires on `msg.sender` | | **Balancer V2** and forks (incl. Swaap) | Canonical vault; standardized flash-loan interface | | **Uniswap V3 / Algebra / PancakeSwap V3** and forks | Pool address re-derived via `CREATE2` (`keccak256(0xff ++ factory ++ salt ++ initHash)`) | ## Aave-family sources | Source | Chains | Basis | | ------ | ------ | ----- | | **Aave V3** | Canonical DAO deployments across all supported chains | Original Aave (Aave Governance) | | **Aave V3 – Prime / EtherFi / Horizon** | Ethereum | Official Aave DAO instances | | **Aave V2** | Ethereum, Polygon, Avalanche | Canonical Aave V2 | | **Spark** | Ethereum, Gnosis | Sky / MakerDAO SubDAO — timelock-gated | | **HyperLend** | HyperEVM | Aave-recognized fork; multisig-governed, audited | | **YEI** (main market) | Sei | 24h timelock + multisig | | **Phiat** | PulseChain | Dominant lender on PulseChain (chain-level exception) | ## Excluded forks Weak/opaque-governance, defunct, or flash-loan-disabled Aave forks are dropped from the trusted set — for example Colend and Fathom (flash loans frozen at the protocol), and several EOA-governed or previously-exploited forks. The full accept/reject policy and per-fork governance analysis is maintained in the [contracts repository](https://github.com/1delta-DAO/contracts-delegation). --- ### singletons Source: https://docs.1delta.io/smart-contract-api/flash-loan/singletons # Singleton Flash Loan Interface [Operations](../operations.md) → [Flash Loans](../flash-loan.md) → Singletons _(Composer)_ Lead type: `ComposerCommands.GEN_2025_SINGELTONS`. The singleton flash loans are constructed from atomic operations on values, e.g., the Balancer V3 vault and Uniswap V4 Position Manager. ## Supported Providers ### Balancer V3 Balancer V3 provides flash loans through its vault contract with advanced features: - **Lead Command**: `ComposerCommands.GEN_2025_SINGELTONS` - **Sub-type**: `DexForkMappings.BALANCER_V3` ### Uniswap V4 Uniswap V4 provides flash loans through its position manager: - **Lead Command**: `ComposerCommands.GEN_2025_SINGELTONS` - **Sub-type**: `DexForkMappings.UNISWAP_V4` ## Parameter Structure | Offset | Length (bytes) | Type | Description | | ------ | -------------- | --------- | ------------------------------------- | | 0 | 20 | `address` | Asset contract address to borrow | | 20 | 32 | `uint256` | Amount to borrow (in asset decimals) | | 52 | Dynamic | `bytes` | Packed composer operations to execute | ## Solidity Example: Balancer V3 Flash Loan ```solidity // Inner operations to execute during flash loan bytes memory innerOperations = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(0), // Transfer type address(this), // recipient amount // amount to transfer ); // Main flash loan operation bytes memory operation = abi.encodePacked( uint8(ComposerCommands.GEN_2025_SINGELTONS), uint8(DexForkMappings.BALANCER_V3), BALANCER_V3_VAULT, USDC, // asset to borrow amount, // amount to borrow innerOperations // operations to execute ); // Execute the flash loan composer.deltaCompose(operation); ``` ## TypeScript Example (using viem) ```typescript // Inner operations to execute during flash loan const innerOperations = encodePacked( ["uint8", "uint8", "address", "uint256"], [ ComposerCommands.TRANSFERS, 0, // Transfer type "0x...", // recipient address amount, ] ) // Main flash loan operation const operation = encodePacked( [ "uint8", // ComposerCommands.GEN_2025_SINGELTONS "uint8", // DexForkMappings.BALANCER_V3 "address", // vault address "address", // asset "uint256", // amount "bytes", // inner operations ], [ComposerCommands.GEN_2025_SINGELTONS, DexForkMappings.BALANCER_V3, BALANCER_V3_VAULT, USDC_ADDRESS, amount, innerOperations] ) return operation } // Usage example const operationData = encodeBalancerV3FlashLoan( "0x...", // composer address 1000000n ) // Call the composer await publicClient.writeContract({ address: composerAddress, abi: parseAbi(["function deltaCompose(bytes data)"]), functionName: "deltaCompose", args: [operationData], }) ``` --- ### standardized-interface Source: https://docs.1delta.io/smart-contract-api/flash-loan/standardized-interface # Standardized Flash Loan Interface [Operations](../operations.md) → [Flash Loans](../flash-loan.md) → Standardized Interface _(Composer)_ While flash loan implementations are nearly all the same, the explicit usage and interface vary. In this section we cover the flash loans provided by: - Balancer V2 and forks - Aave V2 & V3 and forks - Morpho Blue ## Flash Loan Parameters The following parameters need to be provided for Aave V2, V3 and Morpho Blue: ### Parameter Structure | Offset | Length (bytes) | Type | Description | | ----------------- | -------------- | --------- | ------------------------------------------- | | 0 | 20 | `address` | Asset contract address to borrow | | 20 | 20 | `address` | Flash loan pool contract address | | 40 | 16 | `uint128` | Amount to borrow (in asset decimals) | | 56 | 2 | `uint16` | `paramsLength + 1` (total parameter length) | | 58 | 1 | `uint8` | Pool identifier for validation | | 59 + paramsLength | paramsLength | `bytes` | Packed composer operations to execute | ## Key Technical Details ### Validation Logic Since flash loans use callbacks, we need `poolId` to validate that the callback was triggered by a trusted Aave or Morpho pool. ### Parameters Structure `params` is a packed set of composer operations that will be executed during the flash loan. ## Important Considerations - **Re-entrancy**: The composer re-enters itself during flash loan execution - **Caller Forwarding**: The caller address is forwarded from the original call source - **Pool Validation**: The validation logic is hard-coded, so only a limited set of pools are allowed - **DEX Limitations**: Some flash loan sources are DEXs (e.g., Balancer V2, Uniswap V4) - this means swaps through these DEXs are not possible during the flash loan due to re-entrancy protection ## Solidity Example: USDC Loop in Aave V3 ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; // select 1M USDC uint128 amount = uint128(1000000.0e6); // Inner operations: deposit USDC and borrow USDC bytes memory innerOperations = abi.encodePacked( // Deposit USDC to Aave V3 uint8(ComposerCommands.LENDING), uint8(LenderOps.DEPOSIT), uint16(AAVE_V3_ID), USDC, // asset amount, // amount uint8(0), // interest rate mode (0 = variable) // Borrow USDC from Aave V3 uint8(ComposerCommands.LENDING), uint8(LenderOps.BORROW), uint16(AAVE_V3_ID), USDC, // asset amount, // amount uint8(0) // interest rate mode (0 = variable) ); // Main flash loan operation bytes memory operation = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.AAVE_V3), USDC, // asset to borrow AAVE_V3_POOL, // flash loan pool amount, // amount to borrow uint16(innerOperations.length + 1), // params length + 1 uint8(0), // poolId for validation innerOperations // packed operations to execute ); // Execute the flash loan composer.deltaCompose(operation); ``` ## TypeScript Example (using viem) ```typescript // Inner operations: deposit and borrow const innerOperations = encodePacked( ["uint8", "uint8", "uint16", "address", "uint128", "uint8"], [ ComposerCommands.LENDING, LenderOps.DEPOSIT, AAVE_V3_ID, USDC_ADDRESS, amount, 0, // interest rate mode (variable) ] ) + encodePacked( ["uint8", "uint8", "uint16", "address", "uint128", "uint8"], [ ComposerCommands.LENDING, LenderOps.BORROW, AAVE_V3_ID, USDC_ADDRESS, amount, 0, // interest rate mode (variable) ] ).slice(2) // Remove '0x' prefix // Main flash loan operation const operation = encodePacked( [ "uint8", // ComposerCommands.FLASH_LOAN "uint8", // FlashLoanIds.AAVE_V3 "address", // asset "address", // pool "uint128", // amount "uint16", // paramsLength + 1 "uint8", // poolId "bytes", // inner operations ], [ ComposerCommands.FLASH_LOAN, FlashLoanIds.AAVE_V3, USDC_ADDRESS, AAVE_V3_POOL, amount, innerOperations.length / 2 + 1, // length in bytes + 1 0, // poolId innerOperations, ] ) return operation } // Usage example const operationData = encodeFlashLoanLoop( "0x...", // composer address 1000000n ) // Call the composer await publicClient.writeContract({ address: composerAddress, abi: parseAbi(["function deltaCompose(bytes data)"]), functionName: "deltaCompose", args: [operationData], }) ``` ## Notes ### Pool ID Validation The `poolId` parameter is crucial for security. Each flash loan provider has specific pool IDs: - **Morpho Blue**: Pool ID `0` for the main Morpho Blue contract - **Aave V3**: Pool IDs vary by deployment (e.g., `0` for mainnet) - **Aave V2**: Pool IDs vary by deployment (e.g., `7` for Granary) ### Re-entrancy Considerations When using DEX-based flash loans (Balancer V2, Uniswap V4), be aware that: - You cannot perform swaps on the same DEX during the flash loan - Re-entrancy guards prevent nested operations on these protocols - Use alternative DEXs for any swaps needed within the flash loan --- ### lending Source: https://docs.1delta.io/smart-contract-api/lending # Lending [Operations](./operations.md) → Lending _(Composer)_ Lead type: `ComposerCommands.LENDING`. The sub types are defined by the following enum: `LenderOps` Enum | Value | Name | Description | | ----- | ------------------------ | --------------------------------------------- | | 0 | `DEPOSIT` | Deposit collateral to lender | | 1 | `BORROW` | Borrow from lender | | 2 | `REPAY` | Repay to lender | | 3 | `WITHDRAW` | Withdraw collateral from lender | | 4 | `DEPOSIT_LENDING_TOKEN` | Deposit lending token (e.g. for Morpho Blue) | | 5 | `WITHDRAW_LENDING_TOKEN` | Withdraw lending token (e.g. for Morpho Blue) | to the array of composer commands. We encode lender types as follows: `LenderIds` Enum | Value | Name | Description | | ----- | ------------------- | -------------------------- | | 1000 | `UP_TO_AAVE_V3` | Aave V3 IDs: 0-999 | | 2000 | `UP_TO_AAVE_V2` | Aave V2 IDs: 1000-1999 | | 3000 | `UP_TO_COMPOUND_V3` | Compound V3 IDs: 2000-2999 | | 4000 | `UP_TO_COMPOUND_V2` | Compound V2 IDs: 3000-3999 | | 5000 | `UP_TO_MORPHO` | Morpho IDs: 4000-4999 | To encode an operation, the caller has to append this data to the call. ```solidity abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.[Operation]), uint16(LenderIds.[Lender]) ...params ) ``` ## Specific lenders - [Aave V2 & V3 & forks](./lending/aave.md) - [Compound V3 markets](./lending/compound-v3.md) - [Compound V2 markets](./lending/compound-v2.md) - [Morpho Blue](./lending/morpho.md) --- ### aave Source: https://docs.1delta.io/smart-contract-api/lending/aave # Aave V2 & V3 & Forks [Operations](../operations.md) → [Lending](../lending.md) → Aave V2 & V3 _(Composer)_ Aave V2 and V3 behave very similar for all operations. The caller only needs to distinguish them via `LenderIds`, the rest is handled by the contract logic. ## Deposit Deposit the underlying to the lender for the given `pool`. If `amount=0`, we use the contract balance via `underlying.balanceOf(address(this))`. This is recommended when executing this operation after a swap. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | pool `address` | ## Withdraw Withdraw for the lender. Note that this requires that the caller approved the composer to spend `aToken` on their behalf. If `amount=0xffffffffffffffffffffffffffff`, we read `underlying.balanceOf(callerAddress)` and withdraw the full balance without leaving dust. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | aToken `address` | | 96 | 20 | pool `address` | ## Borrow Borrow from the lender. The prerequisite is that the caller approved the composer contract to borrow on their behalf via `debtToken.approveDelegation(...)`. It is important that the `mode` is provided here, most Aave forks only support `mode=2` (variable). If the selector without `mode` is used, one needs to set `mode=0`. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 1 | mode `uint8` | | 77 | 20 | pool `address` | ## Repay Repay to the lender. In this case, use `amount=0` to repay `underlying.balanceOf(address(this))`, the contract balance, if `amount=0xffffffffffffffffffffffffffff`, repay the minimum of the contract balance and the caller debt. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 1 | mode `uint8` | | 77 | 20 | debtToken `address` | | 97 | 20 | pool `address` | --- ### compound-v2 Source: https://docs.1delta.io/smart-contract-api/lending/compound-v2 # Compound V2 markets [Operations](../operations.md) → [Lending](../lending.md) → Compound V2 _(Composer)_ All Compound V2 markets behave the same way. The market is specified by the `cToken` parameter. Note that Compound V2 supports both native tokens (ETH) and ERC20 tokens. ## Deposit Deposit the underlying to the lender for the given `cToken`. If `amount=0`, we use the contract balance via `underlying.balanceOf(address(this))`. This is recommended when executing this operation after a swap. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | cToken `address` | ## Withdraw Withdraw from the lender. Note that this requires that the caller approved the composer to spend `cToken` on their behalf. If `amount=0xffffffffffffffffffffffffffff`, we read the user's full balance and withdraw without leaving dust. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | cToken `address` | ## Borrow Borrow from the lender. The prerequisite is that the caller approved the composer contract to borrow on their behalf. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | cToken `address` | ## Repay Repay to the lender. In this case, use `amount=0` to repay `underlying.balanceOf(address(this))`, the contract balance. If `amount=0xffffffffffffffffffffffffffff`, repay the minimum of the contract balance and the caller debt. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | cToken `address` | --- ### compound-v3 Source: https://docs.1delta.io/smart-contract-api/lending/compound-v3 # Compound V3 markets [Operations](../operations.md) → [Lending](../lending.md) → Compound V3 _(Composer)_ All Compound V3 markets behave the same way. The market is specified by the `comet` parameter. The markets are isolated from each other and only one currency is borrowable. ## Deposit Deposit the underlying to the lender for the given `pool`. If `amount=0`, we use the contract balance via `underlying.balanceOf(address(this))`. This is recommended when executing this operation after a swap. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | comet `address` | ## Withdraw Withdraw for the lender. Note that this requires that the caller approved the composer via `comet.allow(...)`. If `amount=0xffffffffffffffffffffffffffff`, we read `underlying.balanceOf(callerAddress)` and withdraw the full balance without leaving dust. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 1 | isBase `uint8` | | 77 | 20 | comet `address` | You need to provide the `isBase` flag if you want to withdraw the base asset. The reason for this is that Compound V3 has different ways to compute balances for the base asset. ## Borrow Borrow from the lender. The prerequisite is that the caller approved the composer contract to borrow on their behalf via `comet.allow(...)`. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | comet `address` | ## Repay Repay to the lender. In this case, use `amount=0` to repay `underlying.balanceOf(address(this))`, the contract balance, if `amount=0xffffffffffffffffffffffffffff`, repay the minimum of the contract balance and the caller debt. | Offset | Length (bytes) | Description | | ------ | -------------- | -------------------- | | 0 | 20 | underlying `address` | | 20 | 16 | amount `uint128` | | 36 | 20 | receiver `address` | | 76 | 20 | comet `address` | --- ### morpho Source: https://docs.1delta.io/smart-contract-api/lending/morpho # Morpho Blue [Operations](../operations.md) → [Lending](../lending.md) → Morpho Blue _(Composer)_ Morpho Blue uses a market-based system where each market is defined by specific parameters. All operations require the full market specification. ## Market Parameters Each Morpho operation requires the complete market definition: | Offset | Length (bytes) | Description | | ------ | -------------- | --------------------------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm (Interest Rate Model) | | 80 | 16 | MarketParams.lltv (Liquidation Loan-To-Value) | ## Deposit Collateral Deposit collateral tokens to a Morpho Blue market. If `amount=0`, we use the contract balance via `collateralToken.balanceOf(address(this))`. This is recommended when executing this operation after a swap. | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm | | 80 | 16 | amount `uint128` | | 96 | 20 | receiver `address` | | 116 | 20 | morpho `address` | ## Withdraw Collateral Withdraw collateral tokens from a Morpho Blue market. If `amount=0xffffffffffffffffffffffffffff`, we read the user's full collateral balance and withdraw without leaving dust. | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm | | 80 | 16 | amount `uint128` | | 96 | 20 | receiver `address` | | 116 | 20 | morpho `address` | ## Deposit Lending Token Deposit loan tokens (lending tokens) to a Morpho Blue market. This operation supports both assets and shares. Use the flag at offset 96 to specify whether to deposit by assets (0) or shares (1). If `amount=0`, we use the contract balance. | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm | | 80 | 16 | MarketParams.lltv | | 96 | 1 | flags (0=assets, 1=shares) | | 97 | 15 | amount `uint112` | | 112 | 20 | receiver `address` | | 132 | 20 | morpho `address` | | 152 | 2 | callbackLength `uint16` | | 154 | callbackLength | callbackData | ## Withdraw Lending Token Withdraw loan tokens from a Morpho Blue market. This operation supports both assets and shares. Use the flag at offset 96 to specify whether to withdraw by assets (0) or shares (1). If `amount=0xffffffffffffffffffffffffffff`, we withdraw the user's full balance. | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm | | 80 | 16 | MarketParams.lltv | | 96 | 1 | flags (0=assets, 1=shares) | | 97 | 15 | amount `uint112` | | 112 | 20 | receiver `address` | | 132 | 20 | morpho `address` | ## Borrow Borrow loan tokens from a Morpho Blue market. This operation supports both assets and shares. Use the flag at offset 96 to specify whether to borrow by assets (0) or shares (1). | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm | | 80 | 16 | MarketParams.lltv | | 96 | 1 | flags (0=assets, 1=shares) | | 97 | 15 | amount `uint112` | | 112 | 20 | receiver `address` | | 132 | 20 | morpho `address` | ## Repay Repay borrowed loan tokens to a Morpho Blue market. This operation supports both assets and shares. Use the flag at offset 96 to specify whether to repay by assets (0) or shares (1). Special amount values: - `amount=0`: repay contract balance - `amount=0xffffffffffffffffffffffffffff`: repay maximum safe amount (prevents dust) | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------------------- | | 0 | 20 | MarketParams.loanToken | | 20 | 20 | MarketParams.collateralToken | | 40 | 20 | MarketParams.oracle | | 60 | 20 | MarketParams.irm | | 80 | 16 | MarketParams.lltv | | 96 | 1 | flags (0=assets, 1=shares) | | 97 | 15 | amount `uint112` | | 112 | 20 | receiver `address` | | 132 | 20 | morpho `address` | | 152 | 2 | callbackLength `uint16` | | 154 | callbackLength | callbackData | --- ### margin Source: https://docs.1delta.io/smart-contract-api/margin # Margin Operations Margin operations enable DeFi strategies by combining lending, borrowing, and swapping operations in atomic transactions. ## Supported Operations ### Core Margin Operations - **Leverage** - Increase position size by borrowing against collateral and reinvesting - **Close** - Exit leveraged positions by withdrawing collateral and repaying debt - **Collateral Swap** - Exchange collateral assets without closing positions - **Debt Swap** - Change debt composition while maintaining collateral - **Position Migration** - Move positions between lending protocols ## Architecture Deep Dive ### Composer Pattern The 1Delta margin system is built on composer pattern that enables multi-step DeFi operations to execute atomically. The `BaseComposer` contract serves as the foundation, with chain-specific implementations handling protocol integrations. ```solidity abstract contract BaseComposer is DeadLogger, Swaps, Gen2025DexActions, UniversalLending, ERC4626Operations, Transfers, Permits, ExternalCall { function deltaCompose(bytes calldata) external payable; function _deltaComposeInternal(address, uint256, uint256) internal virtual; } ``` ### Operation Execution Flow All margin operations follow a standardized execution pattern within the composer's main loop: ```solidity function _deltaComposeInternal(address callerAddress, uint256 currentOffset, uint256 calldataLength) internal virtual { while (true) { uint256 operation = shr(248, calldataload(currentOffset)); currentOffset = add(1, currentOffset); // handle operations if (currentOffset >= maxIndex) break; } } ``` ## Architecture Overview ### Key Components #### 1. Flash Loan Providers The system integrates multiple flash loan providers for optimal capital efficiency: > **Morpho Blue**, **Aave V3**, **Aave V2**, **Balancer V2**, **Balancer V3**, **Uniswap V4** #### 2. DEX Integration Operations support multiple DEX aggregators and protocols: > **Uniswap** (v2,v3,v4), **Balancer** (v2,v3), **GMX**, **Dodo**, ... #### 3. Lending Protocol Support Compatible with major lending protocols: > **Aave** (v2,v3 and forks), **Compound** (v2,v3 and forks), **Morpho Blue** ### Lending Protocol Integration Margin operations leverage the lending protocol support through the unified Lending Operations interface. For detailed lending operation encoding and protocol-specific parameters, see the [Lending Operations](./lending.md) documentation. ### Operation Command Structure Operations are encoded using compact byte packing: ``` Operation Byte: [Command Type (1 byte)] Data Bytes: [Operation-specific data] ``` ### Flash Loan Operations Margin operations utilize flash loans through the standardized flash loan interface. The system supports multiple providers: For detailed flash loan encoding, provider-specific parameters, and integration patterns, see the [Flash Loan Operations](./flash-loan.md) documentation. ### Technical Implementation #### Operation Encoding Operations are encoded as compact bytecode sequences: ```solidity // Example: Flash loan + swap + deposit sequence bytes memory operation = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(asset), address(provider), uint128(amount), uint16(callbackData.length), uint8(poolId), callbackCallData ); ``` ## Security Architecture ### Access Control - **Caller Validation**: Strict validation of operation initiators - **Callback Verification**: Flash loan callbacks validate caller addresses ### Slippage Protection Built-in slippage checks ensure operations meet minimum requirements: ```solidity assembly { if gt(minimumAmountReceived, amountIn) { mstore(0x0, SLIPPAGE) revert(0x0, 0x4) } } ``` ## Gas Optimization Strategies ### 1. Packed Encoding - Minimize calldata size through tight byte packing - Use uint128 for amounts, uint16 for lengths - Combine related operations in single calls ### 2. Approval Management - One-time maximum approvals reduce future gas costs - Pre-approve operations outside flash loan callbacks - Use permit signatures where supported ### 3. Direct Transfers - Route funds directly between operations - Eliminate intermediate token movements - Use contract balance operations when possible ## Quick Start Examples ### Basic Leverage Operation ```solidity // 1. Setup composer and addresses IComposer composer = IComposer(composerAddress); // 2. Encode flash loan operation bytes memory flashLoan = abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(USDC), morphoBlueAddress, uint128(8000e6), uint16(innerOps.length), uint8(0), // pool ID innerOps ); // 3. Execute operation composer.deltaCompose(flashLoan); ``` ### Multi-Protocol Operation ```solidity // Combine operations across protocols bytes memory multiProtocolOps = abi.encodePacked( // Aave V3 deposit abi.encodePacked( uint8(ComposerCommands.LENDING), uint8(LenderOps.DEPOSIT), uint16(LenderIds.AAVE_V3), address(WETH), uint128(0), userAddress, aaveV3Pool ), // Morpho flash loan abi.encodePacked( uint8(ComposerCommands.FLASH_LOAN), uint8(FlashLoanIds.MORPHO_BLUE), address(USDC), morphoAddress, uint128(amount), uint16(callbackOps.length), uint8(0), callbackOps ) ); ``` ## Integration Requirements ### Prerequisites - **EOA Approval**: User must approve composer for token operations - **Protocol Permissions**: Enable composer on target lending protocols - **Flash Loan Access**: Ensure flash loan providers are accessible ### External Data Requirements For swap operations, provide aggregator data as: - `calldata` - Raw transaction data from aggregator API - `target` - DEX router or aggregator contract address - `value` - ETH value for transaction (typically `0`) ## Next Steps Explore related operation types: - [Lending Operations](./lending.md) - Deposit, borrow, repay, withdraw - [Flash Loans](./flash-loan.md) - Instant borrowing without collateral - [Transfers](./transfers.md) - Token movements and approvals - [External Calls](./external-call.md) - Integration with external protocols --- ### operations Source: https://docs.1delta.io/smart-contract-api/operations # Operation Encoding Operations are produced by encoding them into compact byte arrays that follow a consistent structure. The 1delta protocol supports multiple operation categories, each with specific encoding patterns and use cases. ## Operation Categories ### 1. [Transfer Operations](transfers.md) (`TRANSFERS = 0x40`) Transfer operations handle token movements, approvals, and wrapping operations. **Key Features:** - Token transfers between addresses - Token approvals for spending - Native token wrapping/unwrapping - Permit2 operations **Common Use Cases:** - Moving tokens into position for lending - Transferring profits to user - Setting up approvals for protocols - Wrapping/unwrapping native tokens ### 2. Swap Operations (`SWAPS = 0x10`) Swap operations enable trading across multiple DEX protocols with advanced routing. **Key Features:** - DEX swaps across multiple protocols - Multi-hop swap routing - Flash swap callbacks - Slippage protection **Supported Protocols:** - Uniswap V2/V3 - Balancer V2/V3 - Curve - Dodo - WooFi - GMX - And more... ### 3. [Lending Operations](lending.md) (`LENDING = 0x30`) Lending operations provide access to various lending protocols through a unified interface. **Key Features:** - Deposit/withdraw collateral - Borrow/repay debt - Cross-protocol operations - Position management **Supported Protocols:** - Aave V2/V3 - Compound V2/V3 - Morpho Blue - And more... ### 4. [Flash Loan Operations](flash-loan.md) (`FLASH_LOAN = 0x60`) Flash loan operations enable instant borrowing without collateral, requiring repayment within the same transaction. **Key Features:** - Instant borrowing without collateral - Arbitrage opportunities - Liquidation protection - Complex DeFi strategies **Supported Providers:** - Morpho Blue - Aave V2/V3 - Balancer V2 ### 5. [External Calls](external-call.md) (`EXT_CALL = 0x20`, `EXT_TRY_CALL = 0x21`) External call operations enable integration with arbitrary smart contracts. **Key Features:** - Integration with external protocols - Fallback mechanisms (EXT_TRY_CALL) - Complex interaction patterns - Custom contract calls ### 6. ERC4626 Vault Operations (`ERC4626 = 0x70`) ERC4626 operations provide standardized access to yield vaults. **Key Features:** - Deposit to yield vaults - Withdraw from vaults - Share management - Standardized vault interface ### 7. Modern DEX Operations (`GEN_2025_SINGELTONS = 0x80`) Modern DEX operations support Balancer V3 and Uniswap V4 features. **Key Features:** - Balancer V3 operations - Uniswap V4 operations - Advanced liquidity management - Singleton contract patterns ### 8. Bridge Operations (`BRIDGING = 0x90`) Bridge operations enable cross-chain transfers and interactions (only call forwarder) **Key Features:** - Cross-chain transfers - Bridge protocol integration - Across/Stargate integration ## Encoding Structure All operations follow a consistent encoding pattern: ``` [command: uint8][operation-specific data: bytes] ``` ### Command Byte Values #### `ComposerCommands` Enum | Value | Name | Description | | ------ | --------------------- | ----------------------------- | | `0x10` | `SWAPS` | DEX swap operations | | `0x20` | `EXT_CALL` | External contract calls | | `0x21` | `EXT_TRY_CALL` | External calls with fallback | | `0x30` | `LENDING` | Lending protocol operations | | `0x40` | `TRANSFERS` | Token transfers and approvals | | `0x50` | `PERMIT` | Permit operations | | `0x60` | `FLASH_LOAN` | Flash loan operations | | `0x70` | `ERC4626` | ERC4626 vault operations | | `0x80` | `GEN_2025_SINGELTONS` | Modern DEX operations | | `0x90` | `BRIDGING` | Cross-chain bridge operations | --- ### summary Source: https://docs.1delta.io/smart-contract-api/summary # Contract Interfaces The following subsections describe the smart contract api for both the brokerage/aggregation contract. - [Entrypoint](entrypoint.md) - [Operations](operations.md) - [Transfers](transfers.md) - [External Call](external-call.md) - [Bridging](./bridge/bridge.md) - [Stargate V2](./bridge/stargate.md) - [Across](./bridge/across.md) - [Lending](lending.md) - [Aave](./lending/aave.md) - [Compound V3](./lending/compound-v3.md) - [Compound V2](./lending/compound-v2.md) - [Morpho Blue](./lending/morpho.md) - [Flash Loan](flash-loan.md) - [Standardized Interface](./flash-loan/standardized-interface.md) - [Singletons](./flash-loan/singletons.md) - [Margin](./margin.md) --- ### transfers Source: https://docs.1delta.io/smart-contract-api/transfers # Transfers [Operations](./operations.md) → Transfers _(Composer and Call Forwarder)_ Lead type: `ComposerCommands.TRANSFERS`. The sub types are defined by the following enum: #### `TransferIds` Enum | Value | Name | Description | | ----- | ----------------------------------------------------------- | ----------------------------- | | 0 | [`TRANSFER_FROM`](#transfer-from-operation) | Pull funds from caller | | 1 | [`SWEEP`](#sweep-operation) | Send funds from this contract | | 3 | [`UNWRAP_WNATIVE`](#unwrap-wnative-operation) | Unwrap native currency | | 4 | [`PERMIT2_TRANSFER_FROM`](#permit2-transfer-from-operation) | Permit2 transfer | | 5 | [`APPROVE`](#approve-operation) | Approve target | #### SweepType Enum | Value | Name | Description | | ----- | ---------- | --------------------------------------------------------------------------------- | | 0 | `VALIDATE` | Check if `balanceOf(address(this)) >= amount`, if true transfer it, if not revert | | 1 | `AMOUNT` | Transfer the amount without validation | To encode an operation, the caller has to append ```solidity abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.[Operation]), ...params ); ``` to the array of composer commands. ## Transfer From Operation Pull funds from the caller to a receiver address. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ------------------ | | 0 | 20 | asset `address` | | 20 | 20 | receiver `address` | | 40 | 16 | amount `uint128` | ### Notes If `amount` is `0`, we pull `asset.balanceOf(caller)`. ### Encoding Example ```solidity // Solidity bytes memory transferFromOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.TRANSFER_FROM), assetAddress, receiverAddress, uint128(amount) ); ``` ```typescript // TypeScript const transferFromOp = encodePacked( ["uint8", "uint8", "address", "address", "uint128"], [TRANSFERS_COMMAND, TransferIds.TRANSFER_FROM, assetAddress, receiverAddress, amount] ) ``` ## Sweep Operation Pull funds from this contract to a provided address. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | --------------------- | | 0 | 20 | asset `address` | | 20 | 20 | receiver `address` | | 40 | 1 | sweepType `SweepType` | | 41 | 16 | amount `uint128` | ### Enums Used - [SweepType Enum](#sweeptype-enum) - Validation mode for the sweep operation ### Notes Note that `asset` can be the zero address for native currency. ### Encoding Examples ```solidity // Solidity - Basic sweep bytes memory sweepOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), assetAddress, receiverAddress, uint8(SweepType.AMOUNT), uint128(amount) ); ``` ```typescript // TypeScript - Basic sweep const sweepOp = encodePacked( ["uint8", "uint8", "address", "address", "uint8", "uint128"], [TRANSFERS_COMMAND, TransferIds.SWEEP, assetAddress, receiverAddress, SweepType.AMOUNT, amount] ) ``` ## Sweeping Full Balance To sweep the entire balance of an asset without knowing the exact amount, set `amount = 0` and use `SweepType.VALIDATE`: ```typescript // Sweep entire token balance function encodeSweepFullBalance(asset: string, receiver: string) { return abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), asset, receiver, uint8(SweepType.VALIDATE), // fetch actual balance and validate uint128(0) // amount = 0 triggers balanceOf lookup ) } ``` This works because: - `SweepType.VALIDATE` fetches the actual balance using `balanceOf(address(this))` - `amount = 0` ensures the validation always passes (balance >= 0) - The full balance is transferred to the receiver > **Important:** if the balance is zero and `amount = 0`, the validation passes and the contract skips the empty transfer execution - this is ideal for refunding dust. ## Wrapping Native Currency To `wrap` the native currency to wrapped native, you can just use `asset=address(0),receiver=wrappedNativeAddress`. ```typescript // Wrap native currency using SWEEP operation function encodeWrap(amount: bigint, wrapTarget: string) { return abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.SWEEP), address(0), // signals native asset wrapTarget, // wrapped native contract address uint8(SweepType.AMOUNT), uint128(amount) ) } ``` This works because: - `asset = address(0)` tells the system to handle native currency - The wrapped native contract's `receive()` or `fallback()` function automatically wraps incoming native currency ## Unwrap WNative Operation Unwrap native asset and transfer if needed. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ------------------------------ | | 0 | 20 | wrappedNativeAddress `address` | | 20 | 20 | receiver `address` | | 40 | 1 | sweepType `SweepType` | | 41 | 16 | amount `uint128` | ### Enums Used - [SweepType Enum](#sweeptype-enum) - Validation mode for the unwrap operation ### Notes Note that we do not hard-code the wrapped native address as some chains have duplicate wnative implementations. ### Encoding Example ```solidity // Solidity bytes memory unwrapOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.UNWRAP_WNATIVE), wrappedNativeAddress, receiverAddress, uint8(SweepType.AMOUNT), uint128(amount) ); ``` ```typescript // TypeScript const unwrapOp = encodePacked( ["uint8", "uint8", "address", "address", "uint8", "uint128"], [TRANSFERS_COMMAND, TransferIds.UNWRAP_WNATIVE, wrappedNativeAddress, receiverAddress, SweepType.AMOUNT, amount] ) ``` ## Permit2 Transfer From Operation Execute a transfer via permit2. We only support the canonical Uniswap permit2 at address `0x000000000022D473030F116dDEE9F6B43aC78BA3`. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ------------------ | | 0 | 20 | asset `address` | | 20 | 20 | receiver `address` | | 40 | 16 | amount `uint128` | ### Notes If `amount` is `0`, we pull `asset.balanceOf(caller)`. ### Encoding Example ```solidity // Solidity bytes memory permit2TransferOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.PERMIT2_TRANSFER_FROM), assetAddress, receiverAddress, uint128(amount) ); ``` ```typescript // TypeScript const permit2TransferOp = encodePacked( ["uint8", "uint8", "address", "address", "uint128"], [TRANSFERS_COMMAND, TransferIds.PERMIT2_TRANSFER_FROM, assetAddress, receiverAddress, amount] ) ``` ## Approve Operation Approve an asset - typically for a lender operation or external call. ### Parameters | Offset | Length (bytes) | Description | | ------ | -------------- | ---------------- | | 0 | 20 | token `address` | | 20 | 20 | target `address` | ### Notes ERC20-Approve the `target` via `token`, always uses infinite approve, the approval is stored and skipped if already done in the past. ### Encoding Example ```solidity // Solidity bytes memory approveOp = abi.encodePacked( uint8(ComposerCommands.TRANSFERS), uint8(TransferIds.APPROVE), tokenAddress, targetAddress ); ``` ```typescript // TypeScript const approveOp = encodePacked(["uint8", "uint8", "address", "address"], [TRANSFERS_COMMAND, TransferIds.APPROVE, tokenAddress, targetAddress]) ``` --- ## Endpoints ## Data ## Data › Lending (Data) ### GET /v1/data/lending/comparables - operationId: `comparable-rates-for-one-pair` - docs: https://docs.1delta.io/1delta-api/comparable-rates-for-one-pair - tags: Lending (Data) Comparable rates for one pair The **N best comparable rates for a single pair**, priced at the caller’s size and holding period. One round-trip, small payload — built to sit behind a rate pill next to a borrow input. Unlike `/pairs/optimize` (rank every leveraged pair), this answers the question a borrow form asks: *I am about to borrow X of asset D against collateral C — what are the best rates for that same trade, at my size, over my horizon?* ## Three rates, deliberately kept apart - `aprPct` — what the venue advertises: spot at 0 notional, or top of book. - `aprAtAmountPct` — the same rate at **your size**. A utilization pool re-prices its whole balance to the post-borrow rate (marginal == average); an order book fills cheapest-first, so this is the VWAP of the tiers consumed. Null without an amount. - `effectiveAprPct` — the size-priced rate normalized to `horizonDays`. **This is what `rank` sorts on.** ## Horizon normalization A 4-week fixed rate and a floating pool are not comparable until both are priced over the same holding period. Each venue supplies a repayment rule: a Lista loan exited early pays roughly half the remaining term’s interest (`r·(T+h)/(2h)` — 1%/1yr exited at 6 months is **1.5% effective**); Midnight/Term charge no penalty but exiting means a resale at the then-current price (`horizon.priceRisk`); Exactly rebates unassigned earnings; a CDP’s one-time origination fee amortizes over the horizon, so it dominates on short holds. A horizon that outlasts the term assumes a roll at today’s rate and reports `locked: false`. Always render `horizon.locked` and `horizon.assumptions` next to the number — a normalized rate is not a contractual one. ## Obtainability is part of the answer Term Finance originates only inside periodic sealed-bid rounds; between rounds its rate card still quotes the LAST round’s clearing rate — real, but not takeable. Those rows are dropped by default and, with `includeUnobtainable=true`, returned flagged (`obtainable: false`, `quoteBasis: "last-clearing"`) and ranked last. A venue that cannot fund the requested size is marked `depth.capped` and demoted rather than ranked on a rate it can’t honour. ## Comparability filters (what makes this a comparison rather than a list) **Depth band** — `floor = min(minLiquidityRatio × anchor, liquidityFloorCapUsd)`, default `min(50% × anchor, $10M)`. A venue an order of magnitude shallower is a different product, and it is exactly those markets that quote absurd rates — a near-empty isolated market with reward emissions prices borrowing at **−25%**, a real number and a useless comparison against a $5B pool. The cap is not optional: a pure ratio breaks on the biggest pairs, where half of a $5B pool is a $2.5B floor nothing clears, so the comparison would come back empty exactly where alternatives matter most. The anchor is `referenceMarketUid`'s own depth when given, else the deepest candidate. `droppedIlliquid` + `liquidityFloorUsd` report it — the filter is never silent; `minLiquidityUsd` replaces the formula and `includeIlliquid=true` turns it off. **Stale venues.** A lender whose ingest lagged past the freshness window drops out of the underlying pairs view — which reads exactly like "that lender doesn't offer this pair". Those rows are excluded from ranking but **counted** (`droppedStale`, `staleMaxHours`), because a $19B deployment vanishing with no signal is worse than a short list. `includeStale=true` ranks them anyway. **One collateral basis.** When the caller pins no collateral (a standalone borrow form knows none), comparing "borrow USDC" across every collateral in existence is not a comparison. The server picks ONE representative collateral per chain — first hit in `collateralPreference` (default `ETH,BTC,USDC,USDT`), else the collateral group backing the deepest markets, which resolves to the wrapped native where neither is listed — and compares only venues backed by it. The choice comes back as `collateralBasis` (e.g. `{"1":"ETH"}`) so the UI can say *"vs WETH-backed"*. An explicit `collateral`/`collateralGroups` always wins and disables this. ## Rewards The headline rate folds in reward emissions (same composition as `/pairs/optimize`), which is why a borrow rate can be **negative**. That is real but transient, so each row also carries `rewardAprPct` and `aprExRewardsPct` — the structural cost without emissions. Ranking stays on the headline; showing both is the caller's job. ## Ranking `obtainable` first, then non-`capped`, then best `effectiveAprPct` (cheapest for a borrow, highest for a supply), then deepest liquidity as tie-break. Results are deduped to one row per `(chain, lender, market, term)` — the pairs view is combinatorial in the other leg, so without it the "5 best rates" would be five copies of the same market. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Single chain ID. When set, asset filters operate on token addresses. Pass one for an actionable list — cross-chain rows are a comparison, not one executable position. See the `ChainId` schema for the full set of supported chains. | | `chainIds` | query | string | no | CSV of chain IDs. When two or more, asset filters operate on asset groups. See the `ChainId` schema for the full set of supported chains. | | `side` | query | "borrow" \| "supply" | no | Which leg to compare. | | `debt` | query | string | no | The borrowed asset — address (single chain) or asset group. Required for `side=borrow`. Aliases: `debts`, `debtGroups`. | | `debtGroups` | query | string | no | CSV of debt-side asset groups (works in any chain mode). | | `collateral` | query | string | no | The collateral asset. Required for `side=supply`; strongly recommended for `side=borrow` — a market that will not take your collateral is not a comparable. Aliases: `collaterals`, `collateralGroups`. | | `collateralGroups` | query | string | no | CSV of collateral-side asset groups (works in any chain mode). | | `amount` | query | number | no | Notional in TOKEN UNITS of the priced leg (the debt asset for a borrow). Requires exactly one asset on that side. | | `amountUsd` | query | number | no | Same notional in USD. Works with multi-asset selections. Mutually exclusive with `amount`. | | `horizonDays` | query | number | no | Holding period every venue is repriced to. At 365 a floating pool’s effective rate equals its sticker rate. | | `rateType` | query | "all" \| "fixed" \| "float" | no | Post-filter applied before dedupe and ranking. | | `limit` | query | integer | no | How many comparables to return (max 25). | | `referenceMarketUid` | query | string | no | The venue the caller is already on. Returned as `reference` and excluded from `items`, so the pill can render "you: X% · best: Y%". | | `referenceTermId` | query | string | no | Disambiguates which term of the reference market is the caller’s own. | | `includeUnobtainable` | query | boolean | no | Keep quotes that cannot be taken right now (closed Term auction rounds), flagged and ranked last. | | `minLiquidityRatio` | query | number | no | Ratio side of the depth floor `min(ratio × anchor, cap)`. | | `liquidityFloorCapUsd` | query | number | no | Cap side of the depth floor — stops a huge anchor from demanding a comparably huge venue and returning nothing. | | `minLiquidityUsd` | query | number | no | Absolute USD depth floor that REPLACES the computed `min(ratio × anchor, cap)`. | | `includeStale` | query | boolean | no | Rank venues whose market data is older than the freshness window. Excluded but counted (`droppedStale`) by default. | | `includeIlliquid` | query | boolean | no | Disable the depth band entirely and rank every venue regardless of size. | | `collateralPreference` | query | string | no | CSV of collateral asset groups tried in order when picking the comparison basis (only used when no collateral is pinned). | | `lenders` | query | string | no | CSV of lender keys (prefix-expanded) to restrict the comparison to. See the `LenderId` schema for the full set of accepted values. | | `excludeLenders` | query | string | no | CSV of lender keys to exclude (prefix-expanded). | | `maxConfigRiskScore` | query | number | no | Config-risk ceiling (default 4, as on the pair endpoints). | | `maxTokenRiskScore` | query | number | no | Token-risk ceiling across both legs. | **Response `200`** — Comparable rates | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.side` | "borrow" \| "supply" | | | `data.horizonDays` | number | | | `data.amount` | number | | | `data.amountUsd` | number | | | `data.chainIds` | string[] | EVM chain ids, as decimal strings. See the `ChainId` schema. | | `data.scanned` | integer | Pair rows considered before ranking. | | `data.truncated` | boolean | The candidate guard cap bound, so ranking saw only the deepest rows — narrow the filter. Never a silent trim. | | `data.available` | integer | Distinct comparables that existed before `limit` was applied. | | `data.liquidityFloorUsd` | number | Venues below this USD depth were dropped as not comparable (0 = no floor applied). | | `data.droppedIlliquid` | integer | How many venues the depth band removed. An opinionated filter must never be silent — surface this rather than implying nothing else exists. | | `data.droppedStale` | integer | Venues excluded because their market data is older than `staleMaxHours` — an ingest lag, not an absent lender. Non-zero is the difference between "no one else offers this pair" and "we cannot currently see who does". `includeStale=true` ranks them anyway. | | `data.staleMaxHours` | number | The freshness window `droppedStale` was measured against. | | `data.collateralBasis` | object | The single collateral group each chain's rows were compared against when the caller pinned none, e.g. `{"1":"ETH"}`. Empty when a collateral was supplied, or on the supply side. | | `data.reference` | object | The venue the caller is already on (`referenceMarketUid`), pulled out of `items` so the UI can render "you: X% · best: Y%". | | `data.reference.rank` | integer | 1-based position in the ranking. `0` on the `reference` item. | | `data.reference.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.reference.lender` | string | Raw lender key — stable, use it for keying and deeplinks. Per-market lenders (Morpho Blue, Silo, Euler) encode a hashed market id here, so it is NOT presentable. | | `data.reference.lenderName` | string | Display name from the lender registry, falling back to the raw key when none is registered. This is what a UI should render. | | `data.reference.lenderLogoUri` | string | | | `data.reference.marketUid` | string | The market the rate belongs to: the debt market for a borrow quote, the collateral market for a supply quote. | | `data.reference.marketName` | string | | | `data.reference.curatorName` | string | | | `data.reference.eMode` | string | | | `data.reference.rateType` | "fixed" \| "float" | | | `data.reference.rateModel` | "variable" \| "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| … (9 values) | Which repayment rule priced this quote. | | `data.reference.aprPct` | number | Sticker rate, APR %. Includes intrinsic yield and reward APR (same composition as `borrowAprShort` / `depositAprLong`); a one-time origination fee is NOT in it — the horizon model amortizes that separately. | | `data.reference.aprAtAmountPct` | number | The rate at the requested size. Null when no amount was supplied. A utilization pool re-prices its whole balance to the post-action rate; an order book fills cheapest-first, so this is the VWAP of the tiers consumed. | | `data.reference.rewardAprPct` | number | Reward emissions folded into the headline (positive = subsidising a borrow). Large emissions can push a borrow rate NEGATIVE. | | `data.reference.aprExRewardsPct` | number | The rate WITHOUT reward emissions — the structural, sustainable cost. Show it next to a reward-inflated headline; emissions are transient. | | `data.reference.effectiveAprPct` | number | Size-priced rate normalized to `horizonDays`. The ranking number. | | `data.reference.costPct` | number | Total cost over the horizon as a percent of principal. | | `data.reference.horizon` | object | How the effective rate was arrived at — the caveats a UI must show next to a normalized number. | | `data.reference.horizon.basis` | "flat-forward" \| "early-exit" \| "held-to-maturity" \| "rolled" | `flat-forward`: no maturity, today’s floating rate assumed to hold. `early-exit`: horizon shorter than the term, the venue’s exit rule applied. `held-to-maturity`: horizon matches the term (the clean case). `rolled`: horizon outlasts the term, a roll at today’s rate assumed. | | `data.reference.horizon.locked` | boolean | Is the rate contractually fixed for the WHOLE horizon? False for floating pools and for a fixed term that has to be rolled to cover the horizon. | | `data.reference.horizon.priceRisk` | boolean | Exiting early means unwinding on an order book at the then-current price (Midnight/Term), so the realized cost can land either side of the quote. Not priced in — flagged. | | `data.reference.horizon.assumptions` | string[] | Display-ready caveats, most important first. | | `data.reference.termId` | string | | | `data.reference.durationDays` | number | | | `data.reference.maturity` | number | Calendar maturity, unix seconds. Null for rolling menus and variable pools. | | `data.reference.termDays` | number | Remaining term in days for a position opened now. | | `data.reference.obtainable` | boolean | Can this rate be taken right now? False for a Term repo between auction rounds, whose rate card still quotes the last round’s clearing rate. | | `data.reference.obtainableReason` | string | | | `data.reference.quoteBasis` | "live" \| "last-clearing" | `last-clearing` marks a historical print, not an obtainable quote — never render it as an actionable rate. | | `data.reference.depth` | object | | | `data.reference.depth.fillable` | number | Depth ceiling in token units of the priced leg — borrow liquidity for a pool, total book depth for an order book. | | `data.reference.depth.capped` | boolean | The requested amount exceeds `fillable`: this venue cannot fund the position at that size, and the row is demoted below every non-capped one. | | `data.reference.depth.liquidityUsd` | number | | | `data.reference.depth.utilization` | number | Market utilization, as a fraction between 0 and 1. | | `data.reference.collateral` | object | | | `data.reference.collateral.address` | string | EVM contract address, lowercase or checksummed hex. | | `data.reference.collateral.assetGroup` | string | Group of economically equivalent assets, e.g. all USDC variants. | | `data.reference.collateral.symbol` | string | Token symbol, e.g. `WETH`. | | `data.reference.collateral.decimals` | number | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.reference.collateral.logoUri` | string | URL of the logo image. | | `data.reference.collateral.marketUid` | string | Market identifier, formatted `lender:chainId:address`. | | `data.reference.debt` | object | | | `data.reference.debt.address` | string | EVM contract address, lowercase or checksummed hex. | | `data.reference.debt.assetGroup` | string | Group of economically equivalent assets, e.g. all USDC variants. | | `data.reference.debt.symbol` | string | Token symbol, e.g. `WETH`. | | `data.reference.debt.decimals` | number | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.reference.debt.logoUri` | string | URL of the logo image. | | `data.reference.debt.marketUid` | string | Market identifier, formatted `lender:chainId:address`. | | `data.reference.maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data.reference.ltv` | number | Loan-to-value ratio, as a fraction between 0 and 1. | | `data.reference.risk` | object | | | `data.reference.risk.configScore` | number | | | `data.reference.risk.maxTokenScore` | number | | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object[] | The result set for this response. | | `data.items[].rank` | integer | 1-based position in the ranking. `0` on the `reference` item. | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].lender` | string | Raw lender key — stable, use it for keying and deeplinks. Per-market lenders (Morpho Blue, Silo, Euler) encode a hashed market id here, so it is NOT presentable. | | `data.items[].lenderName` | string | Display name from the lender registry, falling back to the raw key when none is registered. This is what a UI should render. | | `data.items[].lenderLogoUri` | string | | | `data.items[].marketUid` | string | The market the rate belongs to: the debt market for a borrow quote, the collateral market for a supply quote. | | `data.items[].marketName` | string | | | `data.items[].curatorName` | string | | | `data.items[].eMode` | string | | | `data.items[].rateType` | "fixed" \| "float" | | | `data.items[].rateModel` | "variable" \| "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| … (9 values) | Which repayment rule priced this quote. | | `data.items[].aprPct` | number | Sticker rate, APR %. Includes intrinsic yield and reward APR (same composition as `borrowAprShort` / `depositAprLong`); a one-time origination fee is NOT in it — the horizon model amortizes that separately. | | `data.items[].aprAtAmountPct` | number | The rate at the requested size. Null when no amount was supplied. A utilization pool re-prices its whole balance to the post-action rate; an order book fills cheapest-first, so this is the VWAP of the tiers consumed. | | `data.items[].rewardAprPct` | number | Reward emissions folded into the headline (positive = subsidising a borrow). Large emissions can push a borrow rate NEGATIVE. | | `data.items[].aprExRewardsPct` | number | The rate WITHOUT reward emissions — the structural, sustainable cost. Show it next to a reward-inflated headline; emissions are transient. | | `data.items[].effectiveAprPct` | number | Size-priced rate normalized to `horizonDays`. The ranking number. | | `data.items[].costPct` | number | Total cost over the horizon as a percent of principal. | | `data.items[].horizon` | object | How the effective rate was arrived at — the caveats a UI must show next to a normalized number. | | `data.items[].horizon.basis` | "flat-forward" \| "early-exit" \| "held-to-maturity" \| "rolled" | `flat-forward`: no maturity, today’s floating rate assumed to hold. `early-exit`: horizon shorter than the term, the venue’s exit rule applied. `held-to-maturity`: horizon matches the term (the clean case). `rolled`: horizon outlasts the term, a roll at today’s rate assumed. | | `data.items[].horizon.locked` | boolean | Is the rate contractually fixed for the WHOLE horizon? False for floating pools and for a fixed term that has to be rolled to cover the horizon. | | `data.items[].horizon.priceRisk` | boolean | Exiting early means unwinding on an order book at the then-current price (Midnight/Term), so the realized cost can land either side of the quote. Not priced in — flagged. | | `data.items[].horizon.assumptions` | string[] | Display-ready caveats, most important first. | | `data.items[].termId` | string | | | `data.items[].durationDays` | number | | | `data.items[].maturity` | number | Calendar maturity, unix seconds. Null for rolling menus and variable pools. | | `data.items[].termDays` | number | Remaining term in days for a position opened now. | | `data.items[].obtainable` | boolean | Can this rate be taken right now? False for a Term repo between auction rounds, whose rate card still quotes the last round’s clearing rate. | | `data.items[].obtainableReason` | string | | | `data.items[].quoteBasis` | "live" \| "last-clearing" | `last-clearing` marks a historical print, not an obtainable quote — never render it as an actionable rate. | | `data.items[].depth` | object | | | `data.items[].depth.fillable` | number | Depth ceiling in token units of the priced leg — borrow liquidity for a pool, total book depth for an order book. | | `data.items[].depth.capped` | boolean | The requested amount exceeds `fillable`: this venue cannot fund the position at that size, and the row is demoted below every non-capped one. | | `data.items[].depth.liquidityUsd` | number | | | `data.items[].depth.utilization` | number | Market utilization, as a fraction between 0 and 1. | | `data.items[].collateral` | object | | | `data.items[].collateral.address` | string | EVM contract address, lowercase or checksummed hex. | | `data.items[].collateral.assetGroup` | string | Group of economically equivalent assets, e.g. all USDC variants. | | `data.items[].collateral.symbol` | string | Token symbol, e.g. `WETH`. | | `data.items[].collateral.decimals` | number | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].collateral.logoUri` | string | URL of the logo image. | | `data.items[].collateral.marketUid` | string | Market identifier, formatted `lender:chainId:address`. | | `data.items[].debt` | object | | | `data.items[].debt.address` | string | EVM contract address, lowercase or checksummed hex. | | `data.items[].debt.assetGroup` | string | Group of economically equivalent assets, e.g. all USDC variants. | | `data.items[].debt.symbol` | string | Token symbol, e.g. `WETH`. | | `data.items[].debt.decimals` | number | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].debt.logoUri` | string | URL of the logo image. | | `data.items[].debt.marketUid` | string | Market identifier, formatted `lender:chainId:address`. | | `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data.items[].ltv` | number | Loan-to-value ratio, as a fraction between 0 and 1. | | `data.items[].risk` | object | | | `actions` | null | | **Example response** ```json { "success": true, "data": { "side": "borrow", "horizonDays": 1, "amount": 1, "amountUsd": 1, "chainIds": [ "1" ], "scanned": 1, "truncated": true, "available": 1, "liquidityFloorUsd": 1, "droppedIlliquid": 1, "droppedStale": 1, "staleMaxHours": 1, "collateralBasis": {}, "reference": { "rank": 1, "chainId": "1", "lender": "AAVE_V3", "lenderName": "AAVE_V3", "lenderLogoUri": "AAVE_V3", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "marketName": "string", "curatorName": "string", "eMode": "string", "rateType": "fixed", "rateModel": "variable", "aprPct": 1, "aprAtAmountPct": 1, "rewardAprPct": 1, "aprExRewardsPct": 1, "effectiveAprPct": 1, "costPct": 1, "horizon": { "basis": "flat-forward", "locked": true, "priceRisk": true, "assumptions": [ "string" ] }, "termId": "string", "durationDays": 1, "maturity": 1, "termDays": 1, "obtainable": true, "obtainableReason": "string", "quoteBasis": "live", "depth": { "fillable": 1, "capped": true, "liquidityUsd": 1, "utilization": 1 }, "collateral": { "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "assetGroup": "string", "symbol": "string", "decimals": 1, "logoUri": "string", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, "debt": { "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "assetGroup": "string", "symbol": "string", "decimals": 1, "logoUri": "string", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, "maxLeverage": 1, "ltv": 1, "risk": { "configScore": 1, "maxTokenScore": 1 } }, "count": 1, "items": [ { "rank": 1, "chainId": "1", "lender": "AAVE_V3", "lenderName": "AAVE_V3", "lenderLogoUri": "AAVE_V3", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "marketName": "string", "curatorName": "string", "eMode": "string", "rateType": "fixed", "rateModel": "variable", "aprPct": 1, "aprAtAmountPct": 1, "rewardAprPct": 1, "aprExRewardsPct": 1, "effectiveAprPct": 1, "costPct": 1, "horizon": { "basis": "flat-forward", "locked": true, "priceRisk": true, "assumptions": [ "string" ] }, "termId": "string", "durationDays": 1, "maturity": 1, "termDays": 1, "obtainable": true, "obtainableReason": "string", "quoteBasis": "live", "depth": { "fillable": 1, "capped": true, "liquidityUsd": 1, "utilization": 1 }, "collateral": { "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "assetGroup": "string", "symbol": "string", "decimals": 1, "logoUri": "string", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, "debt": { "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "assetGroup": "string", "symbol": "string", "decimals": 1, "logoUri": "string", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" }, "maxLeverage": 1, "ltv": 1, "risk": { "configScore": 1, "maxTokenScore": 1 } } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/irm - operationId: `irm-rate-curves` - docs: https://docs.1delta.io/1delta-api/irm-rate-curves - tags: Lending (Data) IRM rate curves Return sampled borrow and deposit rate curves for one or more markets. Each curve is a series of `(utilization, borrowRate, depositRate)` points spanning 0% to 100% utilization. Rates are **APR %** (e.g. `5.5` = 5.5% APR). Supported protocols: `aave`, `aave_v4`, `compound_v2`, `compound_v3`, `morpho` (including Lista), `euler_v2`, `silo`, `fluid`, `gearbox`, `dolomite`. **Caching:** IRM parameters are quasi-static and cached server-side for 1 hour. Computed curves are also cached (keyed by market UIDs + data-point count). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUids` | query | string | yes | Comma-separated market UIDs, e.g. `AAVE_V3:1:0xa0b8...` | | `dataPoints` | query | integer | no | Number of curve sample points (1–20, default 20) | **Response `200`** — Rate curves per market | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `data.count` | integer | Number of markets returned | | `data.items` | object[] | The result set for this response. | | `data.items[].marketUid` | string | Unique market identifier (`lenderKey:chainId:address`) | | `data.items[].protocol` | "aave" \| "aave_v4" \| "compound_v2" \| "compound_v3" \| "morpho" \| "euler_v2" \| … (10 values) | IRM model type | | `data.items[].lenderKey` | string | | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].underlyingAddress` | string | | | `data.items[].marketName` | string | | | `data.items[].points` | object[] | Sampled rate curve. Length = dataPoints + 1 (includes u=0 and u=1). | | `data.items[].points[].utilization` | number | Utilization ratio (0–1) | | `data.items[].points[].borrowRate` | number | Variable borrow rate (APR %, e.g. 7.67 = 7.67%) | | `data.items[].points[].depositRate` | number | Deposit/supply rate (APR %, e.g. 3.30 = 3.30%) | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": [ { "marketUid": "SPARK:100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0", "protocol": "aave", "lenderKey": "SPARK", "chainId": "100", "underlyingAddress": "0x2a22f9c3b484c3629090feed35f17ff8f88f76f0", "marketName": "Spark USDC.e", "points": [ { "utilization": 0.95, "borrowRate": 7.67, "depositRate": 3.3 } ] } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/irm/depth - operationId: `rate-at-depth-rate-vs-borrow-supply-amount` - docs: https://docs.1delta.io/1delta-api/rate-at-depth-rate-vs-borrow-supply-amount - tags: Lending (Data) Rate-at-depth (rate vs borrow/supply amount) Return rate-at-depth data — the amount-axis complement of `/v1/data/lending/irm` (rate vs utilization). Two shapes, both optional: - **grid** (default): a `borrow`/`supply` sweep from 0 to the fillable ceiling — for charts. Disable with `grid=false`. - **rateAtAmount**: pass `amount(s)` (token units) and/or `amount(s)Usd` (USD) to get the rate + resulting utilization + fillable ceiling at each specific size — the answer to *"what rate to borrow X"*. For a utilization pool the whole balance re-prices to one rate, so `rateAtAmount` is the marginal spot rate at the post-action utilization (marginal == average). Order-book venues (Midnight) fill best-first, so their `rateAtAmount` is a **volume-weighted average** over the consumed ladder. Lista's brokered borrow leg is a **flat fixed** rate up to capacity. Rates are **APR %**. **Caching:** computed grids/points cached server-side for 1 hour (keyed by UIDs + side + points + amounts). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUids` | query | string | yes | Comma-separated market UIDs, e.g. `GEARBOX_V3_0x…:9745:0x…` | | `side` | query | string | no | `borrow` \| `supply` \| `both` (default `borrow`) | | `dataPoints` | query | integer | no | Samples per grid (1–60, default 24) | | `amounts` | query | string | no | Comma-separated sizes in TOKEN units → adds `rateAtAmount[]`. `amount` is accepted as a singular alias. | | `amountsUsd` | query | string | no | Comma-separated sizes in USD (converted per market via its price). `amountUsd` alias accepted. | | `grid` | query | string | no | Set `false` to drop the 0→max grid sweep (points-only). | **Response `200`** — Depth grids and/or rate-at-amount points per market | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object[] | The result set for this response. | | `data.items[].marketUid` | string | Market identifier, formatted `lender:chainId:address`. | | `data.items[].protocol` | string | | | `data.items[].lenderKey` | string | | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].underlyingAddress` | string | | | `data.items[].utilization` | number | Current utilization (0–1) | | `data.items[].variableBorrowRate` | number | Current 0-notional borrow APR % | | `data.items[].borrow` | object | Rate-vs-amount sweep from size 0 to `fillable`. | | `data.items[].borrow.side` | "borrow" \| "supply" | | | `data.items[].borrow.currentUtilization` | number | | | `data.items[].borrow.currentBorrowAprPct` | number | | | `data.items[].borrow.currentDepositAprPct` | number | | | `data.items[].borrow.fillable` | number | Largest size sampled — the depth ceiling (token units). | | `data.items[].borrow.fillableUsd` | number | | | `data.items[].borrow.points` | object[] | | | `data.items[].borrow.points[].size` | number | Cumulative size (token units) | | `data.items[].borrow.points[].sizeUsd` | number | | | `data.items[].borrow.points[].utilization` | number | Market utilization, as a fraction between 0 and 1. | | `data.items[].borrow.points[].borrowAprPct` | number | | | `data.items[].borrow.points[].depositAprPct` | number | | | `data.items[].supply` | object | Rate-vs-amount sweep from size 0 to `fillable`. | | `data.items[].supply.side` | "borrow" \| "supply" | | | `data.items[].supply.currentUtilization` | number | | | `data.items[].supply.currentBorrowAprPct` | number | | | `data.items[].supply.currentDepositAprPct` | number | | | `data.items[].supply.fillable` | number | Largest size sampled — the depth ceiling (token units). | | `data.items[].supply.fillableUsd` | number | | | `data.items[].supply.points` | object[] | | | `data.items[].supply.points[].size` | number | Cumulative size (token units) | | `data.items[].supply.points[].sizeUsd` | number | | | `data.items[].supply.points[].utilization` | number | Market utilization, as a fraction between 0 and 1. | | `data.items[].supply.points[].borrowAprPct` | number | | | `data.items[].supply.points[].depositAprPct` | number | | | `data.items[].rateAtAmount` | object[] | Rate + fillable at each requested size (present only when `amount(s)`/`amount(s)Usd` is passed). | | `data.items[].rateAtAmount[].side` | "borrow" \| "supply" | | | `data.items[].rateAtAmount[].size` | number | Requested size (token units) | | `data.items[].rateAtAmount[].amountUsd` | number | | | `data.items[].rateAtAmount[].utilization` | number | Post-action utilization (0 for order books) | | `data.items[].rateAtAmount[].borrowAprPct` | number | | | `data.items[].rateAtAmount[].depositAprPct` | number | | | `data.items[].rateAtAmount[].fillable` | number | Max borrowable/suppliable before a cap binds (token units) | | `data.items[].rateAtAmount[].capped` | boolean | True when `size` exceeds `fillable` — rate is reported at the ceiling. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": [ { "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "protocol": "string", "lenderKey": "AAVE_V3", "chainId": "1", "underlyingAddress": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "utilization": 1, "variableBorrowRate": 1, "borrow": { "side": "borrow", "currentUtilization": 1, "currentBorrowAprPct": 1, "currentDepositAprPct": 1, "fillable": 1, "fillableUsd": 1, "points": [ { "size": 1, "sizeUsd": 1, "utilization": 1, "borrowAprPct": 1, "depositAprPct": 1 } ] }, "supply": { "side": "borrow", "currentUtilization": 1, "currentBorrowAprPct": 1, "currentDepositAprPct": 1, "fillable": 1, "fillableUsd": 1, "points": [ { "size": 1, "sizeUsd": 1, "utilization": 1, "borrowAprPct": 1, "depositAprPct": 1 } ] }, "rateAtAmount": [ { "side": "borrow", "size": 1, "amountUsd": 1, "utilization": 1, "borrowAprPct": 1, "depositAprPct": 1, "fillable": 1, "capped": true } ] } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/isolated-markets/meta - operationId: `get-isolated-market-metadata` - docs: https://docs.1delta.io/1delta-api/get-isolated-market-metadata - tags: Lending (Data) Get isolated market metadata Returns Morpho isolated market metadata including fee, LLTV, oracle, IRM, and listing status for all markets, optionally filtered by chain. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. | **Response `200`** — Isolated market metadata | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/latest - operationId: `lending-latest` - docs: https://docs.1delta.io/1delta-api/lending-latest - tags: Lending (Data) Get latest lending data (paginated by lender) Returns latest per-market lending data for the requested chains, scoped to a specific page of lender keys. **Pagination** Both `chains` and `lenders` are required. A maximum of **20 lender keys** may be supplied per request. Use [`GET /v1/data/lending/lenders`](/1delta-api/lending-lenders) to enumerate available lender keys (sorted by TVL) and page through them in batches of up to 20: ``` GET /v1/data/lending/lenders?chains=1,8453 → enumerate keys GET /v1/data/lending/latest?chains=1,8453&lenders=k1,…,k20 → page 1 GET /v1/data/lending/latest?chains=1,8453&lenders=k21,…,k40 → page 2 ``` **Breaking changes vs previous /lending/latest** - `lenders` is now required. - Hard cap of 20 lender keys per request. - Top-level `lenderKey` field is removed from items — use `lenderInfo.key`. **Lista DAO fixed-term (brokered) markets:** a market is brokered when its `terms[]` rate card is non-empty and `flags.variableBorrowDisabled === true`. Such markets report `variableBorrowRate = 0` but cannot be borrowed variably through 1delta — read `terms[]` for the available fixed terms and their APRs, and `broker` for the gateway contract. See the `MarketTerm` schema. **Morpho Midnight order-book markets (`MORPHO_MIDNIGHT_`):** liquidity is an order book of maker offers, not a pool. Pass `includeOffers=true` to attach the live two-sided ladder to each such market's loan leg: `offers` (bids — the demand a borrower TAKES) and `lendOffers` (asks — the supply a lender TAKES), both best-first with per-level `aprPct`, `assets`, `assetsUsd`, and `cumulativeAssets`. Plain pool markets return no offers (their single rate suffices). This is the read side of **TAKE**; to fill offers use the standard [deposit](/1delta-api/lending-deposit)/[borrow](/1delta-api/lending-borrow) actions, and to **MAKE** your own offer see [`/v1/actions/midnight/make`](/1delta-api/midnight-make). **Teller markets (`TELLER_`):** fixed-term, fixed-APR pool loans with **TIME-based liquidation** — collateral is seized only on a missed payment past the market window, never on a price move (no margin calls). `fixedTerm.model = "teller"`, `provider.kind = "pool"`, rolling duration up to `teller.maxLoanDuration`. ⚠ **AGGRESSIVE default terms — surface these prominently:** on default the borrower can lose their **ENTIRE escrowed collateral** (a liquidator seizes all of it, not just the amount owed — at a 50% LTV that's ~2× the borrowed value), and the grace window after the term can be **very short** (`params.market.teller.paymentDefaultDuration`, observed as low as **300 s / 5 min**). There is also an **upfront origination fee** (`teller.originationFeePercent` = `marketFeeBps` + `protocolFeeBps`, also on `fixedTerm.fees.originationFeePercent`). The market descriptor (`params.market.teller`) carries the read-side facts the UI should surface: **`implications`** (a ready-to-display string list — lead with the full-collateral-liquidation warning), **`paymentDefaultDuration`**, **`originationFeePercent`**, **`requiresBorrowerAttestation`** (this market only lets whitelisted borrowers open loans — a non-attested account is rejected at borrow time, so gate the borrow CTA on this flag), and **`marketOpen`** (a closed market reports `borrowingEnabled = false`). Borrowing is one atomic `POST /v1/actions/lending/deposit-and-borrow`; closing is a FULL `POST /v1/actions/lending/withdraw-and-repay` (repays everything and releases all collateral — Teller has no partial collateral withdrawal; `posId` = the `bidId` to close). Borrower positions are `bidId`-keyed sub-accounts. **Term Finance markets (`TERM_FINANCE_`):** fixed-rate, fixed-maturity tri-party repo. One repo per maturity, so a pair has many lender keys that differ only by date — read `lenderInfo.name` (e.g. "Term USDC / wstETH — 2026-09-03") rather than the raw key. `fixedTerm.model = "term"`, `provider.kind = "auction"`, `flags.variableBorrowDisabled = true` (there is no variable rate — a `variableBorrowRate` of 0 is NOT a free borrow). ⚠ **Borrowing is only possible inside a scheduled sealed-bid auction round, and most repos are between rounds at any given time** (live Ethereum book: typically ~3 of ~84). `fixedTerm.auction` carries the window and is the gate: - **`canBorrow`** — gate the borrow CTA on this, NOT on `status` or on the presence of a rate. It is true only while a round is accepting submissions. - **`canLend`** — deliberately independent of `canBorrow`: lending also works between rounds by buying repo tokens on the secondary market, so a closed round leaves the market lend-only, not inert. Do not grey out the whole market. - **`status`** — `upcoming` | `open` | `revealing` (bidding shut, prices revealing) | `closed` (no round listed). - **`secondsUntilClose`**, **`startTime`**, **`revealTime`** (the deadline to act), **`endTime`** — unix seconds; derive a live countdown from `revealTime` rather than trusting `secondsUntilClose` against a cached response. - **`minBorrowAmount`** / **`minLendAmount`** — a real per-round floor in loan-token base units (e.g. 1000 USDC). A smaller amount cannot be submitted at all, so validate before building. - **`implications`** — ready-to-display string list, most important first (same convention as `params.market.teller.implications`). `terms[]` is emitted ONLY while `canBorrow` is true, so an empty rate card on a Term market means "not borrowable right now", not "no offers". When a round is open on a repo that has never cleared, `terms[]` is legitimately empty and `variableBorrowRate` is 0: the rate is whatever you bid, set at clearing. **Any rate shown outside an open round is the previous round's clearing rate — historical, not obtainable** (it still prices the secondary lend book, which is why it is reported at all). **Term sheets (`termSheet`):** every market carries a structured description of its lend and borrow offer under one shape, for every lender we serve — pool lenders, fixed-term lenders, CDPs and vaults alike. `termSheet.supply` and `termSheet.borrow` each answer rate, maturity, fees, exit terms, liquidation, counterparty and availability; `termSheet.governance`, `.oracle`, `.utilization` and `.constraints` describe the market as a whole. Absence of a side is meaningful: no `borrow` means the market cannot be borrowed. Read `info.headline` and `info.tags` for a ready-to-render summary, and `info.implications[]` (ordered most-important-first) for the consequences that a rate alone hides — a Teller borrow can lose its ENTIRE collateral after a grace window as short as 300 s, a TermMax lender can be settled in collateral instead of the asset they lent, and a Liquity trove can be redeemed at par while perfectly healthy. `coverage` distinguishes "does not apply here" (`notApplicable`, e.g. Teller genuinely has no oracle) from "not classified yet" (`pending`) — a missing block is never a claim of absence. Every string field is an OPEN enum: new members are added additively and MUST NOT break a client. Give every `switch` a `default` branch and fall back to `info.headline`, which is always populated. **Oracle risk:** each market carries an `oracleInfo` object classifying its price oracle's feed correctness (provider, reported vs intended pair, a 0–100 `worstScore`/`worstBand`, and `flags` such as `wrong-asset`/`correlated-proxy`/`cross-numeraire`). This is distinct from the price-staleness signal in `risk.breakdown[oracle]`. See the `OracleInfo` schema for the full scoring model. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chains` | query | string[] | yes | Chain IDs to query (repeatable, CSV also accepted) | | `lenders` | query | string[] | yes | Lender keys to fetch (repeatable, CSV also accepted). Max 20 per request. See the `LenderId` schema for the full set of accepted values. | | `maxRiskScore` | query | integer | no | Max risk score (1–5). Defaults to 4. | | `terms` | query | "digest" \| "full" \| "none" | no | Term-sheet depth attached to every market as `termSheet`. `digest` (default) is the compact form — headline, tags, rate/maturity/exit/liquidation summary and the exposure ROLLUP, but no `items[]` and no long prose. `full` inlines the complete sheet including `backedBy.items[]` / `acceptedCollateral.items[]` and `info.description` + `info.implications[]`. `none` omits the field entirely. Every exposure item carries its own `marketUid`, so `digest` is not a dead end — resolve the ones you need in one call. | | `includeOffers` | query | boolean | no | Order-book markets (Morpho Midnight) only. When `true`, attach the live maker-offer ladder to each order-book market’s loan leg (`offers` = bids, `lendOffers` = asks). Ignored for pool markets. Defaults to `false`. | **Response `200`** — Latest lending data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Latest lending market data as a flat list of lender/chain entries. Returns only the lender keys requested via `lenders=…` (max 20 per request). | | `data.count` | integer | Number of lender/chain entries | | `data.items` | object[] | Flat array of lender/chain entries | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].lenderInfo` | object | Protocol/lender metadata (name, logo). | | `data.items[].lenderInfo.key` | string | Lender key identifier | | `data.items[].lenderInfo.name` | string | Human-readable lender name | | `data.items[].lenderInfo.logoURI` | string | Lender logo URL | | `data.items[].lastFetched` | number | Epoch ms of latest snapshot | | `data.items[].totalDepositsUsd` | number | Total deposits across all markets in USD | | `data.items[].totalDebtUsd` | number | Total debt across all markets in USD | | `data.items[].tvlUsd` | number | Total value locked in USD (deposits - debt) | | `data.items[].params` | object | Lender-specific parameters. Only present for Morpho/Lista lenders (e.g. `{ market: { … } }`). | | `data.items[].fixedTerm` | object | Fixed-term descriptor for this lender key. Absent/null on variable-rate lenders. For Term Finance read `fixedTerm.auction.canBorrow` before offering a borrow — most repos sit between auction rounds and cannot be borrowed even though they quote a rate. | | `data.items[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data.items[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data.items[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data.items[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data.items[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data.items[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data.items[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data.items[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data.items[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data.items[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data.items[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data.items[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data.items[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data.items[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data.items[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data.items[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data.items[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data.items[].markets` | object[] | Individual lending markets for this lender on this chain | | `data.items[].markets[].lenderKey` | string | Protocol identifier | | `data.items[].markets[].poolId` | string | Pool/vault address or protocol-specific ID | | `data.items[].markets[].depositRate` | number | Deposit APR (percent) | | `data.items[].markets[].variableBorrowRate` | number | Variable borrow APR (percent) | | `data.items[].markets[].stableBorrowRate` | number | Stable borrow APR (percent) | | `data.items[].markets[].intrinsicYield` | number | Intrinsic yield APR from underlying asset (e.g. stETH staking) | | `data.items[].markets[].totalDeposits` | number | Total deposits in token units | | `data.items[].markets[].totalDebtStable` | number | Total stable debt in token units | | `data.items[].markets[].totalDebt` | number | Total variable debt in token units | | `data.items[].markets[].totalLiquidity` | number | Available liquidity (totalDeposits - totalDebt) in token units | | `data.items[].markets[].totalDepositsUsd` | number | Total deposits in USD | | `data.items[].markets[].totalDebtStableUsd` | number | Total stable debt in USD | | `data.items[].markets[].totalDebtUsd` | number | Total variable debt in USD | | `data.items[].markets[].totalLiquidityUsd` | number | Available liquidity in USD | | `data.items[].markets[].utilization` | number | Utilization ratio (totalDebt / totalDeposits) | | `data.items[].markets[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].markets[].underlyingInfo` | object | Nested asset metadata, oracle prices, and market prices for a lending market. | | `data.items[].markets[].underlyingInfo.asset` | object | Token metadata for an underlying asset. | | `data.items[].markets[].underlyingInfo.oraclePrice` | object | On-chain oracle price data. | | `data.items[].markets[].underlyingInfo.prices` | object | Market prices for an asset with 24h comparison. | | `data.items[].markets[].oracleInfo` | object | Oracle feed-correctness classification for the market's price oracle(s). `null` when the market has no oracle classification. This is **feed correctness** — does the oracle price the right asset in the right unit — and is distinct from the price-*staleness* signal carried in `risk.breakdown[oracle]` (a 1–5 score). A market can have several feeds (Compound comets price each collateral asset; Fluid prices each vault side), so `feeds` is an array and `worstScore`/`worstBand` summarize the riskiest one. **Scoring (per feed, additive):** `score = provider base + flag penalties`, clamped 0–100. Provider base (oracle mechanism; first match wins): \| Provider \| Base \| \|---\|---\| \| `chainlink`, `price-cap` \| 10 \| \| `redstone`/`pyth`/`chronicle`/… and *unrecognized* \| 18 \| \| `composite` / cross-feed \| 22 \| \| `exchange-rate` / `pendle-pt` / LST rate adapters \| 28 \| \| `twap`/`uniswap`/DEX \| 30 \| \| `fixed-rate` / `constant` \| 55 \| Flag penalties (added on top): `wrong-asset` +45 · `correlated-proxy` +18 · `cross-numeraire` +18 · `undecoded-source` +8. Bands: **LOW** < 25 · **MEDIUM** 25–49 · **HIGH** 50–74 · **CRITICAL** ≥ 75. | | `data.items[].markets[].oracleInfo.feeds` | object[] | Per-feed classifications, ordered worst-first. | | `data.items[].markets[].oracleInfo.worstScore` | integer | Highest (worst) `score` across `feeds`. | | `data.items[].markets[].oracleInfo.worstBand` | "LOW" \| "MEDIUM" \| "HIGH" \| "CRITICAL" | Band of the worst feed. | | `data.items[].markets[].caps` | object | Supply, borrow, and debt ceiling caps for a lending market. | | `data.items[].markets[].caps.borrowCap` | number | Maximum borrowable amount (token units) | | `data.items[].markets[].caps.supplyCap` | number | Maximum depositable amount (token units) | | `data.items[].markets[].caps.debtCeiling` | string | Isolation-mode debt ceiling | | `data.items[].markets[].flags` | object | Boolean flags describing the operational status of a lending market. Values may be null if unavailable from the protocol. | | `data.items[].markets[].flags.isActive` | boolean | Whether the market is active | | `data.items[].markets[].flags.isFrozen` | boolean | Whether the market is frozen (no new deposits/borrows) | | `data.items[].markets[].flags.hasStable` | boolean | Whether stable-rate borrowing is available | | `data.items[].markets[].flags.borrowingEnabled` | boolean | Whether borrowing is enabled | | `data.items[].markets[].flags.depositsEnabled` | boolean | Whether deposits are enabled | | `data.items[].markets[].flags.collateralActive` | boolean | Whether the asset can be used as collateral | | `data.items[].markets[].flags.variableBorrowDisabled` | boolean | Whether variable-rate borrowing is unavailable through 1delta for this market. `true` for Lista DAO fixed-term (brokered) markets, where borrows must go through the broker and pick a fixed term from `terms[]`. Together with a non-empty `terms[]` this is the canonical "brokered market" signal — such markets report `variableBorrowRate = 0` but cannot be borrowed variably. | | `data.items[].markets[].rewards` | object[] | Active reward programs. Defaults to [] when none. | | `data.items[].markets[].rewards[].asset` | string | Reward token address, lowercased. For a points program (`kind: "points"`) there is no token and this is a synthetic `points:` key. | | `data.items[].markets[].rewards[].symbol` | string | Reward token symbol. Denormalized deliberately — reward tokens are routinely absent from the asset table (aMonUSDe, WMON, aHorRwaRLUSD are live examples), so a join would leave them unnamed. | | `data.items[].markets[].rewards[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].markets[].rewards[].logoURI` | string | URL of the logo image. | | `data.items[].markets[].rewards[].depositRate` | number | Reward APR on deposits | | `data.items[].markets[].rewards[].variableBorrowRate` | number | Reward APR on variable borrows | | `data.items[].markets[].rewards[].stableBorrowRate` | number | Reward APR on stable borrows | | `data.items[].markets[].rewards[].kind` | string | `token` \| `points`. Points are NOT priceable and must be shown separately from any headline APR. | | `data.items[].markets[].rewards[].claim` | string | How the reward is realized, i.e. whether the APR is bankable. `accrual` — claimable from the protocol on-chain; `merkl` — off-chain merkle distribution; `manual`. | | `data.items[].markets[].rewards[].source` | string | LEGACY mechanism tag (`merkle`, `onchain-incentives`, `native`) — it cannot distinguish two programs on the same platform. Prefer `sourceId`. | | `data.items[].markets[].rewards[].sourceId` | string | Stable program identifier, safe to key on: `merkl:aave`, `merkl:euler`, `merkl:morpho`, `dtrinity:rebate`. | | `data.items[].markets[].rewards[].sourceLabel` | string | Display string for the program, e.g. `Merkl · Aave`. | | `data.items[].markets[].rewards[].link` | string | Deep link to THIS program — the exact Merkl opportunity page, not a protocol homepage. | | `data.items[].markets[].rewards[].endsAt` | number | Unix seconds the program stops paying. An APR with two weeks left is not the same product as a standing rate, so render it. | | `data.items[].markets[].rewards[].startsAt` | number | | | `data.items[].markets[].rewards[].dailyRewardsUsd` | number | Program-wide payout rate in USD/day, as the source reports it. | | `data.items[].markets[].rewards[].refs` | object | Platform identifiers verbatim — Merkl campaign ids and opportunity type, or the incentives-controller address for an on-chain program. For support and deduplication, not display. | | `data.items[].markets[].config` | object | Risk config keyed by mode/category ID (e.g. "0" for default, "1" for e-mode) | | `data.items[].markets[].terms` | object[] | Fixed-term rate card for Lista DAO brokered markets. Non-empty ⇒ the market is brokered (borrow via the broker, pick a `termId`); `null` ⇒ a regular variable-rate market. Together with `flags.variableBorrowDisabled` this is the canonical brokered-market signal. | | `data.items[].markets[].terms[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data.items[].markets[].terms[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data.items[].markets[].terms[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data.items[].markets[].terms[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data.items[].markets[].terms[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data.items[].markets[].terms[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data.items[].markets[].terms[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data.items[].markets[].terms[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data.items[].markets[].terms[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data.items[].markets[].terms[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data.items[].markets[].broker` | string | Lista DAO `LendingBroker` contract address — the mandatory gateway for the **debt side** (borrow/repay) of a brokered market. Present (non-zero) only for brokered markets. The borrow/repay calldata routes through this contract (the SDK and worker resolve it automatically). | | `data.items[].markets[].collateralProvider` | string | Lista DAO collateral-provider contract for this market. When set (non-zero), Moolah gates `supplyCollateral`/`withdrawCollateral` behind it, so collateral deposits/withdrawals must route through this provider rather than calling Moolah directly (the SDK/worker handle this). Set for markets whose collateral is a Lista-managed token (e.g. slisBNB); `null` for plain ERC-20 collateral. | | `data.items[].markets[].loanProvider` | string | Lista DAO loan-token provider contract for this market (e.g. the native-WBNB wrapper provider). When set, loan-token operations are gated behind it; for brokered markets the broker handles the debt side. Informational — consumers do not pass it; the SDK/worker resolve routing automatically. | | `data.items[].markets[].closeFactor` | number | Max fraction of a borrower's debt repayable in a single liquidation (0-1). Aave ~0.5 (rises to 1 below the close-factor health threshold), Compound V2 closeFactorMantissa; 1 (full liquidation) for isolated / credit-account protocols (Compound V3, Morpho, Euler, Fluid, Gearbox, Dolomite, Silo). | | `data.items[].markets[].targetHealthFactor` | number | Liquidation target health factor (e.g. 1.05). Set only by protocols that liquidate to a target HF rather than a fixed close factor (Aave V4, spoke-level); omitted otherwise. | | `data.items[].markets[].lenderInfo` | object | Protocol/lender metadata (name, logo). | | `data.items[].markets[].lenderInfo.key` | string | Lender key identifier | | `data.items[].markets[].lenderInfo.name` | string | Human-readable lender name | | `data.items[].markets[].lenderInfo.logoURI` | string | Lender logo URL | | `data.items[].markets[].termSheet` | object | Structured description of this market’s lend and borrow offer. Shape depends on the `terms` query param: `digest` (default) or `full`. Absent when `terms=none`. | | `data.items[].markets[].termSheet.schemaVersion` | integer | | | `data.items[].markets[].termSheet.profileId` | string | | | `data.items[].markets[].termSheet.marketUid` | string | Market identifier, formatted `lender:chainId:address`. | | `data.items[].markets[].termSheet.supply` | object | | | `data.items[].markets[].termSheet.borrow` | object | | | `data.items[].markets[].termSheet.oracle` | object | | | `data.items[].markets[].termSheet.governance` | object | | | `data.items[].markets[].termSheet.utilization` | number | Market utilization, as a fraction between 0 and 1. | | `data.items[].markets[].termSheet.asOf` | number | Unix seconds — everything here is a snapshot. | | `data.items[].markets[].termSheet.lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.items[].markets[].termSheet.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].markets[].termSheet.asset` | object | The market’s own underlying — needed to render `minSize` / `cap` / `minDebt`, which are RAW base units. | | `data.items[].markets[].termSheet.constraints` | object | | | `data.items[].markets[].termSheet.coverage` | object | Distinguishes "does not apply here" (`notApplicable`) from "not classified yet" (`pending`). A missing block is NEVER a claim of absence. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": [ { "chainId": "8453", "lenderInfo": { "key": "AAVE_V3", "name": "Aave V3", "logoURI": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp" }, "lastFetched": 1, "totalDepositsUsd": 1, "totalDebtUsd": 1, "tvlUsd": 1, "params": {}, "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "markets": [ { "lenderKey": "AAVE_V3", "poolId": "string", "depositRate": 1, "variableBorrowRate": 1, "stableBorrowRate": 1, "intrinsicYield": 1, "totalDeposits": 1, "totalDebtStable": 1, "totalDebt": 1, "totalLiquidity": 1, "totalDepositsUsd": 1, "totalDebtStableUsd": 1, "totalDebtUsd": 1, "totalLiquidityUsd": 1, "utilization": 1, "decimals": 1, "underlyingInfo": { "asset": { "chainId": "1", "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "symbol": "USDC", "name": "USD Coin", "decimals": 6, "logoURI": "string", "assetGroup": "USDC", "currencyId": "string", "props": {} }, "oraclePrice": { "oraclePrice": 1, "oraclePriceUsd": 1 }, "prices": { "priceUsd": 1, "priceTs": "2026-01-01T00:00:00Z", "priceUsd24h": 1, "priceTs24h": "2026-01-01T00:00:00Z", "priceChange24h": 1 } }, "oracleInfo": { "feeds": [ { "asset": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "oracle": "string", "provider": "string", "priceDescription": "string", "intendedPair": "string", "correctOracle": true, "denominatorMatch": true, "fixedRate": true, "score": 1, "band": "LOW", "flags": [] } ], "worstScore": 1, "worstBand": "LOW" }, "caps": { "borrowCap": 1, "supplyCap": 1, "debtCeiling": "string" }, "flags": { "isActive": true, "isFrozen": true, "hasStable": true, "borrowingEnabled": true, "depositsEnabled": true, "collateralActive": true, "variableBorrowDisabled": true }, "rewards": [ { "asset": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "symbol": "string", "decimals": 1, "logoURI": "string", "depositRate": 1, "variableBorrowRate": 1, "stableBorrowRate": 1, "kind": "string", "claim": "string", "source": "string", "sourceId": "string", "sourceLabel": "string", "link": "string", "endsAt": 1, "startsAt": 1, "dailyRewardsUsd": 1, "refs": {} } ], "config": {}, "terms": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ {} ] } ], "broker": "0x1fa26015286d1270343d7526c60bd57ab6be8b54", "collateralProvider": "0x33f7a980a246f9b8fea2254e3065576e127d4d5f", "loanProvider": "0x367384c54756a25340c63057d87ea22d47fd5701", "closeFactor": 0.5, "targetHealthFactor": 1.05, "lenderInfo": { "key": "AAVE_V3", "name": "Aave V3", "logoURI": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp" }, "termSheet": { "schemaVersion": 1, "profileId": "string", "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "supply": {}, "borrow": {}, "oracle": {}, "governance": {}, "utilization": 1 } } ] } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/lenders - operationId: `lending-lenders` - docs: https://docs.1delta.io/1delta-api/lending-lenders - tags: Lending (Data) Enumerate available lenders Lightweight enumeration of every `(chainId, lenderKey)` pair that has data for the requested chains, sorted by `tvlUsd` descending. Use this endpoint to discover the lender keys to page through [`GET /v1/data/lending/latest`](/1delta-api/lending-latest), which is hard-capped at 20 lender keys per request. ``` GET /v1/data/lending/lenders?chains=1,8453 → enumerate keys GET /v1/data/lending/latest?chains=1,8453&lenders=k1,…,k20 → page 1 GET /v1/data/lending/latest?chains=1,8453&lenders=k21,…,k40 → page 2 ``` **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chains` | query | string[] | yes | Chain IDs to query (repeatable, CSV also accepted) | | `lenders` | query | string[] | no | Filter by lender keys (repeatable, CSV also accepted). Defaults to all lenders. See the `LenderId` schema for the full set of accepted values. | | `maxRiskScore` | query | integer | no | Max risk score (1–5). Defaults to 4. | | `minTvl` | query | number | no | Filter out lender entries with `tvlUsd` below this USD threshold. Applied as a HAVING clause after aggregation. Returns 400 if non-numeric. | | `count` | query | integer | no | Optional cap on the number of items returned. | **Response `200`** — Available lenders sorted by TVL | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Enumeration of available (chainId, lenderKey) pairs sorted by tvlUsd descending. | | `data.count` | integer | Number of items returned | | `data.items` | object[] | Lender entries sorted by tvlUsd descending | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].lenderInfo` | object | Protocol/lender metadata (name, logo). | | `data.items[].lenderInfo.key` | string | Lender key identifier | | `data.items[].lenderInfo.name` | string | Human-readable lender name | | `data.items[].lenderInfo.logoURI` | string | Lender logo URL | | `data.items[].tvlUsd` | number | Σ totalDepositsUsd − Σ totalDebtUsd over the lender's markets on this chain | | `data.items[].lastFetched` | number | Epoch ms of latest snapshot | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": [ { "chainId": "1", "lenderInfo": { "key": "AAVE_V3", "name": "Aave V3", "logoURI": "https://raw.githubusercontent.com/1delta-DAO/protocol-icons/main/lender/aave_v3.webp" }, "tvlUsd": 1234567890.12, "lastFetched": 1 } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/mode - operationId: `list-mode-categories` - docs: https://docs.1delta.io/1delta-api/list-mode-categories - tags: Lending (Data) List mode categories Return the available risk-category ("mode") entries for the requested lenders and chains. Each entry contains the lender key, chain ID, and a list of mode categories (id + label) under the `eModes` field. The "mode" terminology is the protocol-agnostic generalization of Aave V3's "e-mode" (efficiency mode); other lenders expose analogous category mechanisms. Results are cached server-side (1 hour TTL) because mode categories rarely change. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `lenders` | query | string[] | yes | Protocol identifiers (repeatable) See the `LenderId` schema for the full set of accepted values. | | `chains` | query | string[] | yes | Chain IDs (repeatable) | **Response `200`** — Mode categories per lender/chain | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/mode/analysis - operationId: `mode-analysis-on-chain` - docs: https://docs.1delta.io/1delta-api/mode-analysis-on-chain - tags: Lending (Data) Mode analysis (on-chain) Evaluate all mode-switching options for a user. The API fetches the user's current positions and balance data on-chain via multicall — no request body needed. **Output:** For each available mode on the specified lender/chain, returns: - **healthFactor** — the hypothetical health factor if the user switches to that mode (`null` if no debt) - **supportedAssets** — which marketUids are eligible as collateral or for borrowing in that mode - **canSwitch** — whether the switch is safe (health factor > 1 and no incompatible debt) Mode categories are cached server-side (1 hour TTL). Market configs are cached (3 minute TTL). The "mode" terminology is the protocol-agnostic generalization of Aave V3's "e-mode" (efficiency mode); other lenders expose analogous category mechanisms. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `lender` | query | string | yes | Protocol identifier See the `LenderId` schema for the full set of accepted values. | | `chain` | query | string | yes | Chain ID | | `operator` | query | string | yes | Wallet address of the user | | `accountId` | query | string | no | Sub-account ID (for multi-subaccount lenders like Init Capital). Defaults to first sub-account. | **Response `200`** — Mode analysis results | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/lending/mode/analysis - operationId: `mode-analysis-with-body` - docs: https://docs.1delta.io/1delta-api/mode-analysis-with-body - tags: Lending (Data) Mode analysis (with body) Evaluate all mode-switching options for a user sub-account. **Input:** POST a `UserDataForSubAccount` object (the same shape returned by `/user-positions` per sub-account). **Output:** For each available mode on the specified lender/chain, returns: - **healthFactor** — the hypothetical health factor if the user switches to that mode (`null` if no debt) - **supportedAssets** — which marketUids are eligible as collateral or for borrowing in that mode - **canSwitch** — whether the switch is safe (health factor > 1 and no incompatible debt) Mode categories are cached server-side (1 hour TTL). Market configs are cached (3 minute TTL). The "mode" terminology is the protocol-agnostic generalization of Aave V3's "e-mode" (efficiency mode); other lenders expose analogous category mechanisms. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `lender` | query | string | yes | Protocol identifier See the `LenderId` schema for the full set of accepted values. | | `chain` | query | string | yes | Chain ID | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `accountId` | string | no | | | `health` | number | no | | | `borrowCapacityUSD` | number | no | | | `balanceData` | object | yes | Balance data for the sub-account. `collateral` and `adjustedDebt` are required for health factor calculation. | | `balanceData.collateral` | number | yes | | | `balanceData.adjustedDebt` | number | yes | | | `balanceData.deposits` | number | no | | | `balanceData.debt` | number | no | | | `balanceData.borrowDiscountedCollateral` | number | no | | | `balanceData.nav` | number | no | | | `aprData` | object | no | | | `positions` | object[] | yes | | | `positions[].marketUid` | string | no | Market identifier, formatted `lender:chainId:address`. | | `positions[].depositsUSD` | number | no | | | `positions[].debtUSD` | number | no | | | `positions[].debtStableUSD` | number | no | | | `positions[].collateralEnabled` | boolean | no | | | `userConfig` | object | yes | | | `userConfig.selectedMode` | string | yes | Current mode/config key | | `userConfig.id` | string | no | | | `userConfig.isWhitelisted` | boolean | no | | **Example request body** ```json { "accountId": "string", "health": 1, "borrowCapacityUSD": 1, "balanceData": { "collateral": 1, "adjustedDebt": 1, "deposits": 1, "debt": 1, "borrowDiscountedCollateral": 1, "nav": 1 }, "aprData": {}, "positions": [ { "marketUid": "AAVE_V3:1:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "depositsUSD": 1, "debtUSD": 1, "debtStableUSD": 1, "collateralEnabled": true } ], "userConfig": { "selectedMode": "string", "id": "string", "isWhitelisted": true } } ``` **Response `200`** — Mode analysis results | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/next-account - operationId: `next-available-sub-account` - docs: https://docs.1delta.io/1delta-api/next-available-sub-account - tags: Lending (Data) Next available sub-account Discover the next available sub-account or position ID for a given lender and owner. Different protocols handle sub-accounts differently: - **Euler V2** (`accountType: SELECT`): Sub-accounts are derived by XORing the owner's last address byte with an index (0-255). The integrator selects an `accountId` from the range. Any unused value automatically creates a new sub-account. - **Dolomite** (`accountType: SELECT`): Margin sub-accounts are arbitrary `uint256` account numbers (`accountIdRange` is `0` to `2^256-1`). Account `0` is the default cross-margin account; `activeAccountIds` lists funded accounts and `nextAccountId` is the lowest unused integer. Any unused number automatically creates a new sub-account. - **Init Capital** (`accountType: AUTOGEN`): Position IDs are NFT hashes generated on-chain. To create a new position, **omit** the `posId`/`accountId` parameter entirely. The `nextAccountId` field is a preview of the ID that will be generated. - **Other lenders** (Aave, Morpho, Compound, etc.): Do not support sub-accounts — returns a 400 error. ### Integration Guide | `accountType` | To create new account | To use existing account | |---|---|---| | `SELECT` | Pass `accountId=` from `accountIdRange` | Pass `accountId=` | | `AUTOGEN` | **Omit** `accountId` / `posId` parameter | Pass `posId=` | **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID. See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | Lender identifier. See the `LenderId` schema for the full set of accepted values. | | `account` | query | string | yes | Owner wallet address. | **Response `200`** — Next account information | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.accountType` | "SELECT" \| "AUTOGEN" | SELECT — integrator picks an ID from the range (Euler V2). AUTOGEN — ID is generated on-chain; omit the param to create (Init Capital). | | `data.nextAccountId` | string | For SELECT: lowest unused account ID. For AUTOGEN: preview of the on-chain generated ID. | | `data.activeAccountIds` | string[] | Currently active account IDs for this owner. May be empty for AUTOGEN protocols. | | `data.accountIdRange` | string[] | Inclusive [min, max] range of valid account IDs. | | `data.createHint` | string | Human-readable instructions for integrators on how to create a new sub-account. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "accountType": "SELECT", "nextAccountId": "1", "activeAccountIds": [ "0", "3", "7" ], "accountIdRange": [ "0", "255" ], "createHint": "string" } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/orders - operationId: `lending-orders` - docs: https://docs.1delta.io/1delta-api/lending-orders - tags: Lending (Data) Your open orders (unified) A user's own cancellable/pending orders on an order-book or auction lender, normalized into ONE shape: - `MORPHO_MIDNIGHT_` → signed maker limit offers (`kind: 'maker-offer'`), cancel via [`/v1/actions/midnight/cancel`](/1delta-api/midnight-cancel). - `TERM_FINANCE_` → secondary repo-token listings (`kind: 'listing'`) + primary sealed-bid auction submissions (`kind: 'auction-offer'|'auction-bid'`), managed via [`/v1/actions/term/*`](/1delta-api/term-offer). Each order carries a self-describing `cancel` action (`{ method, path, query }`) pointing at the exact endpoint, so one Cancel button works for every provider. `aprPct` is `null` while an auction price is still sealed. To TAKE (fill) *other* users' liquidity, use the standard lending actions + the unified ladder at `/v1/data/lending/book`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | no | Market uid `lender:chainId:asset` (or pass `lender` + `chainId`). | | `lender` | query | string | no | `MORPHO_MIDNIGHT_` or `TERM_FINANCE_` lender key. See the `LenderId` schema for the full set of accepted values. | | `chainId` | query | string | no | Chain ID (aliases: `chains`, `chain`). See the `ChainId` schema for the full set of supported chains. | | `account` | query | string | yes | The order owner whose orders to return. | **Response `200`** — The account's own orders on the market | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | A user's own orders across order-book / auction lenders. | | `data.orders` | object[] | | | `data.orders[].id` | string | Provider order id — the cancel target (Midnight offer root / Term listingId / auction submission id). | | `data.orders[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.orders[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.orders[].kind` | "maker-offer" \| "listing" \| "auction-offer" \| "auction-bid" | `maker-offer` (Midnight signed limit offer), `listing` (Term secondary repo-token listing), `auction-offer`/`auction-bid` (Term primary sealed-bid submission). | | `data.orders[].side` | "lend" \| "borrow" | | | `data.orders[].amount` | string | Order size, loan-token base units. | | `data.orders[].assets` | number | Size decimal-scaled to loan-token assets, or null. | | `data.orders[].aprPct` | number | Annualized rate in percent, or null while sealed. | | `data.orders[].status` | "open" \| "sealed" \| "revealed" \| "filled" \| "closed" | `open` = cancellable now (maker offer / listing); `sealed`/`revealed` = auction lifecycle; `filled` = assigned at clearing; `closed` = complete or cancelled. | | `data.orders[].filledAmount` | string | Amount assigned at clearing (auctions), base units. | | `data.orders[].maturity` | number | Market/repo maturity, unix seconds. | | `data.orders[].expiry` | number | Maker-offer expiry, unix seconds (Midnight). | | `data.orders[].revealTime` | number | Auction reveal window opens, unix seconds (Term). | | `data.orders[].auctionEndTime` | number | Auction closes / clears, unix seconds (Term). | | `data.orders[].cancel` | object | Self-describing cancel/unlock action — omitted when not cancellable. Fetch `path`+`query` to build the cancel transaction. | | `data.orders[].cancel.method` | "GET" \| "POST" | | | `data.orders[].cancel.path` | string | | | `data.orders[].cancel.query` | object | | | `actions` | null | | **Example response** ```json { "success": true, "data": { "orders": [ { "id": "string", "lender": "TERM_FINANCE_0xABC…", "chainId": "1", "kind": "maker-offer", "side": "lend", "amount": "1000000000000000000", "assets": 1, "aprPct": 1, "status": "open", "filledAmount": "1000000000000000000", "maturity": 1, "expiry": 1, "revealTime": 1, "auctionEndTime": 1, "cancel": { "method": "GET", "path": "/v1/actions/term/unlock-offers", "query": {} } } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/pairs - operationId: `get-lending-pairs` - docs: https://docs.1delta.io/1delta-api/get-lending-pairs - tags: Lending (Data) Get lending pairs Returns paginated leverage pair data with optional filters and sorting. Backed by the same origin route as `/v1/data/lending/pairs/leverage`, so it shares that endpoint's behaviour — including dropping pairs whose collateral leg has no remaining supply capacity (`includeIlliquid=true` keeps them). **Lista DAO fixed-term (brokered) debt side:** when the short (debt) market is brokered, `variableBorrowDisabledShort` is `true` and `termsShort[]` lists the fixed-term loop options (each a `MarketTerm`). The pair has one loop option per term rather than a single variable-rate loop — use the per-term APR from `termsShort[]` in place of `variableBorrowRateShort` (which is `0`/undefined for these pairs). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Filter by chain ID See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | no | Filter by lender key See the `LenderId` schema for the full set of accepted values. | | `assetGroupLong` | query | string | no | Filter by collateral asset group | | `assetGroupShort` | query | string | no | Filter by debt asset group | | `minApr` | query | number | no | Minimum total APR | | `minLeverage` | query | number | no | Minimum max leverage | | `minLiquidityUsd` | query | number | no | Minimum liquidity in USD | | `includeIlliquid` | query | boolean | no | Keep pairs whose collateral leg has no remaining supply capacity (un-openable at any size). Off by default. | | `sortBy` | query | "aprTotal" \| "maxLeverage" \| "totalDepositsUsdLong" \| "totalDebtUsdShort" | no | Sort field | | `sortDir` | query | "asc" \| "desc" | no | Sort direction | | `start` | query | integer | no | Pagination start index | | `count` | query | integer | no | Page size | **Response `200`** — Pair data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.start` | integer | | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object[] | The result set for this response. | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.items[].marketLongUid` | string | Market UID of the collateral side | | `data.items[].marketShortUid` | string | Market UID of the debt side | | `data.items[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data.items[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data.items[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data.items[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data.items[].assetLong` | string | Collateral asset address | | `data.items[].assetShort` | string | Debt asset address | | `data.items[].assetGroupLong` | string | | | `data.items[].assetGroupShort` | string | | | `data.items[].symbolLong` | string | Collateral token symbol | | `data.items[].nameLong` | string | Collateral token name | | `data.items[].symbolShort` | string | Debt token symbol | | `data.items[].nameShort` | string | Debt token name | | `data.items[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data.items[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data.items[].borrowFactorLong` | number | Borrow factor for the long side | | `data.items[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data.items[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data.items[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data.items[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data.items[].borrowFactorShort` | number | Borrow factor for the short side | | `data.items[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data.items[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data.items[].eModeConfigId` | string | E-mode configuration ID | | `data.items[].eMode` | string | E-mode category | | `data.items[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data.items[].aprTotal` | number | Total APR (base + rewards) | | `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data.items[].ltv` | number | Loan-to-value ratio (0-1) | | `data.items[].depositRateLong` | number | | | `data.items[].variableBorrowRateShort` | number | | | `data.items[].intrinsicYieldLong` | number | | | `data.items[].intrinsicYieldShort` | number | | | `data.items[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data.items[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data.items[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data.items[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data.items[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data.items[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data.items[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data.items[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data.items[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data.items[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data.items[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data.items[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data.items[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data.items[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data.items[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data.items[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data.items[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data.items[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data.items[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data.items[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data.items[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data.items[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data.items[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data.items[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data.items[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data.items[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data.items[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data.items[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data.items[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data.items[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data.items[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data.items[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data.items[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data.items[].rewardAprLong` | number | Total reward APR on the collateral side | | `data.items[].rewardAprShort` | number | Total reward APR on the debt side | | `data.items[].rewardsLong` | object[] | Reward programs for the collateral side | | `data.items[].rewardsShort` | object[] | Reward programs for the debt side | | `data.items[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data.items[].totalDebtLong` | number | Total debt in token units (long side) | | `data.items[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data.items[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data.items[].totalDebtShort` | number | Total debt in token units (short side) | | `data.items[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data.items[].totalDepositsUsdLong` | number | | | `data.items[].totalDebtUsdLong` | number | | | `data.items[].totalLiquidityUsdLong` | number | | | `data.items[].totalDepositsUsdShort` | number | | | `data.items[].totalDebtUsdShort` | number | | | `data.items[].totalLiquidityUsdShort` | number | | | `data.items[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data.items[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data.items[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data.items[].utilizationLong` | number | | | `data.items[].utilizationShort` | number | | | `data.items[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data.items[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data.items[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data.items[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data.items[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data.items[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data.items[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data.items[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": { "start": 1, "count": 1, "items": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/pairs/leverage - operationId: `browse-all-leverage-pairs` - docs: https://docs.1delta.io/1delta-api/browse-all-leverage-pairs - tags: Lending (Data) Browse all leverage pairs Returns raw materialized view rows with all rate and liquidity fields. Supports single-chain address filtering or cross-chain asset-group mode. Pairs whose COLLATERAL leg has no remaining supply capacity (`depositableLong <= 0`) are dropped by default — a market that cannot take the deposit is not an opportunity at any rate, and those rows sort to the top of an APR ranking precisely because nobody can reach them. `depositableLong: null` means uncapped, i.e. unlimited, and always passes. `includeIlliquid=true` keeps them. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Single chain ID (address-based filtering). Omit for cross-chain asset-group mode. See the `ChainId` schema for the full set of supported chains. | | `chainIds` | query | string | no | Comma-separated chain IDs for multi-chain (asset-group filtering) See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | no | Lender filter (UPPER_SNAKE_CASE) See the `LenderId` schema for the full set of accepted values. | | `minApr` | query | number | no | Minimum total APR | | `maxApr` | query | number | no | Maximum total APR | | `minLeverage` | query | number | no | Minimum leverage | | `assetLong` | query | string | no | Long asset address (single-chain mode) | | `assetShort` | query | string | no | Short asset address (single-chain mode) | | `assetGroupLong` | query | string | no | Long asset group (ILIKE partial match) | | `assetGroupShort` | query | string | no | Short asset group (ILIKE partial match) | | `minDepositApr` | query | number | no | Min effective deposit APR (deposit_rate + intrinsic_yield) | | `minLtv` | query | number | no | Minimum LTV ratio (0-1) | | `maxBorrowRate` | query | number | no | Max effective borrow rate (borrow_rate + intrinsic_yield) | | `includeIlliquid` | query | boolean | no | Keep pairs whose collateral leg has no remaining supply capacity (un-openable at any size). Off by default. | | `minLiquidityUsdLong` | query | number | no | Min collateral-side liquidity USD. This is withdrawable CASH in the market, NOT deposit capacity — see `includeIlliquid` for the capacity gate. | | `minDepositsUsdLong` | query | number | no | Min collateral-side deposits USD | | `maxUtilizationLong` | query | number | no | Max collateral-side utilization (0-1) | | `minBorrowLiquidityUsd` | query | number | no | Min debt-side borrow liquidity USD | | `minDebtUsdShort` | query | number | no | Min debt-side total debt USD | | `maxUtilizationShort` | query | number | no | Max debt-side utilization (0-1) | | `start` | query | integer | no | Pagination offset | | `count` | query | integer | no | Page size (max 100) | | `sortBy` | query | "aprTotal" \| "maxLeverage" \| "depositRateLong" \| "variableBorrowRateShort" \| "intrinsicYieldLong" \| "intrinsicYieldShort" \| … (13 values) | no | Sort field | | `sortDir` | query | "ASC" \| "DESC" | no | Sort direction | **Response `200`** — Paginated leverage pairs | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.start` | integer | | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object[] | The result set for this response. | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.items[].marketLongUid` | string | Market UID of the collateral side | | `data.items[].marketShortUid` | string | Market UID of the debt side | | `data.items[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data.items[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data.items[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data.items[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data.items[].assetLong` | string | Collateral asset address | | `data.items[].assetShort` | string | Debt asset address | | `data.items[].assetGroupLong` | string | | | `data.items[].assetGroupShort` | string | | | `data.items[].symbolLong` | string | Collateral token symbol | | `data.items[].nameLong` | string | Collateral token name | | `data.items[].symbolShort` | string | Debt token symbol | | `data.items[].nameShort` | string | Debt token name | | `data.items[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data.items[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data.items[].borrowFactorLong` | number | Borrow factor for the long side | | `data.items[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data.items[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data.items[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data.items[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data.items[].borrowFactorShort` | number | Borrow factor for the short side | | `data.items[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data.items[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data.items[].eModeConfigId` | string | E-mode configuration ID | | `data.items[].eMode` | string | E-mode category | | `data.items[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data.items[].aprTotal` | number | Total APR (base + rewards) | | `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data.items[].ltv` | number | Loan-to-value ratio (0-1) | | `data.items[].depositRateLong` | number | | | `data.items[].variableBorrowRateShort` | number | | | `data.items[].intrinsicYieldLong` | number | | | `data.items[].intrinsicYieldShort` | number | | | `data.items[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data.items[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data.items[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data.items[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data.items[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data.items[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data.items[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data.items[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data.items[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data.items[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data.items[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data.items[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data.items[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data.items[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data.items[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data.items[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data.items[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data.items[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data.items[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data.items[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data.items[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data.items[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data.items[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data.items[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data.items[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data.items[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data.items[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data.items[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data.items[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data.items[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data.items[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data.items[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data.items[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data.items[].rewardAprLong` | number | Total reward APR on the collateral side | | `data.items[].rewardAprShort` | number | Total reward APR on the debt side | | `data.items[].rewardsLong` | object[] | Reward programs for the collateral side | | `data.items[].rewardsShort` | object[] | Reward programs for the debt side | | `data.items[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data.items[].totalDebtLong` | number | Total debt in token units (long side) | | `data.items[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data.items[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data.items[].totalDebtShort` | number | Total debt in token units (short side) | | `data.items[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data.items[].totalDepositsUsdLong` | number | | | `data.items[].totalDebtUsdLong` | number | | | `data.items[].totalLiquidityUsdLong` | number | | | `data.items[].totalDepositsUsdShort` | number | | | `data.items[].totalDebtUsdShort` | number | | | `data.items[].totalLiquidityUsdShort` | number | | | `data.items[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data.items[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data.items[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data.items[].utilizationLong` | number | | | `data.items[].utilizationShort` | number | | | `data.items[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data.items[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data.items[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data.items[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data.items[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data.items[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data.items[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data.items[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": { "start": 1, "count": 1, "items": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/pairs/optimize - operationId: `collateral-to-debt-optimizer` - docs: https://docs.1delta.io/1delta-api/collateral-to-debt-optimizer - tags: Lending (Data) Collateral ⇄ debt optimizer Filter pairs by either or both sides, then optionally compute the opposite-side amount per row. ## Asset selection `collaterals` / `debts` are reinterpreted by chain mode: - **Single chain** (`chainId`): values are token addresses. - **Multi-chain or no chain**: values are asset groups. Use `collateralGroups` / `debtGroups` to force group semantics in any chain mode. Group params and address params on the same side are OR'd. ### The native asset, and why you usually want groups The native asset is spelled as the **zero address** in every 1delta data payload. `0xEeee…EEeE` is an encoding-layer sentinel — it is accepted on *action* inputs and normalised away, but it is never served here and **never matches an address filter**, so a client filtering by it silently gets zero rows. Native and wrapped-native markets are different rows (`0x0` on Fluid’s ETH vaults, `0xc02a…` on Aave WETH) but share one `assetGroup` (`ETH`). Selecting by group therefore returns **both** — which is what you want whenever the two are interchangeable for your purpose (a migrate bridges them by wrapping, a leverage loop can open on either). It also removes any need for a per-chain wrapped-native address table in the client. Each asset also carries `props.isNative` + `props.wrapped` (native rows) and `props.wnative` (wrapped rows) if you need to tell them apart after the fact. ## Amount params The collateral and debt sides are **independent** — supply an amount on either side, both, or neither: - `collateralAmount` (token units; requires exactly one collateral asset) - `collateralAmountUsd` (USD; multi-asset OK) - `debtAmount` (token units; requires exactly one debt asset) - `debtAmountUsd` (USD; multi-asset OK) A collateral input adds `maxDebtAmount` + `maxDebtAmountUsd` to each row; a debt input adds `minCollateralAmount` + `minCollateralAmountUsd`. Supplying both a collateral **and** a debt amount returns **both** column pairs. Within a single side the token-unit and `*Usd` forms are mutually exclusive (400 otherwise). Un-openable pairs are dropped by default on BOTH legs (`includeIlliquid=true` keeps them). Unconditionally: a collateral leg with no remaining supply capacity (`depositableLong <= 0` — a full or deliberately zeroed supply cap, where the market returns 0 for a max-deposit query). Additionally, when an amount is supplied: a debt leg whose borrow liquidity cannot fund the resulting debt, and a collateral leg whose capacity cannot absorb the required collateral. With no amount supplied, a small-but-real capacity is a real (smaller) opportunity and stays listed; `depositableLong: null` means uncapped and always passes. ## Depth-aware APR Whenever an amount is supplied, each row also carries the EFFECTIVE APR at the computed notional: `borrowAprAtAmount`, `depositAprAtAmount`, `netAprAtAmount`. Each is the headline effective rate (`depositAprLong` / `borrowAprShort`, which fold in intrinsic yield + rewards) with only its ORGANIC (IRM) component re-priced at the utilization the position moves the pool to — intrinsic + rewards are size-invariant. So a curve lender that borrows near 0% at 0 notional prices materially higher at a real size, and `netAprAtAmount` is comparable to `aprTotal` but at the position's actual size/leverage. Pass `depth=true` to additionally receive the raw `borrowDepthShort`/`supplyDepthLong` grids. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Single chain ID. When set, asset filters operate on token addresses. See the `ChainId` schema for the full set of supported chains. | | `chainIds` | query | string | no | CSV of chain IDs. When two or more, asset filters operate on asset groups. See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | no | Single lender key See the `LenderId` schema for the full set of accepted values. | | `lenders` | query | string | no | CSV of lender keys (prefix-expanded) See the `LenderId` schema for the full set of accepted values. | | `excludeLenders` | query | string | no | CSV of lender keys to exclude (prefix-expanded) | | `collaterals` | query | string | no | CSV of long-side filters. Token addresses (single chain) or asset groups (multi/no chain). | | `debts` | query | string | no | CSV of short-side filters. Same dual semantics as `collaterals`. | | `collateralGroups` | query | string | no | CSV of long-side asset groups (works in any chain mode). | | `debtGroups` | query | string | no | CSV of short-side asset groups (works in any chain mode). | | `collateralTags` | query | string | no | CSV of property flags the collateral (long) asset must carry, e.g. `eth`, `btc`, `native`, `wnative`, `stablecoin`, `savings`, `lst`, `lrt`, `pendle`, `rwa`. AND-ed with any `collaterals`/`collateralGroups` selection (narrows). Denomination flags (`eth`/`btc`) cover canonical base tokens only, not LST/derivative wrappers. | | `collateralTagsMode` | query | "any" \| "all" | no | How to match multiple `collateralTags`: `any` (has at least one) or `all` (has every one). | | `debtTags` | query | string | no | CSV of property flags the debt (short) asset must carry (e.g. `eth`, `btc`, `native`, `wnative`, `stablecoin`, `savings`, `lst`, `lrt`, `pendle`, `rwa`). Same semantics as `collateralTags`. Example: `collateralTags=lst&debtTags=wnative` for leveraged staking. | | `debtTagsMode` | query | "any" \| "all" | no | How to match multiple `debtTags`: `any` or `all`. | | `includeExpired` | query | boolean | no | Include pairs whose collateral or debt is an expired Pendle PT. Excluded by default (judged live off `props.pendle.expiry`/`expired`). | | `collateralAmount` | query | number | no | Token-unit collateral amount. Requires exactly one collateral asset. | | `collateralAmountUsd` | query | number | no | USD collateral amount. Multi-asset selections OK. | | `debtAmount` | query | number | no | Token-unit debt amount. Requires exactly one debt asset. | | `debtAmountUsd` | query | number | no | USD debt amount. Multi-asset selections OK. | | `depth` | query | boolean | no | When true, also return the raw `borrowDepthShort`/`supplyDepthLong` rate-at-depth grids. The `*AtAmount` depth-aware scalars are returned whenever an amount is supplied, regardless of this flag. | | `includeIlliquid` | query | boolean | no | By default the optimizer drops collateral legs with no remaining supply capacity, and — when an amount is supplied — pairs whose borrow liquidity cannot fund the resulting debt or whose collateral capacity cannot absorb the required collateral. Set true to keep such (un-openable) pairs. | | `minApr` | query | number | no | Minimum total APR | | `maxApr` | query | number | no | Maximum total APR | | `minLeverage` | query | number | no | Minimum leverage | | `minDepositApr` | query | number | no | Min deposit APR including intrinsic yield (long side) | | `maxBorrowRate` | query | number | no | Max borrow rate including intrinsic yield (short side) | | `minLtv` | query | number | no | Minimum LTV (0-1) | | `maxUtilizationLong` | query | number | no | Max collateral-side utilization (0-1) | | `maxUtilizationShort` | query | number | no | Max debt-side utilization (0-1) | | `minLiquidityUsdLong` | query | number | no | Min collateral-side liquidity USD. This is withdrawable CASH in the market, NOT deposit capacity — capacity is gated separately (see `includeIlliquid`). | | `minBorrowLiquidityUsd` | query | number | no | Min debt-side borrow liquidity USD | | `minDepositsUsdLong` | query | number | no | Min collateral-side deposits USD | | `minDebtUsdShort` | query | number | no | Min debt-side total debt USD | | `maxRiskScore` | query | number | no | Backwards-compat alias for `maxConfigRiskScore` | | `maxConfigRiskScore` | query | number | no | Max config risk score | | `maxTokenRiskScore` | query | number | no | Max token risk score | | `maxChainRiskScore` | query | number | no | Max chain risk score | | `maxLenderRiskScore` | query | number | no | Max lender risk score | | `start` | query | integer | no | Pagination offset | | `count` | query | integer | no | Page size (max 100) | | `sortBy` | query | "aprTotal" \| "aprBase" \| "maxLeverage" \| "ltv" \| "depositAprLong" \| "borrowAprShort" \| … (15 values) | no | Sort field | | `sortDir` | query | "ASC" \| "DESC" | no | Sort direction | **Response `200`** — Optimizer pairs | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.chainIds` | string[] | EVM chain ids, as decimal strings. See the `ChainId` schema. | | `data.collaterals` | string[] | | | `data.debts` | string[] | | | `data.collateralAmount` | number | | | `data.collateralAmountUsd` | number | | | `data.debtAmount` | number | | | `data.debtAmountUsd` | number | | | `data.start` | integer | | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object[] | The result set for this response. | | `data.items[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.items[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data.items[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data.items[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data.items[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data.items[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data.items[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data.items[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data.items[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data.items[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data.items[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data.items[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data.items[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data.items[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data.items[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data.items[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data.items[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data.items[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data.items[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data.items[].marketLongUid` | string | Market UID of the collateral side | | `data.items[].marketShortUid` | string | Market UID of the debt side | | `data.items[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data.items[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data.items[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data.items[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data.items[].assetLong` | string | | | `data.items[].assetShort` | string | | | `data.items[].assetGroupLong` | string | | | `data.items[].assetGroupShort` | string | | | `data.items[].symbolLong` | string | Collateral token symbol | | `data.items[].nameLong` | string | Collateral token name | | `data.items[].symbolShort` | string | Debt token symbol | | `data.items[].nameShort` | string | Debt token name | | `data.items[].aprBase` | number | Leverage-weighted net APR % EXCLUDING rewards — the SUSTAINABLE rate (reward incentives are typically transient). | | `data.items[].aprTotal` | number | Leverage-weighted net APR % INCLUDING rewards. The reward contribution is aprTotal − aprBase. | | `data.items[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data.items[].ltv` | number | Loan-to-value ratio, as a fraction between 0 and 1. | | `data.items[].depositAprLong` | number | Effective deposit APR (depositRate + intrinsicYield) | | `data.items[].borrowAprShort` | number | Effective borrow APR % (borrowRate + intrinsicYield − rewards, plus any 1y-amortized origination fee — see originationFeeShort). For Liquity-family CDPs the amortized origination fee is the whole borrow cost (variable rate is 0). | | `data.items[].originationFeeShort` | number | One-time origination / mint fee on the debt side, PERCENT (Liquity-family CDPs: River, Felix, Nerite, Ebisu, Soneta, USDAf, Liquity). NOT an APR — it is already folded (1y-amortized) into borrowAprShort / aprTotal, and surfaced raw so consumers can re-amortize over a different holding horizon. Null/absent for markets without one. | | `data.items[].totalDepositsUsdLong` | number | | | `data.items[].totalDepositsUsdShort` | number | | | `data.items[].totalDebtUsdLong` | number | | | `data.items[].totalDebtUsdShort` | number | | | `data.items[].totalLiquidityUsdLong` | number | | | `data.items[].totalLiquidityUsdShort` | number | | | `data.items[].borrowLiquidityShort` | number | | | `data.items[].utilizationLong` | number | | | `data.items[].utilizationShort` | number | | | `data.items[].maxDebtAmount` | number | Max borrowable amount given collateral (only when collateralAmount/collateralAmountUsd param provided) | | `data.items[].maxDebtAmountUsd` | number | USD value of maxDebtAmount | | `data.items[].minCollateralAmount` | number | Min collateral needed for debt amount (only when debtAmount/debtAmountUsd param provided) | | `data.items[].minCollateralAmountUsd` | number | USD value of minCollateralAmount | | `data.items[].borrowAprAtAmount` | number | Effective borrow APR % at the computed debt notional: the headline borrowAprShort with only its organic (IRM) component re-priced at the post-borrow utilization (intrinsic + rewards are size-invariant). Present when an amount is supplied; null for non-curve lenders and brokered debt markets. | | `data.items[].depositAprAtAmount` | number | Effective supply APR % at the collateral notional: the headline depositAprLong with only its organic (IRM) component re-priced at the post-deposit utilization. Present when an amount is supplied; null for non-curve lenders. | | `data.items[].netAprAtAmount` | number | Leverage-weighted net position APR % on equity at the supplied amount, using the effective legs (INCLUDING rewards). Same components as aprTotal (directly comparable), but at the position's actual size/leverage. Null when equity is non-positive or a leg is unavailable. | | `data.items[].netAprAtAmountBase` | number | Net APR % at the supplied amount EXCLUDING rewards — the sustainable at-size rate (netAprAtAmount with per-leg rewards stripped). The at-size reward contribution is netAprAtAmount − netAprAtAmountBase. Null when netAprAtAmount is. | | `data.items[].borrowDepthShort` | object | Debt-market rate-vs-amount borrow grid. Only when depth=true. | | `data.items[].supplyDepthLong` | object | Collateral-market rate-vs-amount supply grid. Only when depth=true. | | `data.items[].risk` | object | Per-dimension risk for the pair. No composite headline score — take the worst (highest) breakdown entry if you need one. | | `data.items[].risk.maxTokenScore` | integer | Worse of the two sides' token risk scores. | | `data.items[].risk.breakdown` | object[] | One entry per dimension: config (market/e-mode configuration), chain, lender (protocol), tokenLong (collateral asset), tokenShort (debt asset), and curation — the last present ONLY for lenders that have curators (Morpho Blue, Euler). Scores are 1-5, higher = riskier; 0/null means unassessed and is labelled "unknown". | | `data.items[].risk.breakdown[].category` | string | | | `data.items[].risk.breakdown[].score` | integer | Normalized risk score — lower is safer. | | `data.items[].risk.breakdown[].label` | "low" \| "medium" \| "high" \| "unknown" | | | `data.items[].risk.breakdown[].curatorIds` | string[] | curation only: curator slugs of the pair's two markets, unioned. The pair's curation score is the WORSE of its two legs — an Euler position spanning a curated collateral vault and an uncurated controller is only as curated as the controller. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "chainIds": [ "1" ], "collaterals": [ "string" ], "debts": [ "string" ], "collateralAmount": 1, "collateralAmountUsd": 1, "debtAmount": 1, "debtAmountUsd": 1, "start": 1, "count": 1, "items": [ { "chainId": "1", "lender": "AAVE_V3", "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositAprLong": 1, "borrowAprShort": 1, "originationFeeShort": 1, "totalDepositsUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdLong": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdLong": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "utilizationLong": 1, "utilizationShort": 1, "maxDebtAmount": 1, "maxDebtAmountUsd": 1, "minCollateralAmount": 1, "minCollateralAmountUsd": 1, "borrowAprAtAmount": 1, "depositAprAtAmount": 1, "netAprAtAmount": 1, "netAprAtAmountBase": 1, "borrowDepthShort": {}, "supplyDepthLong": {}, "risk": { "maxTokenScore": 1, "breakdown": [ { "category": "lender", "score": 1, "label": "low", "curatorIds": [ "string" ] } ] } } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/pools - operationId: `get-lending-pools` - docs: https://docs.1delta.io/1delta-api/get-lending-pools - tags: Lending (Data) Get lending pools Returns paginated lending pool data with optional filters and sorting. **Server-side defaults** (applied when the parameter is omitted; pass an explicit value to override): | Parameter | Default | |-----------|---------| | `minUtil` | `0.1` | | `maxUtil` | `0.9` | | `minTvlUsd` | `100000` (Ethereum, chainId 1) / `25000` (all other chains) | | `maxRiskScore` | `4` (medium) | To disable a default filter, pass `0` (e.g. `minUtil=0`). **Oracle risk:** each pool carries an `oracleInfo` object classifying its price oracle's feed correctness (provider, reported vs intended pair, a 0–100 `worstScore`/`worstBand`, and `flags` such as `wrong-asset`/`correlated-proxy`/`cross-numeraire`). This is distinct from the price-staleness signal in `risk.breakdown[oracle]`. See the `OracleInfo` schema for the full scoring model. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Filter by chain ID See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | no | Filter by lender key (e.g. AAVE_V3) See the `LenderId` schema for the full set of accepted values. | | `underlyings` | query | string | no | Comma-separated token addresses (0x-prefixed) | | `assetGroups` | query | string | no | Comma-separated asset group names | | `minYield` | query | number | no | Minimum deposit rate | | `maxYield` | query | number | no | Maximum deposit rate | | `minUtil` | query | number | no | Minimum utilization (0-1). Defaults to 0.1 when omitted. | | `maxUtil` | query | number | no | Maximum utilization (0-1). Defaults to 0.9 when omitted. | | `minTvlUsd` | query | number | no | Minimum total liquidity in USD. Defaults to 100000 on Ethereum (chainId 1), 25000 on other chains. | | `maxTvlUsd` | query | number | no | Maximum total liquidity in USD | | `minDeposits` | query | number | no | Minimum total deposits (native units) | | `maxDeposits` | query | number | no | Maximum total deposits (native units) | | `minDebt` | query | number | no | Minimum total debt (native units) | | `maxDebt` | query | number | no | Maximum total debt (native units) | | `minLiquidity` | query | number | no | Minimum total liquidity (native units) | | `maxLiquidity` | query | number | no | Maximum total liquidity (native units) | | `minDebtUsd` | query | number | no | Minimum total debt in USD | | `maxDebtUsd` | query | number | no | Maximum total debt in USD | | `minLiquidityUsd` | query | number | no | Minimum total liquidity in USD | | `maxLiquidityUsd` | query | number | no | Maximum total liquidity in USD | | `maxRiskScore` | query | integer | no | Maximum risk score (1–5). Defaults to 4 (medium) when omitted. | | `includeExposures` | query | boolean | no | Include config exposure data per pool. Opt-in; omit or false to skip (expensive). | | `sortBy` | query | "depositRate" \| "variableBorrowRate" \| "stableBorrowRate" \| "intrinsicYield" \| "utilization" \| "totalDeposits" \| … (11 values) | no | Sort field | | `sortDir` | query | "ASC" \| "DESC" | no | Sort direction | | `start` | query | integer | no | Pagination offset | | `count` | query | integer | no | Page size (default 100, max 1000) | **Response `200`** — Pool data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.start` | integer | | | `data.count` | integer | Number of entries in `items`. | | `data.pools` | object[] | | | `data.pools[].chain_id` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.pools[].lender_key` | string | | | `data.pools[].underlying_address` | string | | | `data.pools[].asset_group` | string | | | `data.pools[].deposit_rate` | number | | | `data.pools[].variable_borrow_rate` | number | | | `data.pools[].stable_borrow_rate` | number | | | `data.pools[].intrinsic_yield` | number | | | `data.pools[].utilization` | number | Market utilization, as a fraction between 0 and 1. | | `data.pools[].total_deposits` | number | | | `data.pools[].total_debt` | number | | | `data.pools[].total_liquidity` | number | | | `data.pools[].total_deposits_usd` | number | | | `data.pools[].total_debt_usd` | number | | | `data.pools[].total_liquidity_usd` | number | | | `actions` | null | | **Example response** ```json { "success": true, "data": { "start": 1, "count": 1, "pools": [ { "chain_id": "string", "lender_key": "AAVE_V3", "underlying_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "asset_group": "string", "deposit_rate": 1, "variable_borrow_rate": 1, "stable_borrow_rate": 1, "intrinsic_yield": 1, "utilization": 1, "total_deposits": 1, "total_debt": 1, "total_liquidity": 1, "total_deposits_usd": 1, "total_debt_usd": 1, "total_liquidity_usd": 1 } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/pools/by-config - operationId: `get-pools-grouped-by-config` - docs: https://docs.1delta.io/1delta-api/get-pools-grouped-by-config - tags: Lending (Data) Get pools grouped by config For each (lender, chain, configId) combination, returns which markets are eligible as collateral or borrowable. Each item includes a `collaterals` and `borrowables` array with per-market rate, factor, and TVL data. Either array is `null` when no markets qualify. A market absent from a config entry has both collateral and debt disabled for that config. Useful for building position-builder UIs that need to know which assets can be paired within a given pool configuration (e.g. e-mode categories, isolated pools). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chains` | query | string | no | Comma-separated chain IDs | | `lenders` | query | string | no | Comma-separated lender keys See the `LenderId` schema for the full set of accepted values. | **Response `200`** — Config pool breakdown per lender/chain/configId | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/snapshots - operationId: `get-lending-snapshots` - docs: https://docs.1delta.io/1delta-api/get-lending-snapshots - tags: Lending (Data) Get lending snapshots Returns historical lending data time series for specified markets. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUids` | query | string[] | yes | Market UIDs (repeatable) | | `fields` | query | "depositRate" \| "variableBorrowRate" \| "stableBorrowRate" \| "totalDeposits" \| "totalDebtStable" \| "totalDebt" \| … (11 values)[] | no | Fields to include in each snapshot point (repeatable) | | `start` | query | string | no | ISO start date | | `end` | query | string | no | ISO end date | **Response `200`** — Lending snapshot data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.markets` | integer | Number of distinct markets | | `data.totalPoints` | integer | Total data points across all markets | | `data.series` | object | Map of marketUid → array of {dataTs, ...fields} | | `actions` | null | | **Example response** ```json { "success": true, "data": { "markets": 1, "totalPoints": 1, "series": {} } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › Loop (Data) ### GET /v1/data/loop/range/close - operationId: `max-close-range` - docs: https://docs.1delta.io/1delta-api/max-close-range - tags: Loop (Data) Max close range Compute the maximum amount for closing (deleveraging) a position. The max closeable amount is bounded by the smaller of the user's collateral and debt. `amountIn` = collateral withdrawn, `amountOut` = debt repaid. Use `denomination=exactInput` (default) to base the range on collateral, or `exactOutput` to base it on debt. Requires `positions[]` in the POST body (or `account` for GET) to read collateral and debt balances. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | | `denomination` | query | "exactInput" \| "exactOutput" | no | Which side is the base denomination for the range. | **Response `200`** — Max close range | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/loop/range/close - operationId: `max-close-range-with-body` - docs: https://docs.1delta.io/1delta-api/max-close-range-with-body - tags: Loop (Data) Max close range (with body) Compute the maximum amount for closing (deleveraging) a position. The max closeable amount is bounded by the smaller of the user's collateral and debt. `amountIn` = collateral withdrawn, `amountOut` = debt repaid. Use `denomination=exactInput` (default) to base the range on collateral, or `exactOutput` to base it on debt. Requires `positions[]` in the POST body (or `account` for GET) to read collateral and debt balances. POST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | | `denomination` | query | "exactInput" \| "exactOutput" | no | Which side is the base denomination for the range. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Max close range | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/loop/range/collateral-swap - operationId: `max-collateral-swap-range` - docs: https://docs.1delta.io/1delta-api/max-collateral-swap-range - tags: Loop (Data) Max collateral swap range Compute the maximum amount for a collateral swap. The max swappable amount equals the user's collateral deposit in the source (input) asset. Requires `positions[]` in the POST body (or `account` for GET) to read the user's collateral balances. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | **Response `200`** — Max collateral swap range | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/loop/range/collateral-swap - operationId: `max-collateral-swap-range-with-body` - docs: https://docs.1delta.io/1delta-api/max-collateral-swap-range-with-body - tags: Loop (Data) Max collateral swap range (with body) Compute the maximum amount for a collateral swap. The max swappable amount equals the user's collateral deposit in the source (input) asset. Requires `positions[]` in the POST body (or `account` for GET) to read the user's collateral balances. POST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Max collateral swap range | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/loop/range/debt-swap - operationId: `max-debt-swap-range` - docs: https://docs.1delta.io/1delta-api/max-debt-swap-range - tags: Loop (Data) Max debt swap range Compute the maximum amount for a debt swap. The max swappable amount equals the user's total debt (variable + stable) in the source (input) asset. Use `denomination=exactInput` (default) to base the range on the source debt, or `exactOutput` to base it on the target debt. Requires `positions[]` in the POST body (or `account` for GET) to read the user's debt balances. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | | `denomination` | query | "exactInput" \| "exactOutput" | no | Which side is the base denomination for the range. | **Response `200`** — Max debt swap range | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/loop/range/debt-swap - operationId: `max-debt-swap-range-with-body` - docs: https://docs.1delta.io/1delta-api/max-debt-swap-range-with-body - tags: Loop (Data) Max debt swap range (with body) Compute the maximum amount for a debt swap. The max swappable amount equals the user's total debt (variable + stable) in the source (input) asset. Use `denomination=exactInput` (default) to base the range on the source debt, or `exactOutput` to base it on the target debt. Requires `positions[]` in the POST body (or `account` for GET) to read the user's debt balances. POST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | | `denomination` | query | "exactInput" \| "exactOutput" | no | Which side is the base denomination for the range. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Max debt swap range | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/loop/range/leverage - operationId: `max-leverage-range` - docs: https://docs.1delta.io/1delta-api/max-leverage-range - tags: Loop (Data) Max leverage range Compute the maximum amount that can be opened in a leverage position. **Single-pair mode** (provide `marketUidIn` + `marketUidOut`): returns the max open amount for one specific pair. **Multi-pair mode** (provide `lender` + `chainId`): returns the max open amount for all leverage pairs of a lender, optionally filtered by `marketUidIn` / `marketUidOut`. **Zap mode**: If `payAmount` and `payPriceUSD` are provided, the calculation includes the deposited amount as additional collateral before computing the leverage range. GET fetches user balances on-chain (requires `account`). POST accepts a `SimulationBody` in the request body. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | | `lender` | query | string | no | Lender identifier. Required for multi-pair mode. See the `LenderId` schema for the full set of accepted values. | | `chainId` | query | string | no | Chain ID. Required for multi-pair mode. See the `ChainId` schema for the full set of supported chains. | | `payAmount` | query | string | no | Amount of the pay asset to deposit (for zap calculation). Triggers zap mode when present. | | `payPriceUSD` | query | string | no | USD price of the pay asset. If omitted, defaults to the long (collateral) asset price from the pair. | **Response `200`** — Max open range for one or more leverage pairs | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/loop/range/leverage - operationId: `max-leverage-range-with-body` - docs: https://docs.1delta.io/1delta-api/max-leverage-range-with-body - tags: Loop (Data) Max leverage range (with body) Compute the maximum amount that can be opened in a leverage position. **Single-pair mode** (provide `marketUidIn` + `marketUidOut`): returns the max open amount for one specific pair. **Multi-pair mode** (provide `lender` + `chainId`): returns the max open amount for all leverage pairs of a lender, optionally filtered by `marketUidIn` / `marketUidOut`. **Zap mode**: If `payAmount` and `payPriceUSD` are provided, the calculation includes the deposited amount as additional collateral before computing the leverage range. GET fetches user balances on-chain (requires `account`). POST accepts a `SimulationBody` in the request body. POST accepts a JSON body with the user's current portfolio state, avoiding an on-chain fetch. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | no | Market identifier for the input (debt/short) side. | | `marketUidOut` | query | string | no | Market identifier for the output (collateral/long) side. | | `account` | query | string | no | Wallet address. Required for GET (on-chain balance fetch). | | `accountId` | query | string | no | Sub-account ID (e.g. Euler V2, Init Capital). | | `lender` | query | string | no | Lender identifier. Required for multi-pair mode. See the `LenderId` schema for the full set of accepted values. | | `chainId` | query | string | no | Chain ID. Required for multi-pair mode. See the `ChainId` schema for the full set of supported chains. | | `payAmount` | query | string | no | Amount of the pay asset to deposit (for zap calculation). Triggers zap mode when present. | | `payPriceUSD` | query | string | no | USD price of the pay asset. If omitted, defaults to the long (collateral) asset price from the pair. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Max open range for one or more leverage pairs | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object[] | Array of range results. | | `data[].chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data[].lender` | string | Protocol identifier. See the `LenderId` schema. | | `data[].marketLongUid` | string | Market UID of the collateral side | | `data[].marketShortUid` | string | Market UID of the debt side | | `data[].marketNameLong` | string | Display name of the collateral market/vault (e.g. the Euler eVault name). Disambiguates rows that share the collateral/debt token symbols and lender. | | `data[].marketNameShort` | string | Display name of the debt market/vault. For Euler this is the controller (debt) eVault — the primary way to tell otherwise-identical WETH→USDC rows apart. | | `data[].curatorNameLong` | string | Curator/brand of the collateral market (Euler: resolved from the vault governor). Null for lenders without a curator, or until the curator registry is seeded. Render as "curatorName + symbol", falling back to marketNameLong. | | `data[].curatorNameShort` | string | Curator/brand of the debt (controller) market. Same semantics as curatorNameLong. | | `data[].assetLong` | string | Collateral asset address | | `data[].assetShort` | string | Debt asset address | | `data[].assetGroupLong` | string | | | `data[].assetGroupShort` | string | | | `data[].symbolLong` | string | Collateral token symbol | | `data[].nameLong` | string | Collateral token name | | `data[].symbolShort` | string | Debt token symbol | | `data[].nameShort` | string | Debt token name | | `data[].collateralFactorLong` | number | Liquidation collateral factor for the long side | | `data[].borrowCollateralFactorLong` | number | Borrow-adjusted collateral factor for the long side | | `data[].borrowFactorLong` | number | Borrow factor for the long side | | `data[].collateralDisabledLong` | boolean | Whether collateral is disabled for the long asset | | `data[].debtDisabledLong` | boolean | Whether debt is disabled for the long asset | | `data[].collateralFactorShort` | number | Liquidation collateral factor for the short side | | `data[].borrowCollateralFactorShort` | number | Borrow-adjusted collateral factor for the short side | | `data[].borrowFactorShort` | number | Borrow factor for the short side | | `data[].collateralDisabledShort` | boolean | Whether collateral is disabled for the short asset | | `data[].debtDisabledShort` | boolean | Whether debt is disabled for the short asset | | `data[].eModeConfigId` | string | E-mode configuration ID | | `data[].eMode` | string | E-mode category | | `data[].aprBase` | number | Base APR (deposit - borrow + intrinsic, before rewards) | | `data[].aprTotal` | number | Total APR (base + rewards) | | `data[].maxLeverage` | number | Highest leverage multiple reachable in this market. | | `data[].ltv` | number | Loan-to-value ratio (0-1) | | `data[].depositRateLong` | number | | | `data[].variableBorrowRateShort` | number | | | `data[].intrinsicYieldLong` | number | | | `data[].intrinsicYieldShort` | number | | | `data[].variableBorrowDisabledShort` | boolean | True when the debt (short) market is a Lista DAO brokered market — it cannot be looped at a variable rate, only at one of the fixed terms in `termsShort`. `variableBorrowRateShort` is `0`/undefined for such pairs. | | `data[].termsShort` | object[] | Fixed-term rate card for the debt (short) side when it is a Lista DAO brokered market. Each entry is one loop option — see the per-term net-APR recipe. `null`/empty for regular variable-rate pairs. For Term Finance an empty card means "not borrowable right now" rather than "no offers" — read `fixedTerm.auction` for why. | | `data[].termsShort[].termId` | integer | Term identifier — MEANING IS LENDER-SPECIFIC. Exactly and TermMax: the pool/market unix MATURITY timestamp. Lista: the broker-defined product id. Teller: the duration in seconds (rolling term). Midnight and Term Finance: `0`, a placeholder (single maturity per market, so the id carries no information). Pass to `/v1/actions/lending/borrow?termId=…`. Numeric on-chain; some upstream feeds serialize it as a string — coerce with `Number()` when comparing. | | `data[].termsShort[].depositApr` | number | Annualised fixed LEND rate at this maturity, in percent (Exactly only — its fixed pools quote both sides). | | `data[].termsShort[].available` | number | Borrowable liquidity at this maturity in loan-token human units (Exactly only). | | `data[].termsShort[].durationDays` | number | How long the position is locked at the fixed rate, in days (e.g. 7, 14, 30). | | `data[].termsShort[].durationSecs` | number | Term duration in seconds (raw on-chain value). | | `data[].termsShort[].apr` | number | Annualised borrow APR for this term, in **percent** (e.g. `3.85` = 3.85%). Same unit as `variableBorrowRate` / `stableBorrowRate`. For order-book markets (Midnight) this is the 0-notional top-of-book (cheapest) rate — see `aprAtAmount` for the size-weighted rate. | | `data[].termsShort[].aprAtAmount` | number | Size-weighted (VWAP) borrow APR % at the supplied debt notional, for order-book fixed-term markets (Morpho Midnight): the borrow book filled cheapest-first, `(Σ filledᵢ·aprᵢ)/amount`. Present only when an amount is supplied AND the term carries an order-book `ladder`; broker rate cards (Lista, single flat rate) omit it and `apr` already applies at any size. | | `data[].termsShort[].fillable` | number | Total loan-token depth in this term's order book — the maximum borrow openable at this maturity. Present only for order-book terms with an amount supplied. | | `data[].termsShort[].capped` | boolean | True when the supplied debt notional exceeds `fillable` — the book can't fully fund the borrow at this maturity (`aprAtAmount` is then the drain-the-book VWAP). | | `data[].termsShort[].ladder` | object[] | Order-book borrow ladder (best-borrow first) for order-book fixed-term markets (Midnight). Only serialized when `depth=true` (bulky). `aprAtAmount` is the pre-computed size-weighted rate; use this to re-derive it at any amount. | | `data[].termsShort[].ladder[].apr` | number | Annualised borrow rate at this tier (%). | | `data[].termsShort[].ladder[].units` | string | Credit/debt units at this tier (raw). | | `data[].termsShort[].ladder[].assets` | number | Loan-token size available at this tier. | | `data[].fixedTerm` | object | Fixed-term descriptor for this pair's lender, joined by lender key. Absent on variable-rate lenders. **For Term Finance (`model: "term"`), gate the borrow/loop CTA on `fixedTerm.auction.canBorrow`**: origination only happens inside scheduled sealed-bid auction rounds and most repos sit between rounds, so a pair can carry a maturity, an LTV and a rate and still be impossible to borrow. Note also that `aprBase`/`aprTotal` on such a pair are computed against a `variableBorrowRate` of 0 and therefore read as an enormous leveraged yield with a free debt leg — show them as indicative, not obtainable, whenever `canBorrow` is false. | | `data[].fixedTerm.model` | "lista" \| "midnight" \| "term" \| "exactly" \| "teller" \| "termmax" | Underlying fixed-term protocol shape. | | `data[].fixedTerm.maturity` | integer | Single fixed calendar maturity, unix seconds. Absent for rolling-duration menus (Lista) and multi-maturity markets (Exactly — the menu lives on `terms[]`). | | `data[].fixedTerm.fees` | object | Market-level fees: `continuousFeeApr` (%/yr lender-side haircut, Midnight), `settlementFee` (fraction at the current TTM, Midnight), `latePenaltyApr` (%/yr on overdue debt, Exactly), `originationFeePercent` (upfront % of principal, Teller). Empty for lenders without them. | | `data[].fixedTerm.earlyRepay` | object | Early-repayment policy: `{ kind: "none" \| "penalty" \| "discount" }`. `none` = exit any time at market price; `penalty` = per-loan penalty (amount is position-level); `discount` = repaying early costs LESS than face value (Exactly). | | `data[].fixedTerm.provider` | object | Who fronts the term: `{ kind: "broker" \| "orderbook" \| "auction" \| "pool", address? }`. `auction` markets carry the `auction` window below and can only be borrowed inside a round. | | `data[].fixedTerm.auction` | object | Origination window for a fixed-term market whose terms are only obtainable during a bounded round rather than continuously — Term Finance (`fixedTerm.provider.kind = "auction"`). Served on `fixedTerm.auction`; ABSENT on lenders whose terms are continuously available, and absent is NOT the same as `closed`. This is the difference between "the rate card is empty right now" and "this market cannot be borrowed at all": between rounds a Term repo still has a maturity, collateral params and a last-cleared rate, but nothing can be borrowed. Most repos are between rounds at any given time. | | `data[].fixedTerm.auction.status` | "upcoming" \| "open" \| "revealing" \| "closed" | `upcoming` — a round is listed but not yet accepting submissions. `open` — accepting sealed bids/offers. `revealing` — bidding shut, sealed prices revealing and the round clearing. `closed` — no round is listed. Snapshot at fetch time; re-derive from the timestamps against the current clock when reading a cached response. | | `data[].fixedTerm.auction.canBorrow` | boolean | Can a NEW borrow be opened right now? **Gate the borrow CTA on this**, not on `status` and not on the presence of a rate — it stays correct if more statuses are added. True only inside an open round: Term borrow origination is a sealed bid, so there is no other entry point. | | `data[].fixedTerm.auction.canLend` | boolean | Can a NEW lend position be opened right now? Deliberately independent of `canBorrow` — the primary auction is only one of two lend surfaces, and buying repo tokens on the secondary market works between rounds. A closed round therefore leaves the market **lend-only**, not inert; greying out the whole market would be wrong. | | `data[].fixedTerm.auction.secondsUntilClose` | integer | Seconds until submissions close (`revealTime − now`). Absent unless a round is open. A snapshot — for a live countdown derive from `revealTime`, since responses are cached. | | `data[].fixedTerm.auction.implications` | string[] | Ready-to-display consequences of this market's origination model, most important first (same convention as `params.market.teller.implications`). Auction mechanics are unusual enough that showing only a rate misleads. | | `data[].fixedTerm.auction.id` | string | Auction round id. Absent when `status: "closed"`. | | `data[].fixedTerm.auction.startTime` | integer | Submissions open, unix seconds. Absent when closed. | | `data[].fixedTerm.auction.revealTime` | integer | Submissions CLOSE and sealed prices begin revealing, unix seconds — **the deadline to act**. Absent when closed. | | `data[].fixedTerm.auction.endTime` | integer | Round clears, unix seconds. Equal to `revealTime` on current deployments. Absent when closed. | | `data[].fixedTerm.auction.minBorrowAmount` | string | Minimum bid (borrow) size for this round, loan-token BASE units. A real floor (e.g. `"1000000000"` = 1000 USDC) — a smaller amount cannot be submitted at all, so validate before building the action rather than surfacing a failed transaction. | | `data[].fixedTerm.auction.minLendAmount` | string | Minimum offer (lend) size for this round, loan-token BASE units. | | `data[].rewardAprLong` | number | Total reward APR on the collateral side | | `data[].rewardAprShort` | number | Total reward APR on the debt side | | `data[].rewardsLong` | object[] | Reward programs for the collateral side | | `data[].rewardsShort` | object[] | Reward programs for the debt side | | `data[].totalDepositsLong` | number | Total deposits in token units (long side) | | `data[].totalDebtLong` | number | Total debt in token units (long side) | | `data[].totalLiquidityLong` | number | Total liquidity in token units (long side) | | `data[].totalDepositsShort` | number | Total deposits in token units (short side) | | `data[].totalDebtShort` | number | Total debt in token units (short side) | | `data[].totalLiquidityShort` | number | Total liquidity in token units (short side) | | `data[].totalDepositsUsdLong` | number | | | `data[].totalDebtUsdLong` | number | | | `data[].totalLiquidityUsdLong` | number | | | `data[].totalDepositsUsdShort` | number | | | `data[].totalDebtUsdShort` | number | | | `data[].totalLiquidityUsdShort` | number | | | `data[].borrowLiquidityShort` | number | Available borrow liquidity (debt side) in token units | | `data[].withdrawLiquidityLong` | number | Available withdraw liquidity (collateral side) in token units | | `data[].depositableLong` | number | Remaining deposit capacity (collateral side) in token units | | `data[].utilizationLong` | number | | | `data[].utilizationShort` | number | | | `data[].underlyingInfoLong` | object | Collateral asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoLong.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoLong.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoLong.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `data[].underlyingInfoShort` | object | Debt asset metadata including token info, market prices, and oracle prices | | `data[].underlyingInfoShort.asset` | object | Token metadata (address, symbol, name, decimals, logoURI, assetGroup) | | `data[].underlyingInfoShort.prices` | object | Market prices (priceUsd, priceUsd24h, priceChange24h) | | `data[].underlyingInfoShort.oraclePrice` | object | On-chain oracle prices (oraclePrice, oraclePriceUsd) | | `actions` | null | | **Example response** ```json { "success": true, "data": [ { "chainId": "1", "lender": "AAVE_V3", "marketLongUid": "string", "marketShortUid": "string", "marketNameLong": "string", "marketNameShort": "string", "curatorNameLong": "string", "curatorNameShort": "string", "assetLong": "string", "assetShort": "string", "assetGroupLong": "string", "assetGroupShort": "string", "symbolLong": "string", "nameLong": "string", "symbolShort": "string", "nameShort": "string", "collateralFactorLong": 0.94, "borrowCollateralFactorLong": 0.92, "borrowFactorLong": 1, "collateralDisabledLong": true, "debtDisabledLong": true, "collateralFactorShort": 0.94, "borrowCollateralFactorShort": 0.92, "borrowFactorShort": 1, "collateralDisabledShort": true, "debtDisabledShort": true, "eModeConfigId": "string", "eMode": "string", "aprBase": 1, "aprTotal": 1, "maxLeverage": 1, "ltv": 1, "depositRateLong": 1, "variableBorrowRateShort": 1, "intrinsicYieldLong": 1, "intrinsicYieldShort": 1, "variableBorrowDisabledShort": true, "termsShort": [ { "termId": 2, "depositApr": 1, "available": 1, "durationDays": 7, "durationSecs": 604800, "apr": 3.85, "aprAtAmount": 1, "fillable": 1, "capped": true, "ladder": [ { "apr": 1, "units": "string", "assets": 1 } ] } ], "fixedTerm": { "model": "term", "maturity": 1, "fees": {}, "earlyRepay": {}, "provider": {}, "auction": { "status": "open", "canBorrow": true, "canLend": true, "secondsUntilClose": 263000, "implications": [ "string" ], "id": "string", "startTime": 1, "revealTime": 1, "endTime": 1, "minBorrowAmount": "1000000000", "minLendAmount": "1000000000" } }, "rewardAprLong": 1, "rewardAprShort": 1, "rewardsLong": [ {} ], "rewardsShort": [ {} ], "totalDepositsLong": 1, "totalDebtLong": 1, "totalLiquidityLong": 1, "totalDepositsShort": 1, "totalDebtShort": 1, "totalLiquidityShort": 1, "totalDepositsUsdLong": 1, "totalDebtUsdLong": 1, "totalLiquidityUsdLong": 1, "totalDepositsUsdShort": 1, "totalDebtUsdShort": 1, "totalLiquidityUsdShort": 1, "borrowLiquidityShort": 1, "withdrawLiquidityLong": 1, "depositableLong": 1, "utilizationLong": 1, "utilizationShort": 1, "underlyingInfoLong": { "asset": {}, "prices": {}, "oraclePrice": {} }, "underlyingInfoShort": { "asset": {}, "prices": {}, "oraclePrice": {} } } ] } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › Yields ### GET /v1/data/lending/yields/by-asset/latest - operationId: `get-latest-yields-by-asset` - docs: https://docs.1delta.io/1delta-api/get-latest-yields-by-asset - tags: Yields Get latest yields by asset Returns latest lending yields grouped by asset for a given chain. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `assets` | query | string[] | no | Filter by asset group keys (repeatable) | | `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. | **Response `200`** — Yield data by asset | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of entries in `items`. | | `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "data": {} } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/yields/by-asset/snapshots - operationId: `get-yield-snapshots-by-asset` - docs: https://docs.1delta.io/1delta-api/get-yield-snapshots-by-asset - tags: Yields Get yield snapshots by asset Returns historical yield time series grouped by asset for a given chain. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `assets` | query | string[] | no | Filter by asset group keys (repeatable) | | `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. | | `start` | query | string | no | ISO start date | | `end` | query | string | no | ISO end date | **Response `200`** — Yield snapshot data by asset | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of entries in `items`. | | `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "data": {} } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/yields/by-lender/latest - operationId: `get-latest-yields-by-lender` - docs: https://docs.1delta.io/1delta-api/get-latest-yields-by-lender - tags: Yields Get latest yields by lender Returns latest lending yields grouped by protocol. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. | | `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. | **Response `200`** — Yield data by lender | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of entries in `items`. | | `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "data": {} } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/yields/by-lender/snapshots - operationId: `get-yield-snapshots-by-lender` - docs: https://docs.1delta.io/1delta-api/get-yield-snapshots-by-lender - tags: Yields Get yield snapshots by lender Returns historical yield time series grouped by protocol. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. | | `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. | | `start` | query | string | no | ISO start date | | `end` | query | string | no | ISO end date | **Response `200`** — Yield snapshot data by lender | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of entries in `items`. | | `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "data": {} } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/yields/intrinsic/latest - operationId: `get-latest-intrinsic-yields` - docs: https://docs.1delta.io/1delta-api/get-latest-intrinsic-yields - tags: Yields Get latest intrinsic yields Returns latest intrinsic yield (APR) for each asset group. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `assets` | query | string[] | no | Filter by asset group keys (repeatable) | | `asOf` | query | string | no | ISO date anchor; defaults to latest hour | **Response `200`** — Intrinsic yield data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.asOf` | string | Timestamp the data was measured at. | | `data.count` | integer | Number of entries in `items`. | | `data.intrinsicApr` | object | Map of asset_group → APR in percent | | `actions` | null | | **Example response** ```json { "success": true, "data": { "asOf": "2026-01-01T00:00:00Z", "count": 1, "intrinsicApr": { "USDC": 3.25, "ETH": 2.1 } } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/yields/intrinsic/snapshots - operationId: `get-intrinsic-yield-snapshots` - docs: https://docs.1delta.io/1delta-api/get-intrinsic-yield-snapshots - tags: Yields Get intrinsic yield snapshots Returns historical intrinsic yield time series per asset group. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `assetGroups` | query | string[] | yes | Asset group keys (repeatable) | | `start` | query | string | no | ISO start date | | `end` | query | string | no | ISO end date | **Response `200`** — Intrinsic yield snapshots | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of entries in `items`. | | `data.series` | object | Map of assetGroup → array of {dataTs, intrinsicYield} | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "series": {} } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › User Positions ### GET /v1/data/lending/user-positions - operationId: `lending-user-positions` - docs: https://docs.1delta.io/1delta-api/lending-user-positions - tags: User Positions User positions Fetches lending and borrowing positions for a given account across one or more chains. **Response Structure:** - `items`: Flat array of lender entries sorted by net worth (descending). Each entry fuses sub-account position data with aggregated summary metrics (deposits, debt, APRs, health, leverage). - `summary`: Portfolio-wide totals (net worth, APRs, leverage, active counts) plus per-chain breakdowns. - `partial` / `incompleteLenders`: only present when some lender could not be read in full (RPC error or reverted call). A lender whose reads all failed is omitted rather than returned as an empty position, so totals are a lower bound for that request. **Lender Entry includes:** - Per-asset deposits and debt (in USD and token units) - Sub-account data with health factors and borrow capacity - Aggregated lender-level metrics (total deposits/debt, weighted APRs, health factor, leverage) - Collateral status, withdrawable/borrowable amounts per position **Portfolio Summary includes:** - Total deposits, debt, and net worth (current + 24h ago) across all chains - Weighted average APRs and overall leverage ratio - Count of active lenders and chains - Per-chain totals (deposits, debt, net worth, lender count) The server executes RPC calls internally and returns fully parsed results. --- **Using with action endpoints (POST simulation):** All action endpoints (`/v1/actions/lending/*`, `/v1/actions/loop/*`) accept an optional POST body for post-trade simulation. The data comes directly from this endpoint: ``` // 1. Fetch positions GET /v1/data/lending/user-positions?account=0x...&chains=1 // 2. Pick the lender entry + sub-account you're acting on const sub = response.data.items[i].data[j] // 3. POST to any action endpoint with the same query params as GET, plus: POST /v1/actions/lending/deposit?marketUid=AAVE_V3:1:0x...&amount=1000000 { "balanceData": sub.balanceData, "aprData": sub.aprData, "positions": sub.positions, "modeId": sub.userConfig.selectedMode } // 4. Response includes a "simulation" field with pre/post health factor, // borrow capacity, and projected balanceData/aprData. ``` See the `SimulationBody` schema for full details. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) | | `chains` | query | string | yes | Comma-separated chain IDs | | `lenders` | query | string | no | Comma-separated lender IDs to filter by. If omitted, all supported lenders for each chain are included. See the `LenderId` schema for the full set of accepted values. | **Response `200`** — User position data with portfolio summary | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | User lending positions as a flat array with portfolio summary and per-chain breakdowns. | | `data.items` | object[] | Flat array of lender entries sorted by net worth (descending). Each entry fuses position data with aggregated summary metrics. | | `data.items[].lender` | string | Lender identifier | | `data.items[].chainId` | string | Chain ID | | `data.items[].account` | string | User account address | | `data.items[].data` | object[] | Sub-account position data | | `data.items[].data[].accountId` | string | Sub-account identifier (e.g., "0" for default, NFT ID for Init) | | `data.items[].data[].health` | number | Health factor (null if no debt). Values > 1 are healthy, < 1 at risk of liquidation. | | `data.items[].data[].borrowCapacityUSD` | number | Total USD borrowable while maintaining health >= 1 | | `data.items[].data[].balanceData` | object | Aggregated balance data for a sub-account. | | `data.items[].data[].balanceData.deposits` | number | Total deposits in USD | | `data.items[].data[].balanceData.debt` | number | Total debt in USD | | `data.items[].data[].balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.items[].data[].balanceData.collateral` | number | Collateral value in USD | | `data.items[].data[].balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.items[].data[].balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.items[].data[].balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.items[].data[].balanceData.nav` | number | Net asset value (deposits - debt) | | `data.items[].data[].balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.items[].data[].balanceData.debt24h` | number | Debt 24h ago | | `data.items[].data[].balanceData.nav24h` | number | NAV 24h ago | | `data.items[].data[].balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.items[].data[].aprData` | object | APR breakdown for a sub-account. | | `data.items[].data[].aprData.apr` | number | Net APR (deposit - borrow) | | `data.items[].data[].aprData.depositApr` | number | Weighted deposit APR | | `data.items[].data[].aprData.borrowApr` | number | Weighted borrow APR | | `data.items[].data[].aprData.rewardApr` | number | Total reward APR | | `data.items[].data[].aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.items[].data[].aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.items[].data[].aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.items[].data[].aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.items[].data[].aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.items[].data[].aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.items[].data[].positions` | object[] | Individual asset positions in this sub-account | | `data.items[].data[].positions[].marketUid` | string | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `data.items[].data[].positions[].deposits` | string | Deposit amount in token units (wei) | | `data.items[].data[].positions[].debt` | string | Variable debt in token units | | `data.items[].data[].positions[].debtStable` | string | Stable debt in token units | | `data.items[].data[].positions[].debtShares` | string | Debt share amount (protocol-specific, present when the protocol uses share-based accounting) | | `data.items[].data[].positions[].depositShares` | string | Deposit share amount (protocol-specific, present when the protocol uses share-based accounting) | | `data.items[].data[].positions[].depositsUSD` | number | Deposits in USD (market price) | | `data.items[].data[].positions[].debtUSD` | number | Variable debt in USD (market price) | | `data.items[].data[].positions[].debtStableUSD` | number | Stable debt in USD (market price) | | `data.items[].data[].positions[].depositsUSDOracle` | number | Deposits in USD using on-chain oracle price (used for risk/health calculations) | | `data.items[].data[].positions[].debtUSDOracle` | number | Variable debt in USD using on-chain oracle price | | `data.items[].data[].positions[].debtStableUSDOracle` | number | Stable debt in USD using on-chain oracle price | | `data.items[].data[].positions[].collateralEnabled` | boolean | Whether this asset is enabled as collateral | | `data.items[].data[].positions[].claimableRewards` | number | Claimable rewards in USD | | `data.items[].data[].positions[].withdrawable` | string | Max tokens withdrawable while maintaining health >= 1. Equals full deposit balance if collateral is not enabled. | | `data.items[].data[].positions[].borrowable` | string | Max tokens borrowable against remaining credit line. Zero if borrowing is disabled, reserve is frozen, or debt is disabled for the active mode. | | `data.items[].data[].positions[].underlyingInfo` | object | Nested asset metadata, oracle prices, and market prices for a lending market. | | `data.items[].data[].positions[].loanId` | string | Lista DAO brokered markets only: identifies a single fixed-term loan (the broker posId; the dynamic/flex position uses `type(uint128).max`). Present on per-loan breakdown rows; absent on the aggregate debt row and on the shared collateral row. Pass to `/v1/actions/lending/repay?loanId=…`. | | `data.items[].data[].positions[].term` | object | Per-loan fixed-term detail attached to a user position (`LendingPosition.term`), one per open loan. Emitted by Lista broker, Exactly, TermMax and Teller — several fields are lender-specific, and the repay economics behind them differ sharply per protocol (see FIXED_TERM_REPAY_TERMS.md). Lista only: the flexible/dynamic position uses `isDynamic = true` and the `type(uint128).max` `loanId` sentinel. | | `data.items[].data[].userConfig` | object | User configuration for a sub-account. | | `data.items[].data[].userConfig.selectedMode` | string | Mode/config key (e.g. e-mode category or vault address) | | `data.items[].data[].userConfig.id` | string | Config identifier | | `data.items[].data[].userConfig.isWhitelisted` | boolean | Whether user is whitelisted (for permissioned markets) | | `data.items[].balanceData` | object | Summary-level balance data (without discounted/adjusted fields). | | `data.items[].balanceData.deposits` | number | Total deposits in USD | | `data.items[].balanceData.debt` | number | Total debt in USD | | `data.items[].balanceData.collateral` | number | Collateral value in USD | | `data.items[].balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.items[].balanceData.nav` | number | Net asset value (deposits - debt) | | `data.items[].balanceData.deposits24h` | number | Deposits 24h ago | | `data.items[].balanceData.debt24h` | number | Debt 24h ago | | `data.items[].balanceData.nav24h` | number | NAV 24h ago | | `data.items[].balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.items[].balanceData.rewards[].asset` | string | Reward token contract address | | `data.items[].balanceData.rewards[].totalRewards` | number | Total accumulated rewards (token units) | | `data.items[].balanceData.rewards[].claimableRewards` | number | Immediately claimable rewards (token units) | | `data.items[].aprData` | object | Summary-level APR breakdown. | | `data.items[].aprData.apr` | number | Net APR (deposit - borrow) | | `data.items[].aprData.depositApr` | number | Weighted deposit APR | | `data.items[].aprData.borrowApr` | number | Weighted borrow APR | | `data.items[].aprData.rewardApr` | number | Total reward APR | | `data.items[].aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.items[].aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.items[].aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.items[].aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.items[].aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.items[].aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.items[].leverage` | number | Leverage ratio (deposits / nav) | | `data.summary` | object | Portfolio-wide totals with per-chain breakdowns. Per-lender summaries are fused into each LenderDataEntry in the items array. | | `data.summary.balanceData` | object | Summary-level balance data (without discounted/adjusted fields). | | `data.summary.balanceData.deposits` | number | Total deposits in USD | | `data.summary.balanceData.debt` | number | Total debt in USD | | `data.summary.balanceData.collateral` | number | Collateral value in USD | | `data.summary.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.summary.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.summary.balanceData.deposits24h` | number | Deposits 24h ago | | `data.summary.balanceData.debt24h` | number | Debt 24h ago | | `data.summary.balanceData.nav24h` | number | NAV 24h ago | | `data.summary.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.summary.balanceData.rewards[].asset` | string | Reward token contract address | | `data.summary.balanceData.rewards[].totalRewards` | number | Total accumulated rewards (token units) | | `data.summary.balanceData.rewards[].claimableRewards` | number | Immediately claimable rewards (token units) | | `data.summary.aprData` | object | Summary-level APR breakdown. | | `data.summary.aprData.apr` | number | Net APR (deposit - borrow) | | `data.summary.aprData.depositApr` | number | Weighted deposit APR | | `data.summary.aprData.borrowApr` | number | Weighted borrow APR | | `data.summary.aprData.rewardApr` | number | Total reward APR | | `data.summary.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.summary.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.summary.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.summary.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.summary.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.summary.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.summary.leverage` | number | Overall leverage ratio (deposits / nav) | | `data.summary.activeLenders` | integer | Number of lenders with positions | | `data.summary.activeChains` | integer | Number of chains with positions | | `data.partial` | boolean | Present and true when at least one lender could not be read in full (RPC error or reverted call). Totals are then a lower bound — a lender whose reads all failed is omitted rather than reported as an empty position. | | `data.incompleteLenders` | string[] | Present only when `partial` is set: the `chainId:lender` pairs whose on-chain reads (partly) failed. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "items": [ { "lender": "AAVE_V3", "chainId": "1", "account": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5", "data": [ { "accountId": "0", "health": 1.85, "borrowCapacityUSD": 3000, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "deposits": "1000000000000000000", "debt": "0", "debtStable": "0", "debtShares": "0", "depositShares": "0", "depositsUSD": 2500, "debtUSD": 0, "debtStableUSD": 0, "depositsUSDOracle": 2510, "debtUSDOracle": 0, "debtStableUSDOracle": 0, "collateralEnabled": true, "claimableRewards": 0.5, "withdrawable": "0.5", "borrowable": "100", "underlyingInfo": { "asset": {}, "oraclePrice": {}, "prices": {} }, "loanId": "450", "term": { "loanId": "450", "termId": 2, "isDynamic": false, "debt": "14.5003", "apr": 3.85, "maturity": 1781789025, "termDays": 7, "accruedInterest": "0.000358", "earlyRepayPenalty": "0.001211", "isMatured": false, "faceValue": "100.0", "earlyRepayDiscount": "1.0", "latePenalty": "2.25", "latePenaltyPerDay": "0.225", "latePenaltyApr": 164.24, "secondsLate": 0 } } ], "userConfig": { "selectedMode": "0", "id": "0", "isWhitelisted": true } } ], "balanceData": { "deposits": 10000.5, "debt": 5000.25, "collateral": 9000, "collateralAllActive": 10000.5, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "leverage": 2 } ], "summary": { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "collateral": 9000, "collateralAllActive": 10000.5, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "leverage": 2, "activeLenders": 3, "activeChains": 2 }, "partial": true, "incompleteLenders": [ "1:AAVE_V3", "1:COMPOUND_V3_USDC" ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/lending/user-positions/parse - operationId: `parse-user-positions` - docs: https://docs.1delta.io/1delta-api/parse-user-positions - tags: User Positions Parse user positions Accepts the raw multicall RPC responses obtained by executing the calls from `/rpc-call` and decodes them into structured user position data. **Workflow:** 1. Call `/rpc-call` to get prepared RPC calls and a `rpcCallId` 2. Execute the RPC calls against your own node 3. Send `rpcCallId` + `rawResponses` to this endpoint for parsing The `rpcCallId` ties the responses back to the cached preparation context (valid for 5 minutes). After successful parsing the cached context is deleted. **Response Structure:** - `items`: Flat array of lender entries sorted by net worth (descending). Each entry fuses sub-account position data with aggregated summary metrics (deposits, debt, APRs, health, leverage). - `summary`: Portfolio-wide totals (net worth, APRs, leverage, active counts) plus per-chain breakdowns. **Lender Entry includes:** - Per-asset deposits and debt (in USD and token units) - Sub-account data with health factors and borrow capacity - Aggregated lender-level metrics (total deposits/debt, weighted APRs, health factor, leverage) - Collateral status, withdrawable/borrowable amounts per position **Portfolio Summary includes:** - Total deposits, debt, and net worth (current + 24h ago) across all chains - Weighted average APRs and overall leverage ratio - Count of active lenders and chains - Per-chain totals (deposits, debt, net worth, lender count) **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `rpcCallId` | string | yes | The rpcCallId returned by /rpc-call. | | `rawResponses` | object[] | yes | Raw JSON-RPC response results in the same order as the rpcCalls array. Each entry is the hex-encoded result of the corresponding multicall3 aggregate3 call. | | `rawResponses[].result` | string | no | Hex-encoded result data | **Example request body** ```json { "rpcCallId": "string", "rawResponses": [ { "result": "string" } ] } ``` **Response `200`** — Parsed user position data with portfolio summary | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | User lending positions as a flat array with portfolio summary and per-chain breakdowns. | | `data.items` | object[] | Flat array of lender entries sorted by net worth (descending). Each entry fuses position data with aggregated summary metrics. | | `data.items[].lender` | string | Lender identifier | | `data.items[].chainId` | string | Chain ID | | `data.items[].account` | string | User account address | | `data.items[].data` | object[] | Sub-account position data | | `data.items[].data[].accountId` | string | Sub-account identifier (e.g., "0" for default, NFT ID for Init) | | `data.items[].data[].health` | number | Health factor (null if no debt). Values > 1 are healthy, < 1 at risk of liquidation. | | `data.items[].data[].borrowCapacityUSD` | number | Total USD borrowable while maintaining health >= 1 | | `data.items[].data[].balanceData` | object | Aggregated balance data for a sub-account. | | `data.items[].data[].balanceData.deposits` | number | Total deposits in USD | | `data.items[].data[].balanceData.debt` | number | Total debt in USD | | `data.items[].data[].balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.items[].data[].balanceData.collateral` | number | Collateral value in USD | | `data.items[].data[].balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.items[].data[].balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.items[].data[].balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.items[].data[].balanceData.nav` | number | Net asset value (deposits - debt) | | `data.items[].data[].balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.items[].data[].balanceData.debt24h` | number | Debt 24h ago | | `data.items[].data[].balanceData.nav24h` | number | NAV 24h ago | | `data.items[].data[].balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.items[].data[].aprData` | object | APR breakdown for a sub-account. | | `data.items[].data[].aprData.apr` | number | Net APR (deposit - borrow) | | `data.items[].data[].aprData.depositApr` | number | Weighted deposit APR | | `data.items[].data[].aprData.borrowApr` | number | Weighted borrow APR | | `data.items[].data[].aprData.rewardApr` | number | Total reward APR | | `data.items[].data[].aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.items[].data[].aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.items[].data[].aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.items[].data[].aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.items[].data[].aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.items[].data[].aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.items[].data[].positions` | object[] | Individual asset positions in this sub-account | | `data.items[].data[].positions[].marketUid` | string | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `data.items[].data[].positions[].deposits` | string | Deposit amount in token units (wei) | | `data.items[].data[].positions[].debt` | string | Variable debt in token units | | `data.items[].data[].positions[].debtStable` | string | Stable debt in token units | | `data.items[].data[].positions[].debtShares` | string | Debt share amount (protocol-specific, present when the protocol uses share-based accounting) | | `data.items[].data[].positions[].depositShares` | string | Deposit share amount (protocol-specific, present when the protocol uses share-based accounting) | | `data.items[].data[].positions[].depositsUSD` | number | Deposits in USD (market price) | | `data.items[].data[].positions[].debtUSD` | number | Variable debt in USD (market price) | | `data.items[].data[].positions[].debtStableUSD` | number | Stable debt in USD (market price) | | `data.items[].data[].positions[].depositsUSDOracle` | number | Deposits in USD using on-chain oracle price (used for risk/health calculations) | | `data.items[].data[].positions[].debtUSDOracle` | number | Variable debt in USD using on-chain oracle price | | `data.items[].data[].positions[].debtStableUSDOracle` | number | Stable debt in USD using on-chain oracle price | | `data.items[].data[].positions[].collateralEnabled` | boolean | Whether this asset is enabled as collateral | | `data.items[].data[].positions[].claimableRewards` | number | Claimable rewards in USD | | `data.items[].data[].positions[].withdrawable` | string | Max tokens withdrawable while maintaining health >= 1. Equals full deposit balance if collateral is not enabled. | | `data.items[].data[].positions[].borrowable` | string | Max tokens borrowable against remaining credit line. Zero if borrowing is disabled, reserve is frozen, or debt is disabled for the active mode. | | `data.items[].data[].positions[].underlyingInfo` | object | Nested asset metadata, oracle prices, and market prices for a lending market. | | `data.items[].data[].positions[].loanId` | string | Lista DAO brokered markets only: identifies a single fixed-term loan (the broker posId; the dynamic/flex position uses `type(uint128).max`). Present on per-loan breakdown rows; absent on the aggregate debt row and on the shared collateral row. Pass to `/v1/actions/lending/repay?loanId=…`. | | `data.items[].data[].positions[].term` | object | Per-loan fixed-term detail attached to a user position (`LendingPosition.term`), one per open loan. Emitted by Lista broker, Exactly, TermMax and Teller — several fields are lender-specific, and the repay economics behind them differ sharply per protocol (see FIXED_TERM_REPAY_TERMS.md). Lista only: the flexible/dynamic position uses `isDynamic = true` and the `type(uint128).max` `loanId` sentinel. | | `data.items[].data[].userConfig` | object | User configuration for a sub-account. | | `data.items[].data[].userConfig.selectedMode` | string | Mode/config key (e.g. e-mode category or vault address) | | `data.items[].data[].userConfig.id` | string | Config identifier | | `data.items[].data[].userConfig.isWhitelisted` | boolean | Whether user is whitelisted (for permissioned markets) | | `data.items[].balanceData` | object | Summary-level balance data (without discounted/adjusted fields). | | `data.items[].balanceData.deposits` | number | Total deposits in USD | | `data.items[].balanceData.debt` | number | Total debt in USD | | `data.items[].balanceData.collateral` | number | Collateral value in USD | | `data.items[].balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.items[].balanceData.nav` | number | Net asset value (deposits - debt) | | `data.items[].balanceData.deposits24h` | number | Deposits 24h ago | | `data.items[].balanceData.debt24h` | number | Debt 24h ago | | `data.items[].balanceData.nav24h` | number | NAV 24h ago | | `data.items[].balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.items[].balanceData.rewards[].asset` | string | Reward token contract address | | `data.items[].balanceData.rewards[].totalRewards` | number | Total accumulated rewards (token units) | | `data.items[].balanceData.rewards[].claimableRewards` | number | Immediately claimable rewards (token units) | | `data.items[].aprData` | object | Summary-level APR breakdown. | | `data.items[].aprData.apr` | number | Net APR (deposit - borrow) | | `data.items[].aprData.depositApr` | number | Weighted deposit APR | | `data.items[].aprData.borrowApr` | number | Weighted borrow APR | | `data.items[].aprData.rewardApr` | number | Total reward APR | | `data.items[].aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.items[].aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.items[].aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.items[].aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.items[].aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.items[].aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.items[].leverage` | number | Leverage ratio (deposits / nav) | | `data.summary` | object | Portfolio-wide totals with per-chain breakdowns. Per-lender summaries are fused into each LenderDataEntry in the items array. | | `data.summary.balanceData` | object | Summary-level balance data (without discounted/adjusted fields). | | `data.summary.balanceData.deposits` | number | Total deposits in USD | | `data.summary.balanceData.debt` | number | Total debt in USD | | `data.summary.balanceData.collateral` | number | Collateral value in USD | | `data.summary.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.summary.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.summary.balanceData.deposits24h` | number | Deposits 24h ago | | `data.summary.balanceData.debt24h` | number | Debt 24h ago | | `data.summary.balanceData.nav24h` | number | NAV 24h ago | | `data.summary.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.summary.balanceData.rewards[].asset` | string | Reward token contract address | | `data.summary.balanceData.rewards[].totalRewards` | number | Total accumulated rewards (token units) | | `data.summary.balanceData.rewards[].claimableRewards` | number | Immediately claimable rewards (token units) | | `data.summary.aprData` | object | Summary-level APR breakdown. | | `data.summary.aprData.apr` | number | Net APR (deposit - borrow) | | `data.summary.aprData.depositApr` | number | Weighted deposit APR | | `data.summary.aprData.borrowApr` | number | Weighted borrow APR | | `data.summary.aprData.rewardApr` | number | Total reward APR | | `data.summary.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.summary.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.summary.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.summary.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.summary.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.summary.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.summary.leverage` | number | Overall leverage ratio (deposits / nav) | | `data.summary.activeLenders` | integer | Number of lenders with positions | | `data.summary.activeChains` | integer | Number of chains with positions | | `data.partial` | boolean | Present and true when at least one lender could not be read in full (RPC error or reverted call). Totals are then a lower bound — a lender whose reads all failed is omitted rather than reported as an empty position. | | `data.incompleteLenders` | string[] | Present only when `partial` is set: the `chainId:lender` pairs whose on-chain reads (partly) failed. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "items": [ { "lender": "AAVE_V3", "chainId": "1", "account": "0xbadA9c382165b31419F4CC0eDf0Fa84f80A3C8E5", "data": [ { "accountId": "0", "health": 1.85, "borrowCapacityUSD": 3000, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "deposits": "1000000000000000000", "debt": "0", "debtStable": "0", "debtShares": "0", "depositShares": "0", "depositsUSD": 2500, "debtUSD": 0, "debtStableUSD": 0, "depositsUSDOracle": 2510, "debtUSDOracle": 0, "debtStableUSDOracle": 0, "collateralEnabled": true, "claimableRewards": 0.5, "withdrawable": "0.5", "borrowable": "100", "underlyingInfo": { "asset": {}, "oraclePrice": {}, "prices": {} }, "loanId": "450", "term": { "loanId": "450", "termId": 2, "isDynamic": false, "debt": "14.5003", "apr": 3.85, "maturity": 1781789025, "termDays": 7, "accruedInterest": "0.000358", "earlyRepayPenalty": "0.001211", "isMatured": false, "faceValue": "100.0", "earlyRepayDiscount": "1.0", "latePenalty": "2.25", "latePenaltyPerDay": "0.225", "latePenaltyApr": 164.24, "secondsLate": 0 } } ], "userConfig": { "selectedMode": "0", "id": "0", "isWhitelisted": true } } ], "balanceData": { "deposits": 10000.5, "debt": 5000.25, "collateral": 9000, "collateralAllActive": 10000.5, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "leverage": 2 } ], "summary": { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "collateral": 9000, "collateralAllActive": 10000.5, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "leverage": 2, "activeLenders": 3, "activeChains": 2 }, "partial": true, "incompleteLenders": [ "1:AAVE_V3", "1:COMPOUND_V3_USDC" ] } } ``` **Response `400`** — Validation error **Response `404`** — RPC call context not found or expired (older than 5 minutes). Call `/rpc-call` again. **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lending/user-positions/rpc-call - operationId: `user-position-rpc-calls` - docs: https://docs.1delta.io/1delta-api/user-position-rpc-calls - tags: User Positions User position RPC calls Prepares raw JSON-RPC calls (using multicall3 aggregate3) for fetching user lending positions on a single chain. Returns an `rpcCallId` and an array of `rpcCalls` that the integrator executes against their own RPC provider. The raw responses are then submitted to `/parse` together with the `rpcCallId`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) | | `chain` | query | string | yes | Chain ID to query | | `lenders` | query | string | no | Comma-separated lender IDs to filter by. If omitted, all supported lenders for the chain are included. See the `LenderId` schema for the full set of accepted values. | | `batchSize` | query | integer | no | Max number of sub-calls per multicall batch | | `blockTag` | query | string | no | Block tag for the RPC calls | **Response `200`** — Prepared RPC calls with a context ID for parsing | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `data.data.rpcCallId` | string | Unique ID referencing the server-side cached context. Pass this to /parse together with the raw responses. Valid for 5 minutes. | | `data.data.rpcCalls` | object[] | Ordered list of JSON-RPC calls to execute against the target chain RPC. Each call uses multicall3 aggregate3. | | `data.data.rpcCalls[].method` | string | JSON-RPC method name | | `data.data.rpcCalls[].params` | any[] | JSON-RPC parameters (call object and block tag) | | `actions` | null | | **Example response** ```json { "success": true, "data": { "data": { "rpcCallId": "string", "rpcCalls": [ { "method": "eth_call", "params": [] } ] } } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › Prices ### GET /v1/data/prices/latest - operationId: `get-latest-prices` - docs: https://docs.1delta.io/1delta-api/get-latest-prices - tags: Prices Get latest prices Returns latest USD prices for tracked assets. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `assets` | query | string[] | no | Asset group keys (repeatable) | | `asOf` | query | string | no | ISO date anchor; defaults to latest hour | **Response `200`** — Latest price data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.asOf` | string | Timestamp the data was measured at. | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object | Map of asset_group → priceUsd | | `data.debug` | object | | | `data.debug.rows` | object[] | | | `actions` | null | | **Example response** ```json { "success": true, "data": { "asOf": "2026-01-01T00:00:00Z", "count": 1, "items": { "USDC": 1.0001, "WBTC": 67432.12 }, "debug": { "rows": [ {} ] } } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/prices/latest-asof - operationId: `get-prices-as-of-x-hours-ago` - docs: https://docs.1delta.io/1delta-api/get-prices-as-of-x-hours-ago - tags: Prices Get prices as of X hours ago Returns prices at an effective cutoff time computed as `asOf − hoursAgo`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `hoursAgo` | query | number | yes | Non-negative number of hours in the past | | `asOf` | query | string | no | ISO date anchor; defaults to now | | `assetGroups` | query | string[] | no | Asset group keys (repeatable) | **Response `200`** — Prices at the effective cutoff time | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.asOf` | string | Timestamp the data was measured at. | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object | Map of asset_group → priceUsd | | `data.debug` | object | | | `data.debug.rows` | object[] | | | `actions` | null | | **Example response** ```json { "success": true, "data": { "asOf": "2026-01-01T00:00:00Z", "count": 1, "items": { "USDC": 1.0001, "WBTC": 67432.12 }, "debug": { "rows": [ {} ] } } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/sparklines - operationId: `sparkline-price-ratio-time-series` - docs: https://docs.1delta.io/1delta-api/sparkline-price-ratio-time-series - tags: Prices Sparkline price-ratio time series Returns price-ratio time series for the cross product of `currencies` × `quotes` over a configurable lookback window (default 24h). **Request body:** `{ currencies: string[], quotes: string[], windowHours?: number }` where each ID is either a shorthand (`"usd"`, `"eth"`) or `"{chainId}-{address}"`. See the `SparklineRequest` schema. **Response:** `{ windowHours, count, result }`. Each `result[i]` has `{ currency, quote, data }` where `data` is an array of `{ time, value }` points and `value = price(currency) / price(quote)`. Pairs with no data are omitted from `result` (so `count` ≤ `currencies.length × quotes.length`). Useful for rendering small inline charts (token cards, asset selectors) without hitting the heavier snapshot endpoints. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `currencies` | string[] | yes | Currency identifiers. Use shorthand ("usd", "eth") or "{chainId}-{address}" format. | | `quotes` | string[] | yes | Quote identifiers (same format as currencies) | | `windowHours` | number | no | Lookback window in hours | **Example request body** ```json { "currencies": [ "string" ], "quotes": [ "string" ], "windowHours": 24 } ``` **Response `200`** — Sparkline data | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.windowHours` | number | | | `data.count` | integer | Number of non-empty sparkline pairs | | `data.result` | object[] | | | `data.result[].currency` | string | | | `data.result[].quote` | string | | | `data.result[].data` | object[] | Informational payload. `null` when the endpoint only builds calldata. | | `data.result[].data[].value` | number | Price ratio (currency / quote) | | `data.result[].data[].time` | string | | | `actions` | null | | **Example response** ```json { "success": true, "data": { "windowHours": 1, "count": 1, "result": [ { "currency": "string", "quote": "string", "data": [ { "value": 1, "time": "2026-01-01T00:00:00Z" } ] } ] } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › Token ### GET /v1/data/token/available - operationId: `get-available-lending-assets` - docs: https://docs.1delta.io/1delta-api/get-available-lending-assets - tags: Token Get available lending assets Returns the list of assets available for lending on a given chain. Proxied from origin with a long-lived cache (1 hour). **Filters:** - `chainId` / `chainIds` — filter by chain - `lender` — filter by lender protocol - `symbol`, `name`, `address` — filter by asset metadata - `assetGroup` — filter by asset group **Response Structure:** - `count`: Number of matching assets - `items`: Array of asset objects with address, chain_id, symbol, name, and additional metadata **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Filter by chain ID See the `ChainId` schema for the full set of supported chains. | | `chainIds` | query | string | no | Comma-separated chain IDs to filter by (alternative to chainId) See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | no | Filter by lender protocol key See the `LenderId` schema for the full set of accepted values. | | `symbol` | query | string | no | Filter by token symbol | | `name` | query | string | no | Filter by token name (partial match) | | `address` | query | string | no | Filter by token contract address | | `assetGroup` | query | string | no | Filter by asset group | **Response `200`** — Available lending assets | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of available assets | | `data.items` | object[] | The result set for this response. | | `data.items[].address` | string | Token contract address | | `data.items[].chain_id` | integer | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.items[].symbol` | string | Token symbol, e.g. `WETH`. | | `data.items[].name` | string | Human-readable display name. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": [ { "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "chain_id": 1, "symbol": "USDC", "name": "USD Coin" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/token/balances - operationId: `token-balances` - docs: https://docs.1delta.io/1delta-api/token-balances - tags: Token Token balances Fetches token balances for a given account on a specific chain, including USD values. **Features:** - Automatically includes native token balance (ETH, BNB, etc.) - Fetches current prices for USD conversion - Returns both raw and formatted balance values **Response Structure:** - `items`: Array of balance entries for each token - `count`: Total number of balance entries **Balance Entry includes:** - `address`: Token contract address (zeroAddress for native) - `symbol`: Token symbol - `name`: Token name - `decimals`: Token decimals - `balanceRaw`: Raw balance as string (wei/smallest unit) - `balance`: Formatted balance as decimal string - `balanceUSD`: Balance value in USD **Note:** The native token balance is always included with address `0x0000000000000000000000000000000000000000`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID to fetch balances on See the `ChainId` schema for the full set of supported chains. | | `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) | | `assets` | query | string | yes | Comma-separated token addresses to fetch balances for | **Response `200`** — Token balances with USD values | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.account` | string | Lowercase account address | | `data.count` | integer | Number of balance entries | | `data.items` | object[] | The result set for this response. | | `data.items[].address` | string | Token contract address (zeroAddress for native) | | `data.items[].symbol` | string | Token symbol, e.g. `WETH`. | | `data.items[].name` | string | Human-readable display name. | | `data.items[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].balanceRaw` | string | Raw balance in smallest unit (wei) | | `data.items[].balance` | string | Formatted balance as decimal string | | `data.items[].priceUSD` | number | Per-unit USD price of the token | | `data.items[].balanceUSD` | number | Balance value in USD | | `actions` | null | | **Example response** ```json { "success": true, "data": { "chainId": "1", "account": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5", "count": 1, "items": [ { "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "symbol": "USDC", "name": "USD Coin", "decimals": 6, "balanceRaw": "1000000", "balance": "1.0", "priceUSD": 1, "balanceUSD": 1 } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/token/balances/lending - operationId: `lending-token-balances` - docs: https://docs.1delta.io/1delta-api/lending-token-balances - tags: Token Lending token balances Fetches token balances for all available lending assets on a chain for a given account. Combines the available-assets lookup with balance fetching in a single call. **How it works:** 1. Fetches all available lending asset addresses from origin (optionally filtered by lender) 2. Fetches token balances for those assets via multicall 3. Enriches with token metadata, prices, and USD values **Response Structure:** - `items`: Array of non-zero balance entries (same format as `/token/balances`) - `count`: Number of tokens with non-zero balance **Balance Entry includes:** - `address`: Token contract address (zeroAddress for native) - `symbol`: Token symbol - `name`: Token name - `decimals`: Token decimals - `balanceRaw`: Raw balance as string (wei/smallest unit) - `balance`: Formatted balance as decimal string - `priceUSD`: Per-unit USD price - `balanceUSD`: Balance value in USD **Note:** Zero-balance entries are excluded. The native token balance is included only if non-zero. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID to fetch balances on See the `ChainId` schema for the full set of supported chains. | | `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) | | `lender` | query | string | no | Optional lender filter — only fetch assets available on this protocol See the `LenderId` schema for the full set of accepted values. | **Response `200`** — Token balances for all lending assets with USD values | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.account` | string | Lowercase account address | | `data.count` | integer | Number of balance entries | | `data.items` | object[] | The result set for this response. | | `data.items[].address` | string | Token contract address (zeroAddress for native) | | `data.items[].symbol` | string | Token symbol, e.g. `WETH`. | | `data.items[].name` | string | Human-readable display name. | | `data.items[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].balanceRaw` | string | Raw balance in smallest unit (wei) | | `data.items[].balance` | string | Formatted balance as decimal string | | `data.items[].priceUSD` | number | Per-unit USD price of the token | | `data.items[].balanceUSD` | number | Balance value in USD | | `actions` | null | | **Example response** ```json { "success": true, "data": { "chainId": "1", "account": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5", "count": 1, "items": [ { "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "symbol": "USDC", "name": "USD Coin", "decimals": 6, "balanceRaw": "1000000", "balance": "1.0", "priceUSD": 1, "balanceUSD": 1 } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/data/token/balances/parse - operationId: `parse-token-balances` - docs: https://docs.1delta.io/1delta-api/parse-token-balances - tags: Token Parse token balances Accepts the raw hex RPC response obtained by executing the call from `/token/balances/rpc-call` and decodes it into structured token balance data with USD values. **Workflow:** 1. Call `/token/balances/rpc-call` to get prepared RPC calls and a `rpcCallId` 2. Execute the RPC call against your own node 3. Send `rpcCallId` + `rawResponses` to this endpoint for parsing The `rpcCallId` ties the response back to the cached preparation context (valid for 5 minutes). After successful parsing the cached context is deleted. **Multi-chain mode** (when the rpc-call was made with `chains`): `rawResponses` entries are `{ chainId, result }` (result = hex string or full JSON-RPC envelope), and the response is `{ account, chains: [{ chainId, count, items }], missingChains? }` — chains whose response was not submitted appear in `missingChains`. **Response Structure:** - `items`: Array of balance entries for each token - `count`: Total number of balance entries **Balance Entry includes:** - `address`: Token contract address (zeroAddress for native) - `symbol`: Token symbol - `name`: Token name - `decimals`: Token decimals - `balanceRaw`: Raw balance as string (wei/smallest unit) - `balance`: Formatted balance as decimal string - `balanceUSD`: Balance value in USD **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `rpcCallId` | string | yes | The rpcCallId returned by /token/balances/rpc-call. | | `rawResponses` | string[] | yes | Array containing the raw hex-encoded result from the eth_call. Typically a single-element array. | **Example request body** ```json { "rpcCallId": "string", "rawResponses": [ "string" ] } ``` **Response `200`** — Token balances with USD values | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.account` | string | Lowercase account address | | `data.count` | integer | Number of balance entries | | `data.items` | object[] | The result set for this response. | | `data.items[].address` | string | Token contract address (zeroAddress for native) | | `data.items[].symbol` | string | Token symbol, e.g. `WETH`. | | `data.items[].name` | string | Human-readable display name. | | `data.items[].decimals` | integer | Token decimals — divide raw amounts by `10 ** decimals`. | | `data.items[].balanceRaw` | string | Raw balance in smallest unit (wei) | | `data.items[].balance` | string | Formatted balance as decimal string | | `data.items[].priceUSD` | number | Per-unit USD price of the token | | `data.items[].balanceUSD` | number | Balance value in USD | | `actions` | null | | **Example response** ```json { "success": true, "data": { "chainId": "1", "account": "0xbada9c382165b31419f4cc0edf0fa84f80a3c8e5", "count": 1, "items": [ { "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "symbol": "USDC", "name": "USD Coin", "decimals": 6, "balanceRaw": "1000000", "balance": "1.0", "priceUSD": 1, "balanceUSD": 1 } ] } } ``` **Response `400`** — Validation error **Response `404`** — RPC call context not found or expired (older than 5 minutes). Call `/token/balances/rpc-call` again. **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/token/balances/rpc-call - operationId: `token-balance-rpc-calls` - docs: https://docs.1delta.io/1delta-api/token-balance-rpc-calls - tags: Token Token balance RPC calls Prepares raw JSON-RPC `eth_call`s for fetching token balances using a batched balance-fetcher contract. Returns an `rpcCallId` and an array of `rpcCalls` that the integrator executes against their own RPC provider(s). The raw responses are then submitted to `/token/balances/parse` together with the `rpcCallId`. Two modes: **single-chain** (`chainId` + required `assets`; `rpcCalls` is a bare call array) and **multi-chain** (`chains` CSV, max 30; `rpcCalls` entries are `{ chainId, call }`). In multi-chain mode `assets` is optional — it defaults to each chain's curated `mainTokens` from the token lists, keeping balance scans small even where full lists hold tens of thousands of tokens (max 200 assets per chain). Chains without any known main tokens are reported in `skippedChains`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | no | Chain ID to fetch balances on (single-chain mode; required unless `chains` is given) See the `ChainId` schema for the full set of supported chains. | | `chains` | query | string | no | Comma-separated chain IDs (multi-chain mode, max 30). Takes precedence over `chainId`. | | `account` | query | string | yes | EVM account address (0x-prefixed, 40 hex chars) | | `assets` | query | string | no | Comma-separated token addresses. Required in single-chain mode; optional in multi-chain mode (defaults to each chain’s `mainTokens`; when given, applied to every chain). | | `blockTag` | query | string | no | Block tag for the RPC call | **Response `200`** — Prepared RPC calls with a context ID for parsing | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `data.data.rpcCallId` | string | Unique ID referencing the server-side cached context. Pass this to /parse together with the raw responses. Valid for 5 minutes. | | `data.data.rpcCalls` | object[] | Ordered list of JSON-RPC calls to execute against the target chain RPC. Each call uses multicall3 aggregate3. | | `data.data.rpcCalls[].method` | string | JSON-RPC method name | | `data.data.rpcCalls[].params` | any[] | JSON-RPC parameters (call object and block tag) | | `actions` | null | | **Example response** ```json { "success": true, "data": { "data": { "rpcCallId": "string", "rpcCalls": [ { "method": "eth_call", "params": [] } ] } } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/token/list - operationId: `get-token-list-for-a-chain` - docs: https://docs.1delta.io/1delta-api/get-token-list-for-a-chain - tags: Token Get token list for a chain Fetches the complete token list for a given chain, including metadata such as symbol, name, decimals, and asset group. **Response Structure:** - `tokens`: Object keyed by token address (lowercase) containing token metadata - `count`: Total number of tokens in the list **Token Metadata includes:** - `symbol`: Token symbol (e.g., "USDC") - `name`: Full token name (e.g., "USD Coin") - `decimals`: Token decimals (e.g., 6 for USDC) - `assetGroup`: Asset grouping for price lookups - `logoURI`: Optional logo URL **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID to fetch token list for See the `ChainId` schema for the full set of supported chains. | **Response `200`** — Token list for the chain | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.count` | integer | Total number of tokens | | `data.tokens` | object | Map of token address (lowercase) → token metadata | | `actions` | null | | **Example response** ```json { "success": true, "data": { "chainId": "1", "count": 1, "tokens": {} } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/token/prices - operationId: `token-prices-by-address` - docs: https://docs.1delta.io/1delta-api/token-prices-by-address - tags: Token Token prices by address Returns per-address USD prices for the given asset addresses on a chain. **How it works:** 1. Resolves each address to its asset group via the token list 2. Looks up the latest USD price for each asset group 3. Returns a map of address → price **Query format:** - `assets`: Comma-separated list of EVM addresses (0x-prefixed, 40 hex chars) **Response Structure:** - `items`: Object mapping lowercase addresses to their USD price (0 if unknown) - `count`: Number of resolved assets **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `assets` | query | string | yes | Comma-separated list of token addresses | **Response `200`** — Per-address USD prices | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.count` | integer | Number of resolved assets | | `data.items` | object | Map of lowercase address → USD price | | `actions` | null | | **Example response** ```json { "success": true, "data": { "chainId": "1", "count": 1, "items": { "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48": 1, "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2": 3500.12 } } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › Vaults (Data) ### GET /v1/data/vaults - operationId: `vaults` - docs: https://docs.1delta.io/1delta-api/vaults - tags: Vaults (Data) Get vault data across providers Returns public vault data across the supported ERC-4626-style providers on a single chain. By default this is served from the recorder origin — a DB-backed, USD-priced, **paginated** listing — and the response is a flat `{ start, count, items[] }` envelope (one entry per vault, see *Response shape* below). **Pagination** — `start` is the row offset and `limit` the page size; the origin returns up to one page per call. To walk a chain, request `start=0`, then `start=limit`, `start=2*limit`, … until fewer than `limit` items come back. This is intentional: large chains return hundreds of vaults and are paged rather than returned in one payload. **Legacy live mode** — pass `source=live` to bypass the origin and compute the data live on-chain via multicall. This returns the older **provider-keyed** `VaultPublicDataAll` shape (one key per provider, *not* `items[]`) and ignores `start`/`limit`. It is also the automatic fallback when no origin is configured (e.g. local dev) or the origin is unreachable. **Supported providers** | key | source | |---|---| | `fluid` | Fluid `fTokens` (ERC-4626 yield tokens) and vaults (NFT-position margin markets) | | `gearbox` | Gearbox V3 passive PoolV3 (ERC-4626 Diesel shares) | | `morpho` | Morpho Blue MetaMorpho vaults | | `lista` | Lista DAO earn vaults (Moolah-fork of MetaMorpho, BNB chain; fetched on-chain) | | `silo` | Silo V2 + V3 isolated lending vaults (GraphQL-backed) | | `euler-earn` | Euler V2 Earn vaults (ERC-4626) | | `lst` | Protocol-issued liquid-staking share tokens (Lido wstETH, Rocket Pool rETH, EtherFi weETH, Renzo ezETH, Kelp rsETH, Swell rswETH/swETH, Puffer pufETH, YieldNest ynETH, StakeWise osETH, Stader ETHx, Mantle mETH, Coinbase cbETH). Ethereum only in this drop. | | `savings` | ERC-4626 yield-bearing-stablecoin wrappers (Ethena sUSDe, Sky sUSDS/stUSDS, Maker sDAI, Reservoir wsrUSD, YieldFi yUSD, Resolv wstUSR, Angle stUSD/stEUR, Falcon sUSDf, InfiniFi siUSD, Maple syrupUSDC/syrupUSDT). Plus Avant savUSD on Avalanche and YO yoETH on Base. | | `yearn` | Yearn V3 vaults (VaultV3 + TokenizedStrategy ERC-4626) on Ethereum, Polygon, Base, Arbitrum, Gnosis, Sonic, Katana. Discovered + priced via the yDaemon API. | | `aave-earn` | Aave Earn ("stable") vaults — curator-run ERC-4626 wrappers over an Aave v3 supply position. Discovered + priced via the Aave public GraphQL API (`api.v3.aave.com`) by tracked curator/vault, enriched on-chain for `totalSupply` + share price. | **Response shape** *Default (origin) mode:* `{ start, count, items[] }` where each item is a normalized, USD-priced vault record: `{ chainId, provider, vaultAddress, underlying, symbol, name, displayName, curatorName, decimals, assetDecimals, dataTs, updatedAt, rates: { depositRate, rewardsRate, totalRate, fee }, tvl: { totalAssets, totalSupply, totalAssetsFormatted, totalAssetsUsd }, liquidity: { liquidity, liquidityFormatted, liquidityUsd }, underlyingInfo, vaultInfo, curatorEntity, providerMeta, … }`. `totalAssetsUsd` / `liquidityUsd` are computed by the recorder from its own price store (see margin-fetcher `DATABASE_INTEGRATION.md`). Three metadata bundles travel with every item (mirroring lending's `underlyingInfo` + `lenderInfo`): - **`underlyingInfo`** — the underlying token: `{ asset: { chainId, address, symbol, name, decimals, logoURI, assetGroup, currencyId, props }, prices: { priceUsd, priceTs } }`. - **`vaultInfo`** — the vault's *own* identity: `{ address, symbol, name, logoURI, assetGroup, yieldProfile, denomination }`. `logoURI` is resolved from the **share token's** token-list entry, falling back to the underlying asset's logo. `name` uses the branded share-token name for `lst`/`savings` (e.g. *etherFi weETH*) and the curated label elsewhere (e.g. *Steakhouse USDC*). - **`curatorEntity`** — the curator's `{ name, logoUri }` from the curator registry, or `null`. *Legacy live mode (`source=live`):* the top-level object is keyed by provider name. Each provider's value is a free-form payload from `@1delta/margin-fetcher`'s `getVaultPublicDataAll` — schemas diverge per provider (see the package's types for exact field shapes). Common fields across most providers: vault/share token address, underlying asset, supply rate, total assets / supply, and provider-specific metadata (e.g. Fluid `vaultId`, Silo `siloAddress`). **LST deposit metadata (`providerMeta` on `lst` items)** `lst` records carry the data needed to build a deposit without reading SDK source: - `isMintable` — `false` ⇒ no permissionless on-chain mint (e.g. cbETH); skip the action endpoint. - `mintContract` — the mint target. - `exchangeRate` / `convertToShares` — to compute expected output and a `minOut`. - `isRebasing` — output-balance semantics (stETH/eETH rebase; wstETH/weETH don't). - `mintInputAsset` — the **primary** pay asset (`native` or an ERC-20 address). - **`acceptedInputs[]`** — the full accept-set, each `{ asset: "native"|"0x…", symbol?, mode: "direct"|"wrap"|"submit-wrap", needs?: string[] }`. `asset` is what to pass as `payAsset`; `needs` lists the option query params that path requires. This is the machine-readable answer to "what can I pay with"; drive the deposit request off it. See `GET /v1/actions/vaults/lst` for the build flow. - **`delegation`** — present only when the deposit requires/allows picking a validator/group/node/pool: `{ required, kind, optionKey, default, source }`. **Absent ⇒ pooled** (no picker needed). When present and `source: "endpoint"`, fetch the selectable set from [/v1/data/vaults/validators](/1delta-api/vaults-validators) and send the chosen `id` back to the deposit as the param named by `delegation.optionKey`. This is the flag that tells the UI whether a validator fetch is needed. Attached by the worker in both origin and `source=live` modes. **Exit fees (`withdrawFeeBps`)** Basis points (`10` = 0.10 %), on `gearbox` pools and on `savings` entries whose `withdrawalMode` is `fee-or-queued` (Native Credit Pool `wNLP`). Distinct from `rates.fee`, which is a **performance** fee skimmed from yield — `withdrawFeeBps` is a one-off charge on the way **out**. For Native `wNLP` specifically, an exit has two legs and only one of them is priced by this field: - **Instant** (`instantRedeem`) — the fee is deducted from the underlying paid to the receiver, never collected as a separate transfer, so the caller neither funds nor approves it: `received = shares × exchangeRate × (1 − withdrawFeeBps/10_000)`. Capped by `liquidity`, which is a **gross** figure — what actually lands is `liquidity × (1 − withdrawFeeBps/10_000)`. - **Queued** (`requestWithdrawal` → wait `withdrawalCooldownSeconds` → `claim`) — pays at par, so `withdrawFeeBps` does not apply. Its cost is implicit: the payout is snapshotted at request time and yield accruing over the wait goes to the protocol. At a 3-day window that is worth a few bps against a 100 bps instant fee, which is why the action builders default to the queue and require `instant=true` to take the haircut. There is no deposit or management fee on these vaults — `exchangeRate` and the reported rates are already net. `instantRedeemEnabled: false` means the pool is queue-only and `withdrawFeeBps` is unreachable. **Lockup likelihood (`instantLiquidityRatio`, `savings` items)** `liquidity / totalAssets` clamped to `0…1` — the share of the vault exitable **this block**, so `1 − instantLiquidityRatio` is the share that must queue. `instant` vaults report `1`, cooldown/queued/request-based report `0`, and Native `fee-or-queued` pools report live coverage (observed across the full range: `1.00` on Ethereum `wNLP-USDC`, `0.20` on `wNLP-WBTC`, `0.0005` on BNB `wNLP-T4B`). Not named `utilization` on purpose: these protocols expose no debt accumulator, so `borrowed / supplied` is not readable per pool — this measures exit **coverage** instead, which is what actually predicts lockup. Two caveats: Native's buffer also custodies market-maker collateral so it can exceed the pool it serves (hence the clamp — `1` means "fully covered", not "zero utilization"), and it is a live spot reading that moves as market makers draw inventory. Nothing is lost below `1`; the remainder redeems at par through the queue. **Related action endpoints** - `GET /v1/actions/vaults/deposit` — ERC-4626 deposit via the 1delta Composer, with optional Fluid native-deposit path. Also serves Native `wNLP` (auto-detected; no `underlying` needed). - `GET /v1/actions/vaults/withdraw` — ERC-4626 withdraw via the 1delta Composer, with native-unwrap support. Also serves Native `wNLP` (`instant=true` for the fee-paying leg). - `GET /v1/actions/vaults/lst` — LST/LRT mint · withdraw-request · claim · cancel, driven by the `acceptedInputs` above. - `GET /v1/actions/vaults/savings` — cooldown/queued savings exits, plus Native `wNLP` deposit · request-withdraw · claim · cancel. For Fluid **margin vaults** (the NFT-position kind, not fTokens), the lending action endpoints (`/v1/actions/lending/{deposit,withdraw,borrow,repay}`) are the right surface — they understand the per-vault `FLUID__` lender keys and Fluid's NFT ownership model (including the pre-flight `ownerOf` validation for deposit-to-existing-NFT with a custom `receiver`). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID to query See the `ChainId` schema for the full set of supported chains. | | `start` | query | integer | no | Pagination offset (origin mode). Row index of the first item to return. Non-negative integer; defaults to 0. | | `limit` | query | integer | no | Pagination page size (origin mode). Max items to return per call. Non-negative integer. Ignored in `source=live` mode. | | `provider` | query | string | no | Origin mode: narrow the listing to a single provider (e.g. `morpho`). | | `source` | query | "live" | no | Set to `live` to bypass the origin and compute on-chain via multicall (returns the legacy provider-keyed shape; `start`/`limit` ignored). | | `providers` | query | string | no | Legacy live mode only (`source=live`): CSV of vault providers to include. Defaults to all (`fluid,gearbox,morpho,lista,silo,euler-earn,lst,savings,lagoon,aave-earn,upshift,yearn,hypercore,gmx`). Unknown providers return 400. | | `siloProtocolVersion` | query | "v2" \| "v3" | no | Narrow the Silo query to a single protocol version. Has no effect on other providers. | | `siloLimit` | query | integer | no | Page-size hint for the Silo GraphQL query (positive integer). | | `terms` | query | "digest" \| "full" \| "none" | no | Term-sheet depth attached to every vault as `termSheet` — the SAME shape and the same parameter as `/v1/data/lending/latest`, so one renderer handles an Aave reserve and a Pendle PT. A vault carries `termSheet.supply` only; `borrow` is absent, and that absence is the statement that it cannot be borrowed. `digest` (default) is the compact form; `full` inlines `info.description`, `backedBy.items[]` and the `coverage` map; `none` omits the field. **Read `coverage` before trusting a silence** — it separates "does not apply here" (`notApplicable`) from "not wired yet" (`pending`), so an absent `governance` block never reads as "ungoverned". Origin mode only. | **Response `200`** — Origin mode: `{ start, count, items[] }` paginated, USD-priced vault records. Legacy live mode (`source=live`): provider-keyed vault data, with failed providers omitted (the worker logs a warning but does not propagate per-provider errors). | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/vaults/user - operationId: `vaults-user` - docs: https://docs.1delta.io/1delta-api/vaults-user - tags: Vaults (Data) Get user balances across ERC-4626 vaults Returns per-vault balances for `account` across the supplied ERC-4626 share-token addresses. Static vault metadata (underlying, decimals, share-price ratio) is sourced from the cached `/v1/data/vaults` public-data fetch, so this endpoint's only on-chain footprint is exactly one `balanceOf(account)` per vault. **Why this exists** Vault shares are plain ERC-20s, so `/v1/data/token/balances` can read them — but it can't convert shares → assets. This endpoint folds that conversion in so the frontend doesn't have to redo `shares * totalAssets / totalSupply` math (and get the rounding subtly wrong). **Scope** Vault addresses must be tracked by `/v1/data/vaults` (the 5 supported providers — `fluid`, `gearbox`, `morpho`, `silo`, `euler-earn`). Unknown addresses are listed back to the caller in the response's `unknown` field; a request that contains *only* unknown addresses returns 400. Untracked vaults are intentionally not auto-included — the 1delta data layer only surfaces vaults that have passed risk review. **Per-item fields** (naming mirrors `/v1/data/token/balances` — `Raw` is a stringified uint, `` is the formatted human-readable string) | field | meaning | |---|---| | `vault` | share-token address (echoes the input) | | `underlying` | result of `vault.asset()` | | `symbol`, `name`, `decimals` | from the token registry / on-chain `decimals()` | | `sharesRaw` / `shares` | raw uint + formatted balance in vault tokens | | `assetsRaw` / `assets` | shares converted to underlying at the current fair share price (via `convertToAssets`) — raw uint + formatted | | `priceUSD` | unit price of the underlying | | `balanceUSD` | `assets * priceUSD` — USD value of the position | **Resilience** Failed reads (e.g. a non-ERC-4626 address slipped into the list, or a vault that reverts on `convertToAssets`) are silently dropped from the response — the whole request is not failed. Vaults the user hasn't deposited into (zero shares) are kept in the response so the caller can render a deterministic table. **Scope** This is for passive ERC-4626 vaults (Fluid fTokens, MetaMorpho, Gearbox V3 pools, Silo, Euler Earn). For Fluid's NFT-position **margin vaults**, use `/v1/data/lending/user-positions` instead — it understands the `FLUID__` lender keys and the NFT-per-position model. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `account` | query | string | yes | User address (EOA or contract) | | `vaults` | query | string | yes | CSV of ERC-4626 share-token addresses to query. Duplicates are de-duped; invalid addresses are skipped. | **Response `200`** — Per-vault balances joined with underlying prices. Items with failed reads are omitted; zero-share entries are kept. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/vaults/validators - operationId: `vaults-validators` - docs: https://docs.1delta.io/1delta-api/vaults-validators - tags: Vaults (Data) Get selectable validators for an LST deposit Returns the selectable **delegation targets** (validators / validator-groups / nodes) for an LST that lets — or requires — the depositor to choose where the stake is delegated. The companion to the `delegation` descriptor carried on each `lst` item in [/v1/data/vaults](/1delta-api/vaults): the descriptor says *whether* a choice is needed and the deposit option key to send it back as; this endpoint returns the live set. **The flow** 1. `/v1/data/vaults?provider=lst` → an item's `providerMeta.delegation` tells you if a choice is needed: - **absent** ⇒ pooled LST (Lido, Rocket Pool, …) — no picker, deposit directly. - `{ required, kind, optionKey, default, source }` ⇒ a selection applies. 2. If `source: "endpoint"`, call this endpoint to populate the picker. 3. Send the chosen item's `id` back to /v1/actions/vaults/deposit as the param named by `delegation.optionKey` (e.g. `validator=` for Core, `validatorGroup=` for Celo). **Behaviour by LST type** - **Required** (Core stCORE — `validator`): the picker is mandatory; preselect the `recommended` item. - **Optional / auto** (Celo stCELO — `validatorGroup`, `default: "auto"`): the picker is optional — omit the choice and the deposit endpoint auto-resolves a valid group. Offer it as an "advanced" control. - **Off-chain** (Solv — `poolId`, `source: "offchain"`): `items[]` is empty — the value comes from the protocol's docs, not the chain. Render an input, not a list. - **Pooled / unknown**: `delegation: null`, empty `items[]` (200, not 404) so a UI can treat "no selection" uniformly. **Per-item fields** | field | meaning | |---|---| | `id` | the opaque value to pass back as `delegation.optionKey` (validator / group / node address) | | `status` | `active` · `inactive` · `jailed` · `full` — only `active` targets are `selectable` | | `selectable` | passes the protocol's eligibility (healthy + not blocked + has room) | | `recommended` | the default pick (best capacity / health) — preselect this | | `receivableVotes` | remaining capacity (raw underlying string), where the protocol exposes it (Celo) — show as "room left" so a user avoids a near-full target | Only the selectable set is returned today; per-validator APR / commission are populated as clean sources are wired (absent ⇒ not yet available, never approximated). Results are cached ~60s (validator metadata moves per epoch/round, not per block). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `shareToken` | query | string | yes | LST share-token address (alias: `vault`). | **Response `200`** — `{ chainId, shareToken, delegation, start, count, items[] }`. `delegation` is null for pooled/unknown share tokens; `items[]` is empty for pooled or off-chain (Solv poolId) selections. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/vaults/withdrawals - operationId: `vaults-withdrawals` - docs: https://docs.1delta.io/1delta-api/vaults-withdrawals - tags: Vaults (Data) Get a user's pending vault withdrawal requests Returns a user's **pending withdrawal requests** across every vault that has a withdrawal queue / cooldown (LSTs, savings cooldowns, ERC-7540 async vaults). The static LST/savings withdrawal registry is always probed; pass `vaults` to additionally read arbitrary ERC-7540 vaults by address. Each entry is normalised to a uniform shape so the frontend treats every protocol identically — render the list, and when `status === "claimable"` build the claim via the matching action endpoint ([/v1/actions/vaults/lst](/1delta-api/vaults-lst) or [/savings](/1delta-api/vaults-savings)). **Response:** `{ chainId, account, count, requests }`, where each `requests[]` entry carries: | field | meaning | |---|---| | `lst` | the share-token the request was made against | | `brand`, `symbol` | UI labels | | `requestId` | protocol-native id (NFT tokenId, queue index, 7540 requestId, or a bucket name like `waiting`/`unbonded`) — pass back to the claim action | | `amountUnderlying` | wei the request returns on claim (expected amount for floating-rate queues) | | `status` | `pending` · `claimable` · `claimed` · `expired` | | `readyAt` | unix seconds the request becomes claimable (fixed-cooldown protocols only) | | `yieldProfile`, `denomination` | present when the vault is in the public-data lookup | Empty per-vault results are dropped. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `account` | query | string | yes | 0x-prefixed holder address. | | `vaults` | query | string | no | Optional CSV of extra ERC-7540 vault addresses to probe with the generic async-redeem reader, in addition to the static registry. | **Response `200`** — Flat `requests[]` of pending withdrawal requests across all queued/cooldown vaults for `account`. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Data › General ### GET /v1/data/chains - operationId: `get-supported-chains` - docs: https://docs.1delta.io/1delta-api/get-supported-chains - tags: General Get supported chains Returns every supported chain with its id, display name and logo. Chain ids are decimal **strings**, not numbers. Also published as the `ChainId` schema so it can be code-generated. **Response `200`** — Supported chains | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of supported chains | | `data.items` | object[] | Supported chains, sorted ascending by numeric chainId. | | `data.items[].chainId` | string | Decimal EVM chain id, as a string. | | `data.items[].name` | string | Human-readable display name. Prefers the registry `shortName` (concise, e.g. "eth"); falls back to the long `name`, then to "Chain {id}". | | `data.items[].logoURI` | string | Absolute URL to the chain icon. Always populated; consumers should handle broken images gracefully. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": [ { "chainId": "1", "name": "eth", "logoURI": "https://raw.githubusercontent.com/1delta-DAO/chains/main/1.webp" } ] } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/health - operationId: `health-check` - docs: https://docs.1delta.io/1delta-api/health-check - tags: General Health check Returns service health status. **Response `200`** — Service health | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.latestHour` | string | Latest data generation hour | | `actions` | null | | **Example response** ```json { "success": true, "data": { "latestHour": "2026-01-01T00:00:00Z" } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/lender-ids - operationId: `get-lender-ids` - docs: https://docs.1delta.io/1delta-api/get-lender-ids - tags: General Get lender IDs Returns every supported protocol identifier as a flat array of strings. These are the values accepted by the `lender` query parameter and used as the first segment of a `marketUid`. Also published as the `LenderId` schema so it can be code-generated. **Response `200`** — Lender IDs | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | string[] | Sorted list of supported lender protocol identifiers. | | `actions` | null | | **Example response** ```json { "success": true, "data": [ "AAVE_V2", "AAVE_V3", "COMPOUND_V2", "COMPOUND_V3_USDC", "EULER_V2", "INIT", "LISTA", "MORPHO", "SPARK", "VENUS" ] } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/meta/lending/complete - operationId: `complete-lending-metadata` - docs: https://docs.1delta.io/1delta-api/complete-lending-metadata - tags: General Complete lending metadata Returns the full lending-protocol metadata bundle for the requested chains and lenders. This is the single source of truth for static lender/chain/market configuration consumed by the SDKs and the position-builder UI. **Response includes**, per `(chainId, lenderKey)`: - Supported markets and their underlying assets (address, symbol, decimals, asset group) - Per-market risk parameters (LTV, liquidation threshold, factor, mode/e-mode IDs) - Pool configuration IDs and which markets are eligible as collateral / borrowable per config - Protocol contract addresses (pool, oracle, IRM, composer wiring) Filter with `chainIds` and/or `lenders` to keep payloads small — both filters are AND-combined. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainIds` | query | string[] | no | Filter by chain IDs (repeatable) See the `ChainId` schema for the full set of supported chains. | | `lenders` | query | string[] | no | Filter by lender keys (repeatable) See the `LenderId` schema for the full set of accepted values. | **Response `200`** — Lending metadata | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.count` | integer | Number of entries in `items`. | | `data.items` | object | The result set for this response. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "count": 1, "items": {} } } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/data/rpcs - operationId: `get-rpc-endpoints-for-chains` - docs: https://docs.1delta.io/1delta-api/get-rpc-endpoints-for-chains - tags: General Get RPC endpoints for chains Returns RPC URLs for the requested chains. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chains` | query | string[] | yes | Chain IDs to fetch RPCs for (repeatable) | **Response `200`** — RPC endpoints for requested chains | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Chain ID to array of RPC URLs. Keys are chain IDs; values are arrays of RPC endpoint URLs. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `400`** — Validation error **Response `404`** — None of the requested chains exist in the data **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions ## Actions › Index ### GET /v1/actions - operationId: `list-action-endpoints` - docs: https://docs.1delta.io/1delta-api/list-action-endpoints - tags: Index List action endpoints Returns a flat directory of every action endpoint, grouped by category (`lending`, `loop`, `swap`, `allocate`). Useful for client-side discovery and link generation. **Response `200`** — Endpoint listing | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `actions` | null | | **Example response** ```json { "success": true, "data": {} } ``` **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Lending (Actions) ### GET /v1/actions/lending/borrow - operationId: `lending-borrow` - docs: https://docs.1delta.io/1delta-api/lending-borrow - tags: Lending (Actions) Borrow Build calldata for borrowing from a lending pool. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics. **Lista DAO fixed-term (brokered) markets:** when the market is brokered (its public data has a non-empty `terms[]` rate card and `flags.variableBorrowDisabled === true`), pass `termId` to open a fixed-rate, fixed-term loan at the chosen term. Omitting `termId` on a brokered market opens the flexible (variable) position — direct mode only, since the broker has no on-behalf flex-borrow overload for the composer path. **Morpho Midnight order-book markets (`MORPHO_MIDNIGHT_`):** borrowing = **TAKING** the bid side of the book — this endpoint fills the `offers` returned by [`/v1/data/lending/latest?includeOffers=true`](/1delta-api/lending-latest), best-first. Borrowing is fixed-rate / fixed-maturity but has no `termId` (a single calendar maturity per market). To post your own limit offer instead (MAKE), use [`/v1/actions/midnight/make`](/1delta-api/midnight-make). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) | | `termId` | query | integer | no | **Lista DAO fixed-term (brokered) markets only.** Selects a fixed-rate term from the market's `terms[]` rate card (the `termId` of the chosen entry). A market is brokered when its public data carries a non-empty `terms[]` array and `flags.variableBorrowDisabled === true`; the broker contract is the mandatory gateway for the debt side. When `termId` is supplied the borrow opens a fixed-term loan at that term; when it is omitted on a brokered market the borrow falls back to the flexible (variable) position (direct mode only — the composer/proxy path has no on-behalf flex-borrow and requires a term). Ignored for non-brokered lenders. | | `receiveAsset` | query | string | no | Asset to receive. Use the zero address to receive native ETH on lenders that allow native-debt borrows (e.g. Init Capital, Fluid native-debt vaults). Proxy mode: defaults to market asset. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Response `200`** — Transaction calldata and approvals for borrow | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/lending/borrow - operationId: `borrow-simulate` - docs: https://docs.1delta.io/1delta-api/borrow-simulate - tags: Lending (Actions) Borrow (simulate) Build calldata for borrowing from a lending pool and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) | | `termId` | query | integer | no | **Lista DAO fixed-term (brokered) markets only.** Selects a fixed-rate term from the market's `terms[]` rate card (the `termId` of the chosen entry). A market is brokered when its public data carries a non-empty `terms[]` array and `flags.variableBorrowDisabled === true`; the broker contract is the mandatory gateway for the debt side. When `termId` is supplied the borrow opens a fixed-term loan at that term; when it is omitted on a brokered market the borrow falls back to the flexible (variable) position (direct mode only — the composer/proxy path has no on-behalf flex-borrow and requires a term). Ignored for non-brokered lenders. | | `receiveAsset` | query | string | no | Asset to receive. Use the zero address to receive native ETH on lenders that allow native-debt borrows (e.g. Init Capital, Fluid native-debt vaults). Proxy mode: defaults to market asset. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Transaction calldata with post-trade simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Simulation results including projected health factor and borrow capacity | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/deposit - operationId: `lending-deposit` - docs: https://docs.1delta.io/1delta-api/lending-deposit - tags: Lending (Actions) Deposit Build calldata for depositing into a lending pool. Use `mode=direct` (default) for raw protocol interaction or `mode=proxy` for 1delta composer. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics. **Morpho Midnight order-book markets (`MORPHO_MIDNIGHT_`):** depositing = **lending** = **TAKING** the ask side of the book — this endpoint fills the `lendOffers` returned by [`/v1/data/lending/latest?includeOffers=true`](/1delta-api/lending-latest), best-first. To post your own limit offer instead (MAKE), use [`/v1/actions/midnight/make`](/1delta-api/midnight-make). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `payAsset` | query | string | no | Asset to pay with. Use the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Response `200`** — Transaction calldata and approvals for deposit | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/lending/deposit - operationId: `deposit-simulate` - docs: https://docs.1delta.io/1delta-api/deposit-simulate - tags: Lending (Actions) Deposit (simulate) Build calldata for depositing into a lending pool and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `payAsset` | query | string | no | Asset to pay with. Use the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Transaction calldata with post-trade simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Simulation results including projected health factor and borrow capacity | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/enable-collateral - operationId: `enable-disable-collateral` - docs: https://docs.1delta.io/1delta-api/enable-disable-collateral - tags: Lending (Actions) Enable/disable collateral Build calldata for toggling an asset as collateral. Supported on lenders with explicit collateral toggles (Aave V2/V3, Compound V2 via `enterMarkets`/`exitMarket`); other lenders return a 400. Identify the market via `marketUid` (format: `lender:chainId:address`). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave) or cToken (CompoundV2). | | `enabled` | query | boolean | yes | true to enable, false to disable | **Response `200`** — Transaction calldata | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Response from direct-mode lending operations (deposit, withdraw, borrow, repay). | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/mode - operationId: `switch-mode` - docs: https://docs.1delta.io/1delta-api/switch-mode - tags: Lending (Actions) Switch mode Build calldata for switching the active risk-category ("mode") on a lender that supports it (e.g. Aave V3 e-mode). The "mode" terminology is the protocol-agnostic generalization of Aave V3's "e-mode" (efficiency mode); other lenders expose analogous category mechanisms. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | Protocol identifier See the `LenderId` schema for the full set of accepted values. | | `mode` | query | integer | yes | Target mode category ID | **Response `200`** — Transaction calldata | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Response from direct-mode lending operations (deposit, withdraw, borrow, repay). | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/repay - operationId: `lending-repay` - docs: https://docs.1delta.io/1delta-api/lending-repay - tags: Lending (Actions) Repay Build calldata for repaying a loan. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics. When on-chain debt data is available and `amount` covers the full debt, the API uses protocol-level max-repay mechanisms automatically. If `isAll=true` but `amount` is less than the debt, the API falls back to a partial repay to avoid reverts. **Lista DAO fixed-term (brokered) markets:** pass `loanId` to target a specific loan (use the per-loan `loanId` from the user-positions response, or the `type(uint128).max` sentinel for the flexible/dynamic position). The broker repays interest-first plus an early-repayment penalty on not-yet-matured fixed loans and refunds any excess, so to fully close a loan fund `outstanding + accruedInterest + earlyRepayPenalty` from the per-loan `term`. **Morpho Midnight fixed-term markets (`MORPHO_MIDNIGHT_`) — repaying to avoid liquidation.** A Midnight loan is **zero-coupon and fixed-maturity**: you owe a *static face value* — the position's `debt` in loan-token units — repaid **1:1**, which does **not** grow over time. So the amount to repay is fixed and known up front (the continuous + settlement fees accrue on the *lender's* side and are **never** added to your debt), and there is **no early-repayment penalty** (unlike Lista) — you may repay any time before maturity at face value. A borrower faces **two** liquidation triggers; both are cleared by repaying: - **Before maturity — health (LTV) based.** As with any collateralised loan, if the collateral's oracle value falls enough to breach the market's LLTV, the position can be liquidated. Keep an LTV buffer, add collateral, or repay down. - **At/after maturity — default.** The fixed `maturity` (surfaced on `params.market.maturity`) is a **hard deadline**. Once it passes, an unrepaid loan is **in default and can be liquidated regardless of health or LTV** — being past-due is itself the trigger. This is the Midnight-specific risk to watch: mark the maturity date and fully repay **before** it, even if the position is comfortably collateralised. **Repay exactly the debt.** Over-repaying **reverts** on-chain (there is no over-repay buffer — do **not** pad the `amount`, and `isAll` does not auto-size here), while under-repaying leaves a dust position that stays open and therefore still liquidatable after maturity. Set `amount` to the position's current `debt` (loan-token units) from `/v1/data/lending/user-positions` and approve exactly that to the Midnight core. To **fully close and reclaim collateral**, repay the debt and then withdraw the collateral via [`/v1/actions/lending/withdraw`](/1delta-api/lending-withdraw) — collateral cannot be freed while any debt remains. **Teller markets (`TELLER_`):** pass `posId` = the `bidId` to repay (from the user-positions `term.loanId`). A **full** repay (`isAll`, or an `amount` ≥ the amount owed) uses `repayLoanFull` which repays principal + interest **and releases ALL the bid's collateral** — Teller has no keep-collateral partial close. A **partial** repay (`amount` < owed) uses `repayLoan` and keeps the collateral escrowed. ⚠ Liquidation is TIME-based and **aggressive**: after the term you have only a **short grace window** (`params.market.teller.paymentDefaultDuration`, as low as 5 min) to roll over or repay — miss it and the loan DEFAULTS, and a liquidator can seize your **ENTIRE collateral** (not just the amount owed). Repay or roll over **before** the deadline; there is no price buffer. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `isAll` | query | boolean | no | Withdraw/repay full balance. When on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode: - If `amount` covers the full position the action is treated as "withdraw/repay all" regardless of this flag. - If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts. Without on-chain data, the flag is trusted as-is. | | `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) | | `loanId` | query | string | no | **Lista DAO fixed-term (brokered) markets only.** Identifies which loan to repay. Pass the `loanId` of the target loan from the user's positions (each per-loan position in the user-positions response carries `loanId` and a `term` object). To repay the flexible / dynamic position instead, pass the sentinel `340282366920938463463374607431768211455` (`type(uint128).max`). The broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed loans) and refunds any excess to the caller, so to fully close a loan fund `outstanding + accruedInterest + earlyRepayPenalty` (all on the per-loan `term`). Required on brokered repays; ignored for non-brokered lenders. | | `payAsset` | query | string | no | Asset to pay with. Use the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Response `200`** — Transaction calldata and approvals for repay | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/lending/repay - operationId: `repay-simulate` - docs: https://docs.1delta.io/1delta-api/repay-simulate - tags: Lending (Actions) Repay (simulate) Build calldata for repaying a loan and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `isAll` | query | boolean | no | Withdraw/repay full balance. When on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode: - If `amount` covers the full position the action is treated as "withdraw/repay all" regardless of this flag. - If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts. Without on-chain data, the flag is trusted as-is. | | `lendingMode` | query | string | no | Interest rate mode (0=NONE, 1=STABLE, 2=VARIABLE) | | `loanId` | query | string | no | **Lista DAO fixed-term (brokered) markets only.** Identifies which loan to repay. Pass the `loanId` of the target loan from the user's positions (each per-loan position in the user-positions response carries `loanId` and a `term` object). To repay the flexible / dynamic position instead, pass the sentinel `340282366920938463463374607431768211455` (`type(uint128).max`). The broker repays interest-first (plus an early-repayment penalty for not-yet-matured fixed loans) and refunds any excess to the caller, so to fully close a loan fund `outstanding + accruedInterest + earlyRepayPenalty` (all on the per-loan `term`). Required on brokered repays; ignored for non-brokered lenders. | | `payAsset` | query | string | no | Asset to pay with. Use the zero address to pay with native ETH on lenders whose vault accepts native debt repayment (e.g. Init Capital, Fluid native-debt vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Transaction calldata with post-trade simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Simulation results including projected health factor and borrow capacity | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/repay-with-atoken - operationId: `repay-with-atoken` - docs: https://docs.1delta.io/1delta-api/repay-with-atoken - tags: Lending (Actions) Repay with aToken Build calldata for repaying a loan using aTokens on Aave V3. Other lenders return a 400. Identify the market via `marketUid` (format: `lender:chainId:address`). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token. | | `amount` | query | string | yes | Amount in wei | | `lendingMode` | query | string | no | Interest rate mode (default: VARIABLE) | **Response `200`** — Transaction calldata | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Response from direct-mode lending operations (deposit, withdraw, borrow, repay). | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/simulate - operationId: `lending-simulate` - docs: https://docs.1delta.io/1delta-api/lending-simulate - tags: Lending (Actions) Simulate a base lending operation on-chain Build a base lending operation and **execute it against live chain state** before the user signs it. This is an EVM check, not the arithmetic projection that `simulate=true` adds to the other lending endpoints. The transaction is built by the very endpoint the client would call (`/v1/actions/lending/{action}`) and then replayed through an `eth_call` with storage overrides — so what is verified is the exact calldata that would be submitted, including the lender quirks that only surface on-chain. **Scope is the four single-grant operations.** `deposit` and `repay` override the pay token (funding balance and approval in one write); `withdraw` and `borrow` override the lender's own grant mapping (Aave credit delegation, Morpho `isAuthorized`, Comet `isAllowed`) so the action can be previewed *before* the user has signed that permission. Anything needing two grants at once — notably a leverage open that pulls fresh margin **and** borrows on behalf — cannot be previewed cold and is out of scope. **The override is optimistic.** `willSucceed: true` with `grantOverridden: true` means "this succeeds once the permission exists"; it is not evidence the permission exists. Keep gating the real grant on the permissions array. The `simulation` object is either: - `{ simulated: true, willSucceed, gasUsed, amountOut, returnData, revertReason?, block, grantOverridden }` - `{ simulated: false, reason, detail }` — where `reason` is one of `NO_TRANSACTION`, `MULTI_STEP`, `NATIVE_VALUE`, `MULTIPLE_GRANTS`, `GRANT_SLOT_UNKNOWN`, `SIMULATOR_UNAVAILABLE`. Note `amountOut` is a measured balance delta on `operator`, so it reads `0` for lenders with no receipt token (Morpho Blue and every CDP-shaped lender) — those return their own values in `returnData` instead. A simulator outage never fails the request: the calldata is still returned and remains valid. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `action` | query | string | yes | Which base operation to build and replay: `deposit`, `withdraw`, `borrow` or `repay`. | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `payAsset` | query | string | no | Asset to pay with. Use the zero address to pay with native ETH on lenders whose vault accepts native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native is forwarded as `msg.value` only when the lender supports it (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | | `block` | query | string | no | Block number or tag to simulate against. Defaults to `latest`. | **Response `200`** — Transaction calldata plus the on-chain execution result **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/lending/withdraw - operationId: `lending-withdraw` - docs: https://docs.1delta.io/1delta-api/lending-withdraw - tags: Lending (Actions) Withdraw Build calldata for withdrawing from a lending pool. Identify the market via `marketUid` (format: `lender:chainId:address`). Approval transactions are automatically filtered: if the user already has sufficient allowances, `permissions` (envelope) and `permissionTxns` (per-entry) will be empty. Pass `simulate=true` to include projected post-trade metrics. When on-chain deposit data is available and `amount` covers the full deposit balance, the API uses protocol-level max-withdraw mechanisms automatically (e.g. `maxUint256` or share-based redemption). If `isAll=true` but `amount` is less than the deposit balance, the API falls back to a partial withdrawal to avoid reverts. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `isAll` | query | boolean | no | Withdraw/repay full balance. When on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode: - If `amount` covers the full position the action is treated as "withdraw/repay all" regardless of this flag. - If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts. Without on-chain data, the flag is trusted as-is. | | `receiveAsset` | query | string | no | Asset to receive. Use the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Response `200`** — Transaction calldata and approvals for withdraw | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/lending/withdraw - operationId: `withdraw-simulate` - docs: https://docs.1delta.io/1delta-api/withdraw-simulate - tags: Lending (Actions) Withdraw (simulate) Build calldata for withdrawing from a lending pool and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Market identifier (`lender:chainId:address`). The address encodes the underlying token (Aave/Morpho/CompoundV3), cToken (CompoundV2), or pool (Init Capital). | | `amount` | query | string | yes | Amount in wei | | `mode` | query | "proxy" \| "direct" | no | Execution mode. proxy = 1delta composer, direct = raw protocol | | `operator` | query | string | no | Wallet address of the user executing the action | | `receiver` | query | string | no | Recipient of the lender position (deposit) or underlying tokens (borrow/withdraw). Defaults to `operator` when omitted. Custom-receiver support is per-lender. The API auto-selects the execution path: **Direct path supported** - Aave V2/V3 — `supply` / `withdraw` honor `to`. - Aave V4 — deposit via GiverPM `supplyOnBehalfOf`. Requires the GiverPM to be curated in `aave-v4-peripherals.json` with a name containing "giver". - Compound V3 — `supplyTo` / `withdrawTo`. - Morpho Blue & Lista DAO ERC-20 markets — Morpho `onBehalf`. - Euler V2 ERC-20 vaults — ERC-4626 `deposit(receiver)`. Collateral auto-enable is dropped for non-sub-account receivers. - Silo V2/V3 ERC-20 — `deposit(_, receiver, _)`. - Gearbox V3 passive-pool deposits — ERC-4626 `deposit(_, receiver)`. - Fluid borrow & withdraw — `operate(..., to_)` outflow slot. - Fluid **deposit to an existing NFT** when `accountId` is supplied — pure-deposit `operate()` calls bypass Fluid's owner auth gate, and the API folds a pre-flight `VaultFactory.ownerOf(nftId) == receiver` check into the merged multicall (rejects with 400 `INVALID_PARAM` on mismatch, `VALIDATION_FAILED` if the RPC can't confirm ownership). **Routes to composer (proxy) path** - Compound V2 family — direct `mint` is `msg.sender`-only. - Fluid **fresh-open deposits** — no `accountId` or `accountId=0`. The composer mints the new position NFT to itself, then transfers it to `receiver` via the encoder's `nftReceiver` slot. - Native-ETH vaults on Fluid (deposit / withdraw / repay) and the CompoundV2 family — the composer forwards `msg.value` to the vault's payable entrypoint. Other lenders' composer paths reject native asset and require wrapped-native as `payAsset`. **Direct-only branches that throw** - Gearbox V3 credit-side `addCollateral` — CA bound to operator. - Aave V4 native-gateway path — `supplyAsCollateralNative` has no recipient slot. **Unsupported in any single tx** - Init Capital — position NFT swept to operator. - Euler V2 / Silo V2/V3 native deposit paths — router/orchestrator credits msg.sender. - Fluid repay — on-chain primitive permits it, direct handler doesn't expose a receiver slot yet (routes to proxy as a conservative default). When the lender cannot honor a custom receiver on the direct path, `getTarget` falls back to `proxy` automatically. Forcing `mode=direct` on an unsupported path either throws (Gearbox credit-side, Aave V4 spoke, the explicit Silo router check) or silently credits the operator instead (Compound V2, Init, and Fluid fresh-open). | | `isAll` | query | boolean | no | Withdraw/repay full balance. When on-chain position data is available, the API compares `amount` against the actual balance to decide the effective mode: - If `amount` covers the full position the action is treated as "withdraw/repay all" regardless of this flag. - If `isAll` is true but `amount` is less than the position, the API falls back to a partial action with the provided `amount` to avoid on-chain reverts. Without on-chain data, the flag is trusted as-is. | | `receiveAsset` | query | string | no | Asset to receive. Use the zero address to receive native ETH on lenders whose vault returns native (e.g. Init Capital, Fluid native-ETH vaults, CompoundV2 `cETH` markets). Proxy mode: defaults to market asset. Native delivery is supported only when the lender does so on-chain (e.g. Fluid, CompoundV2); otherwise the composer rejects. | | `isShares` | query | boolean | no | Amount is in shares (direct mode) | | `accountId` | query | string | no | Per-position identifier. Lender-specific: - **Init Capital** — account ID, required for borrow/withdraw/repay. - **Euler V2** — sub-account index (0..255), defaults to 0. - **Gearbox V3** — credit-account address (alias: `creditAccount`). - **Fluid** — position NFT id. Omit or pass `0` to mint a new position; supply an existing nftId to act on an existing position. Required for borrow/withdraw/repay; for deposit it unlocks the direct path with a custom `receiver` (deposit lands on the receiver-owned NFT after pre-flight `ownerOf` validation). | | `slippage` | query | number | no | Slippage tolerance in **basis points** (`50` = 0.5%, `100` = 1%). Required whenever the action has to price something: - **Aggregator swap** — when `payAsset` / `receiveAsset` differs from the market's underlying, the currency conversion is routed through a DEX aggregator and this bounds that swap. - **Order-book take (Morpho Midnight)** — bounds the worst execution price accepted while filling offers. Ignored when neither applies (same-asset action on a pool lender). | | `simulate` | query | boolean | no | When true, the API fetches the user's on-chain balances and returns projected post-trade metrics in the `simulation` field. Default: false. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Transaction calldata with post-trade simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Simulation results including projected health factor and borrow capacity | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Loop (Actions) ### GET /v1/actions/loop/close - operationId: `close-margin-position` - docs: https://docs.1delta.io/1delta-api/close-margin-position - tags: Loop (Actions) Close margin position Close a leveraged position. Identify the collateral market with `marketUidIn` and debt market with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`). **Response `actions` fields (when `account` is provided):** - `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute. - `transactions`: Empty for close operations (no setup needed). - `permissions`: Lender withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first. **Lista DAO fixed-term (brokered) markets:** when `marketUidOut` is brokered, pass `loanId` to select which broker loan the repay leg pays down (or the `type(uint128).max` sentinel for the flexible position). The collateral withdraw leg is handled automatically (routed through the market's `collateralProvider` when set, e.g. slisBNB). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `amount` | query | string | yes | Amount in wei | | `tradeType` | query | 0 \| 1 | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) | | `irModeOut` | query | 0 \| 1 \| 2 | no | Interest rate mode for debt | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `isAll` | query | boolean | no | Repay full debt | | `loanId` | query | string | no | **Lista DAO fixed-term (brokered) debt markets only.** Identifies which loan the close repays on the loop's repay leg: the loan's `loanId` (broker posId) from the user-positions response, or the `type(uint128).max` sentinel (`340282366920938463463374607431768211455`) for the flexible/dynamic position. Required when `marketUidOut` is a brokered market; ignored otherwise. | | `accountId` | query | string | no | Account ID | **Response `200`** — Quote or full build response | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.lender` | string | Protocol identifier | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/loop/close - operationId: `close-position-simulate` - docs: https://docs.1delta.io/1delta-api/close-position-simulate - tags: Loop (Actions) Close position (simulate) Close a leveraged position and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `amount` | query | string | yes | Amount in wei | | `tradeType` | query | 0 \| 1 | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) | | `irModeOut` | query | 0 \| 1 \| 2 | no | Interest rate mode for debt | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `isAll` | query | boolean | no | Repay full debt | | `loanId` | query | string | no | **Lista DAO fixed-term (brokered) debt markets only.** Identifies which loan the close repays on the loop's repay leg: the loan's `loanId` (broker posId) from the user-positions response, or the `type(uint128).max` sentinel (`340282366920938463463374607431768211455`) for the flexible/dynamic position. Required when `marketUidOut` is a brokered market; ignored otherwise. | | `accountId` | query | string | no | Account ID | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Quote or full build with simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Quotes and simulation results | | `data.lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/loop/collateral-swap - operationId: `collateral-swap` - docs: https://docs.1delta.io/1delta-api/collateral-swap - tags: Loop (Actions) Collateral swap Swap collateral assets within a lending position. Identify the sell-side collateral market with `marketUidIn` and buy-side with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`). **Response `actions` fields (when `account` is provided):** - `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute. - `transactions`: Collateral enable (`enterMarkets`) for Compound V2 lenders. Empty otherwise. - `permissions`: Lender withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `amount` | query | string | yes | Amount in wei | | `tradeType` | query | 0 \| 1 | no | Trade type | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `isAll` | query | boolean | no | Swap full collateral balance | | `accountId` | query | string | no | Account ID | **Response `200`** — Quote or full build response | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.lender` | string | Protocol identifier | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/loop/collateral-swap - operationId: `collateral-swap-simulate` - docs: https://docs.1delta.io/1delta-api/collateral-swap-simulate - tags: Loop (Actions) Collateral swap (simulate) Swap collateral assets and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. For `isAll` trades, include `depositBalanceIn` (raw underlying balance string) in the body so the withdrawal approval is sized to the actual position. This field is accepted alongside or independently of the simulation fields. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `amount` | query | string | yes | Amount in wei | | `tradeType` | query | 0 \| 1 | no | Trade type | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `isAll` | query | boolean | no | Swap full collateral balance | | `accountId` | query | string | no | Account ID | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | | `depositBalanceIn` | string | no | Raw deposit balance of the input collateral asset in underlying units. Used for isAll to size the withdrawal approval correctly. | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ], "depositBalanceIn": "1000000000000000000" } ``` **Response `200`** — Quote or full build with simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Quotes and simulation results | | `data.lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/loop/debt-swap - operationId: `debt-swap` - docs: https://docs.1delta.io/1delta-api/debt-swap - tags: Loop (Actions) Debt swap Swap debt between different borrow positions. Identify the repay-side debt market with `marketUidIn` and borrow-side with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`). **Response `actions` fields (when `account` is provided):** - `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute. - `transactions`: Empty for debt-swap operations (no setup needed). - `permissions`: Lender borrow and withdrawal delegations (targeting the lending protocol contract). Only missing delegations are returned. Execute these first. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `amount` | query | string | yes | Amount in wei | | `tradeType` | query | 0 \| 1 | no | Trade type | | `irModeIn` | query | 0 \| 1 \| 2 | no | Interest rate mode for repaid debt | | `irModeOut` | query | 0 \| 1 \| 2 | no | Interest rate mode for new debt | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `isAll` | query | boolean | no | Repay full debt | | `accountId` | query | string | no | Account ID | **Response `200`** — Quote or full build response | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.lender` | string | Protocol identifier | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/loop/debt-swap - operationId: `debt-swap-simulate` - docs: https://docs.1delta.io/1delta-api/debt-swap-simulate - tags: Loop (Actions) Debt swap (simulate) Swap debt between borrow positions and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `amount` | query | string | yes | Amount in wei | | `tradeType` | query | 0 \| 1 | no | Trade type | | `irModeIn` | query | 0 \| 1 \| 2 | no | Interest rate mode for repaid debt | | `irModeOut` | query | 0 \| 1 \| 2 | no | Interest rate mode for new debt | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `isAll` | query | boolean | no | Repay full debt | | `accountId` | query | string | no | Account ID | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Quote or full build with simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Quotes and simulation results | | `data.lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/loop/leverage - operationId: `leverage-loop` - docs: https://docs.1delta.io/1delta-api/leverage-loop - tags: Loop (Actions) Leverage (loop) Open a leveraged position via borrow → swap → deposit. Identify the debt market with `marketUidIn` and collateral market with `marketUidOut`. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`). **Response `actions` fields (when `account` is provided):** - `alternatives`: DEX aggregator swap transactions sorted best-output-first. Pick one to execute. - `transactions`: Pre-trade setup — mode/e-mode switch (Aave V3) or collateral enable (Venus). Empty if not needed. - `permissions`: ERC20 approvals (targeting the composer contract) and lender borrow delegations (targeting the lending protocol contract). Only missing approvals are returned. Execute these first. **Lista DAO fixed-term (brokered) markets:** when `marketUidIn` is brokered, pass `termId` to open the loop's debt leg as a fixed-term broker loan. The collateral deposit leg is handled automatically (routed through the market's `collateralProvider` when set, e.g. slisBNB). Closing such a loop requires the loan's `loanId` on `/v1/actions/loop/close`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `debtAmount` | query | string | yes | Debt amount in wei | | `payAsset` | query | string | no | Asset to pay with (optional zap-in asset) | | `payAmount` | query | string | no | Pay amount in wei | | `leverage` | query | number | no | Target leverage multiplier | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `borrowMode` | query | 0 \| 1 \| 2 | no | Borrow mode (0=NONE, 1=STABLE, 2=VARIABLE) | | `termId` | query | integer | no | **Lista DAO fixed-term (brokered) debt markets only.** Selects the fixed term to borrow for the loop's debt leg, from the debt market's `terms[]` rate card (the `MarketTerm.termId`). Required when `marketUidIn` is a brokered market — the borrow leg routes through the broker; ignored otherwise. | | `accountId` | query | string | no | Account ID (Init Capital) | | `selectedMode` | query | integer | no | Position mode for new positions (Init Capital) | **Response `200`** — Quote or full build response | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.lender` | string | Protocol identifier | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/loop/leverage - operationId: `leverage-loop-simulate` - docs: https://docs.1delta.io/1delta-api/leverage-loop-simulate - tags: Loop (Actions) Leverage loop (simulate) Open a leveraged position and simulate post-trade state. Same parameters as GET. Optionally send a JSON body with current portfolio state (`balanceData`, `aprData`, `positions`) to receive projected post-trade metrics in the `simulation` field — if omitted, the API fetches balances on-chain automatically. Use the data returned by the user-positions endpoint directly — always include `positions` for accurate health-factor and borrow-capacity projections. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidIn` | query | string | yes | Market identifier for input side (`lender:chainId:address`). | | `marketUidOut` | query | string | yes | Market identifier for output side (`lender:chainId:address`). | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `debtAmount` | query | string | yes | Debt amount in wei | | `payAsset` | query | string | no | Asset to pay with (optional zap-in asset) | | `payAmount` | query | string | no | Pay amount in wei | | `leverage` | query | number | no | Target leverage multiplier | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | | `borrowMode` | query | 0 \| 1 \| 2 | no | Borrow mode (0=NONE, 1=STABLE, 2=VARIABLE) | | `termId` | query | integer | no | **Lista DAO fixed-term (brokered) debt markets only.** Selects the fixed term to borrow for the loop's debt leg, from the debt market's `terms[]` rate card (the `MarketTerm.termId`). Required when `marketUidIn` is a brokered market — the borrow leg routes through the broker; ignored otherwise. | | `accountId` | query | string | no | Account ID (Init Capital) | | `selectedMode` | query | integer | no | Position mode for new positions (Init Capital) | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `balanceData` | object | yes | Aggregated balance data for a sub-account. | | `balanceData.deposits` | number | no | Total deposits in USD | | `balanceData.debt` | number | no | Total debt in USD | | `balanceData.adjustedDebt` | number | no | Debt adjusted for borrow factors | | `balanceData.collateral` | number | no | Collateral value in USD | | `balanceData.collateralAllActive` | number | no | Collateral if all assets were enabled | | `balanceData.borrowDiscountedCollateral` | number | no | Collateral discounted by borrow factors | | `balanceData.borrowDiscountedCollateralAllActive` | number | no | Discounted collateral if all enabled | | `balanceData.nav` | number | no | Net asset value (deposits - debt) | | `balanceData.deposits24h` | number | no | Deposits 24h ago (for change calculation) | | `balanceData.debt24h` | number | no | Debt 24h ago | | `balanceData.nav24h` | number | no | NAV 24h ago | | `balanceData.rewards` | object[] | no | Pending reward token claims. Each entry represents a single reward program. | | `balanceData.rewards[].asset` | string | no | Reward token contract address | | `balanceData.rewards[].totalRewards` | number | no | Total accumulated rewards (token units) | | `balanceData.rewards[].claimableRewards` | number | no | Immediately claimable rewards (token units) | | `aprData` | object | yes | APR breakdown for a sub-account. | | `aprData.apr` | number | no | Net APR (deposit - borrow) | | `aprData.depositApr` | number | no | Weighted deposit APR | | `aprData.borrowApr` | number | no | Weighted borrow APR | | `aprData.rewardApr` | number | no | Total reward APR | | `aprData.rewardDepositApr` | number | no | Reward APR on deposits | | `aprData.rewardBorrowApr` | number | no | Reward APR on borrows | | `aprData.intrinsicApr` | number | no | Intrinsic yield APR (e.g., stETH staking) | | `aprData.intrinsicDepositApr` | number | no | Intrinsic yield APR portion from deposits | | `aprData.intrinsicBorrowApr` | number | no | Intrinsic yield APR portion from borrows | | `aprData.rewards` | object | no | Per-reward-token APR breakdown. Keys are reward token addresses. | | `modeId` | string | no | Mode/config key from `userConfig.selectedMode` (defaults to "0") | | `positions` | object[] | no | Current lending positions from the matching sub-account's `positions` array. The full `LendingPosition` objects returned by user-positions are accepted — only the fields in `SimulationPosition` are used. Always include this for accurate health-factor and borrow-capacity projections. | | `positions[].marketUid` | string | yes | Unique market identifier (format: `{lender}:{chainId}:{address}`) | | `positions[].depositsUSD` | number | yes | Deposit amount in USD | | `positions[].debtUSD` | number | yes | Variable debt in USD | | `positions[].debtStableUSD` | number | yes | Stable debt in USD | | `positions[].collateralEnabled` | boolean | yes | Whether this asset is enabled as collateral | **Example request body** ```json { "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} }, "modeId": "0", "positions": [ { "marketUid": "AAVE_V3:1:0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", "depositsUSD": 5000, "debtUSD": 2000, "debtStableUSD": 0, "collateralEnabled": true } ] } ``` **Response `200`** — Quote or full build with simulation | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Quotes and simulation results | | `data.lender` | string | Protocol identifier. See the `LenderId` schema. | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.simulation` | object | Projected post-trade metrics, or null if simulation failed | | `data.simulation.pre` | object | Portfolio state before the trade. | | `data.simulation.pre.healthFactor` | number | Health factor before the trade (null-safe: capped at 1e18 when no debt) | | `data.simulation.pre.borrowCapacity` | number | Borrow capacity (USD) before the trade | | `data.simulation.post` | object | Projected portfolio state after the trade. | | `data.simulation.post.healthFactor` | number | Projected health factor after the trade | | `data.simulation.post.borrowCapacity` | number | Projected borrow capacity (USD) after the trade | | `data.simulation.post.balanceData` | object | Aggregated balance data for a sub-account. | | `data.simulation.post.balanceData.deposits` | number | Total deposits in USD | | `data.simulation.post.balanceData.debt` | number | Total debt in USD | | `data.simulation.post.balanceData.adjustedDebt` | number | Debt adjusted for borrow factors | | `data.simulation.post.balanceData.collateral` | number | Collateral value in USD | | `data.simulation.post.balanceData.collateralAllActive` | number | Collateral if all assets were enabled | | `data.simulation.post.balanceData.borrowDiscountedCollateral` | number | Collateral discounted by borrow factors | | `data.simulation.post.balanceData.borrowDiscountedCollateralAllActive` | number | Discounted collateral if all enabled | | `data.simulation.post.balanceData.nav` | number | Net asset value (deposits - debt) | | `data.simulation.post.balanceData.deposits24h` | number | Deposits 24h ago (for change calculation) | | `data.simulation.post.balanceData.debt24h` | number | Debt 24h ago | | `data.simulation.post.balanceData.nav24h` | number | NAV 24h ago | | `data.simulation.post.balanceData.rewards` | object[] | Pending reward token claims. Each entry represents a single reward program. | | `data.simulation.post.aprData` | object | APR breakdown for a sub-account. | | `data.simulation.post.aprData.apr` | number | Net APR (deposit - borrow) | | `data.simulation.post.aprData.depositApr` | number | Weighted deposit APR | | `data.simulation.post.aprData.borrowApr` | number | Weighted borrow APR | | `data.simulation.post.aprData.rewardApr` | number | Total reward APR | | `data.simulation.post.aprData.rewardDepositApr` | number | Reward APR on deposits | | `data.simulation.post.aprData.rewardBorrowApr` | number | Reward APR on borrows | | `data.simulation.post.aprData.intrinsicApr` | number | Intrinsic yield APR (e.g., stETH staking) | | `data.simulation.post.aprData.intrinsicDepositApr` | number | Intrinsic yield APR portion from deposits | | `data.simulation.post.aprData.intrinsicBorrowApr` | number | Intrinsic yield APR portion from borrows | | `data.simulation.post.aprData.rewards` | object | Per-reward-token APR breakdown. Keys are reward token addresses. | | `data.simulationError` | string | Error message if simulation failed | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ], "simulation": { "pre": { "healthFactor": 1.85, "borrowCapacity": 3000 }, "post": { "healthFactor": 2.1, "borrowCapacity": 3500, "balanceData": { "deposits": 10000.5, "debt": 5000.25, "adjustedDebt": 5500, "collateral": 9000, "collateralAllActive": 10000.5, "borrowDiscountedCollateral": 8000, "borrowDiscountedCollateralAllActive": 9000, "nav": 5000.25, "deposits24h": 9800, "debt24h": 4900, "nav24h": 4900, "rewards": [ { "asset": "0xc00e94Cb662C3520282E6f5717214004A7f26888", "totalRewards": 12.5, "claimableRewards": 12.5 } ] }, "aprData": { "apr": 2.5, "depositApr": 3.5, "borrowApr": 5.2, "rewardApr": 1.2, "rewardDepositApr": 0.8, "rewardBorrowApr": 0.4, "intrinsicApr": 0, "intrinsicDepositApr": 0, "intrinsicBorrowApr": 0, "rewards": {} } } }, "simulationError": "string" }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/loop/migrate - operationId: `loop-migrate` - docs: https://docs.1delta.io/1delta-api/loop-migrate - tags: Loop (Actions) Migrate position (cross-lender) Move a whole debt + collateral position from one lender to another in a single flash-loan transaction, optionally converting ONE leg (collateral OR debt) via an aggregator swap. Flow (no conversion): flash the debt → repay the source → withdraw the source collateral → deposit it to the target → borrow the debt from the target → repay the flash. Same-lender / different-market moves (e.g. Morpho market A→B, Aave V4 reserve→reserve) are supported. **Supported sources & targets:** Aave V2/V3, Aave V4, Compound V3, Morpho Blue / Lista, Fluid (an existing position via NFT-custody, OR a brand-new position — see below), Gearbox V3 (existing credit account as source; a fresh credit account is opened in-callback as target), Euler V2 (accountId 0; collateral-share transfer through the call forwarder). **Not supported:** Dolomite (either side), Euler as a TARGET, non-Venus Compound V2 as a target, both legs converting at once, Fluid↔Fluid. > **Fluid target — existing vs fresh:** pass the position's NFT id in `accountId` to migrate INTO an existing Fluid position (delivered via the VaultFactory NFT-custody flow). Omit it (or pass 0) to open a **brand-new** Fluid position: the migrate emits a single dual-axis Fluid `operate` that supplies the withdrawn collateral, borrows the debt, and mints the new position NFT straight to you — no NFT custody, no target-side consent, and the transaction targets the composer (`deltaCompose`) normally. > **Native ↔ wrapped-native (wrap conversion):** a native debt — e.g. a Venus `vBNB` borrow — migrates into a target lender's **wrapped-native** debt market (WBNB). On-behalf borrowing cannot be delegated for the native asset, so the target MUST be the wrapped form; a native TARGET debt is rejected. The builder flashes the wrapped form, unwraps it to repay the native source, and borrows the wrapped form on the target — no aggregator needed. Compound V2 / Venus can be a migration **source** but never a **target** (no borrow delegation). The **collateral** leg wraps BOTH ways — a native source collateral (e.g. Fluid's ETH slot) is wrapped to WETH before the target deposit, and a wrapped source collateral is unwrapped for a native-collateral target — again with no aggregator. Native collateral is only reachable as such a wrap pair; native → an unrelated ERC20 target is rejected. > **Lista DAO markets:** two per-market extras decide the shape. A **brokered** market (non-zero `broker`) routes its debt leg through the fixed-term broker — pass `loanId` when it is the SOURCE (which loan to repay) and `termId` when it is the TARGET (which term to open); the target has no default because the broker's flexible borrow has no on-behalf variant. A market with a **`collateralProvider`** (e.g. the slisBNB markets) routes its collateral leg through that provider, which exposes no `position()` getter — so a provider-gated SOURCE cannot use the withdraw-all sentinel and is sized from your live collateral balance instead (read server-side; pass `collateralAmount` to override). > **Asset conversion (swap leg):** ONE leg may change asset via an aggregator swap — either the collateral (`marketUidTargetCollateral` uses a different underlying) or the debt (`marketUidTargetDebt`), not both. The route fetches the aggregator quote server-side and bakes the trade into the flash callback. A **collateral** swap is EXACT_INPUT of the withdrawn collateral → provide a concrete `collateralAmount` (or `collateralAmountHint`) so the swap input lines up. A **debt** swap is EXACT_OUTPUT (buy exactly the source debt to repay, selling the flashed target debt). Tune the swap tolerance with `slippage`. **Euler as a source** still needs an off-chain eVault share-balance read via the `prepareMigrate` SDK. Omit `account` for quote-only (returns `data.quotes` with price deltas). Include `account` to build full transaction calldata (populates `actions` with `alternatives`, `transactions`, and `permissions`). **Setup transactions (`actions.permissions`):** returned only for the consents actually missing, to be executed BEFORE the migrate. These vary by lender pair — e.g. the source collateral withdrawal approval; Aave V4 Giver/Taker/Config Position-Manager authorizations + per-reserve borrow allowance + collateral-enable grant; Morpho `setAuthorization`; a Gearbox V3 SOURCE's `setBotPermissions` grant on the credit account; Euler collateral eVault share approval to the composer. Fluid legs need no separate permission (NFT custody — or, for a fresh open, the composer opening on your behalf — IS the authorization). **Delivery:** the migrate transaction targets the composer (`deltaCompose`) normally, OR the Fluid `VaultFactory.safeTransferFrom` when a Fluid leg requires NFT custody — `actions.transactions[0].to` reflects this. **`data.result` (resulting position):** a summary for the UI — `from`/`to` lenders with their collateral + debt assets (address/symbol/decimals/logo), the new position amounts (`to.collateral.amount`/`amountUsd`, `to.debt.amount`/`amountUsd`), `netUsd`, `leverage`, `apr: { deposit, borrow, net }` and `healthFactor`. The rates, liquidation threshold, decimals and prices behind those are **resolved server-side** from the target markets — the corresponding query params are overrides only. USD/symbol fields are best-effort (omitted when price/token metadata is unavailable). `to.collateral.amount` is present when the withdraw was sized server-side (Aave source) or passed explicitly. **Finding a target:** [`GET /v1/actions/loop/migrate/targets`](/1delta-api/loop-migrate-targets) returns the ranked destinations this endpoint accepts for a given position — support matrix, native ⇄ wrapped equivalence, un-openable fixed-term books and borrow liquidity all applied server-side. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidSourceCollateral` | query | string | yes | Source collateral market (`lender:chainId:address`). The position being moved FROM. | | `marketUidSourceDebt` | query | string | yes | Source debt market (`lender:chainId:address`). | | `marketUidTargetCollateral` | query | string | yes | Target collateral market (`lender:chainId:address`). The position being moved TO. May be a different lender and/or a different asset (collateral conversion). | | `marketUidTargetDebt` | query | string | yes | Target debt market (`lender:chainId:address`). May be a different lender and/or a different asset (debt conversion). | | `debtAmount` | query | string | yes | Live debt to migrate, in the debt asset’s wei. For a debt conversion this is the NEW-debt (flash/borrow) amount instead. The flash is sized a small buffer above this so the source repay clears in full (a residual would make the full collateral withdrawal revert). | | `account` | query | string | no | Account address. Include to build the transaction + permission setup; omit for a quote-only response. | | `isMaxIn` | query | boolean | no | Withdraw the full collateral balance from the source (default true for a same-asset move). Set false + `collateralAmount` for an exact-amount conversion so the swap input lines up. | | `collateralAmount` | query | string | no | Exact source collateral to withdraw, in wei. Required (with `isMaxIn=false`) for a collateral conversion so the withdrawn amount matches the swap input. | | `accountId` | query | string | no | Per-position id where the lender needs one: an existing Fluid NFT id (omit or 0 opens a BRAND-NEW Fluid position), Euler sub-account index (must be 0 — sub-accounts unsupported). Defaults to 0. | | `loanId` | query | string | no | Lista fixed-term broker SOURCE only: the loan `posId` to repay, or `type(uint128).max` for the flex/dynamic position. Required when the source debt market is brokered; ignored otherwise. The target borrow is keyed by term, not loanId. | | `termId` | query | integer | no | Lista fixed-term broker TARGET only: which term the migrated debt opens at. REQUIRED when the target debt market is brokered — the broker exposes no on-behalf flexible borrow, so there is no default; ignored otherwise. Mirrors the `termId` on /v1/actions/loop/open. | | `irModeFrom` | query | 0 \| 1 \| 2 | no | Aave interest mode of the source debt (repay). 2 = variable. | | `irModeTo` | query | 0 \| 1 \| 2 | no | Aave interest mode of the target debt (borrow). 2 = variable. | | `slippage` | query | string | no | Swap-leg slippage tolerance as a FRACTION (`0.005` = 0.5%). Only used when a leg is converted via an aggregator swap; ignored for same-asset / wrap moves. Defaults to 0.5%. ⚠ **This endpoint is the exception.** Every other `slippage` in this API is in BASIS POINTS (`50` = 0.5%) — migrate takes a fraction, which is 100× smaller for the same tolerance. Sending `50` here would ask for 5000% slippage. | | `eModeTo` | query | string | no | Risk-config category to read the TARGET collateral's liquidation threshold from (Aave-style e-modes publish one config per category). Defaults to `0` (no e-mode). Display only — it does not change the built transaction. | | `collateralDecimals` | query | integer | no | **Override.** Target collateral decimals. Resolved server-side; pass only to overrule the published metadata (e.g. a market whose token-list decimals are known-wrong, which would mis-scale the `data.result` USD values). Never affects the on-chain amounts. | | `debtDecimals` | query | integer | no | **Override.** TARGET debt decimals — the swap target’s when the debt converts, else the source’s. Resolved server-side; see `collateralDecimals`. | | `sourceDebtDecimals` | query | integer | no | **Override.** SOURCE debt decimals, for the `from`-leg display when the debt is converted. Resolved server-side; defaults to `debtDecimals`. | | `depositApr` | query | string | no | **Override.** Target collateral deposit APR as a FRACTION (0.05 = 5%), intrinsic yield folded in. Resolved server-side and reported as `data.result.apr.deposit`. | | `borrowApr` | query | string | no | **Override.** Target debt borrow APR as a FRACTION (0.05 = 5%), intrinsic yield folded in — for a fixed-term target this is the term rate, not the 0% variable rate. Resolved server-side. | | `liqThreshold` | query | string | no | **Override.** Target collateral liquidation threshold as a FRACTION (0.85 = 85%), driving `data.result.healthFactor` (= collateralUsd · liqThreshold / debtUsd; < 1 ⇒ liquidatable). Resolved server-side from the target market’s risk config — see `eModeTo`. | | `collateralPriceUsd` | query | string | no | **Override.** USD price of the TARGET collateral for the display conversion. Resolved server-side, preferring the market’s own ORACLE price (what the lender liquidates against). | | `debtPriceUsd` | query | string | no | **Override.** USD price of the TARGET debt for the display conversion. Resolved server-side; see `collateralPriceUsd`. | **Response `200`** — Quote or full build response | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.lender` | string | Protocol identifier | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].deltas` | object | | | `data.quotes[].deltas.aggregator` | string | Aggregator source | | `data.quotes[].deltas.tradeInput` | number | Trade input amount | | `data.quotes[].deltas.tradeOutput` | number | Trade output amount | | `data.quotes[].deltas.deltas` | object | Balance deltas | | `data.quotes[].rateImpact` | object[] | Projected interest-rate impact per market for THIS quote (its own trade amounts). Omitted if IRM data is unavailable. | | `data.quotes[].rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.quotes[].rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].utilization.current` | number | Current value | | `data.quotes[].rateImpact[].utilization.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].borrowRate.current` | number | Current value | | `data.quotes[].rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.quotes[].rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.quotes[].rateImpact[].depositRate.current` | number | Current value | | `data.quotes[].rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "lender": "AAVE_V3", "quotes": [ { "deltas": { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1, "deltas": {} }, "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/loop/migrate/targets - operationId: `loop-migrate-targets` - docs: https://docs.1delta.io/1delta-api/loop-migrate-targets - tags: Loop (Actions) Migration targets for a position Which markets can this position migrate to? The discovery companion to [`/v1/actions/loop/migrate`](/1delta-api/loop-migrate) — it returns the ranked set of destinations that endpoint would actually accept, so a client never encodes protocol knowledge to build that list. Give it the two marketUids of an existing position (and, ideally, its size) and it does everything a caller would otherwise hand-roll: - **Native ⇄ wrapped-native equivalence.** Some lenders key a market to the native asset (Fluid ETH vaults), others to the wrapped ERC20 (Aave WETH); a migrate bridges them by wrapping. Selection is by shared `assetGroup`, so both forms surface in BOTH directions on every chain — no per-chain WETH table anywhere in the client. - **The migrate support matrix.** Lenders that cannot be a target are dropped (Dolomite, Euler, Curvance, LlamaLend and non-Venus Compound V2 forks today). This is the same code path `/migrate` validates with, so the list cannot drift out of sync with what builds. - **The native-debt rule.** On-behalf borrowing cannot be delegated for the native asset, so native-debt markets are dropped unless the move is a wrap conversion into Fluid. - **Un-openable fixed-term books.** An order-book lender (Morpho Midnight) reports a 0% variable rate and no terms in the pair feed whether its book is rich or empty. Each fixed-term candidate's real borrow term is resolved and the ones that cannot be opened are dropped — 10 of 12 Midnight borrow legs on Base at time of writing. Survivors get `termsShort` back-filled with the true rate + maturity. - **Borrow liquidity at this position's size**, applied BEFORE truncation (a client-side filter after paging silently loses real destinations to rows it then discards). **Rows** come back in the `/v1/data/lending/pairs/optimize` shape, so an existing pair normaliser keeps working, plus a `migrate` block per row: ```jsonc "migrate": { "healthFactor": 1.87, // collateralUsd · liquidationThreshold / debtUsd on THIS target "netApr": 0.041, // equity-weighted earn − pay for THIS position (not max-leverage aprTotal) "depositApr": 0.031, // effective rates behind netApr (intrinsic yield folded in) "borrowApr": 0.058, "borrowLiquidityUsd": 6470141, "sufficientLiquidity": true, "maturity": 1787929200, // fixed-term targets only "termHeadline": "Fixed 4.01% until 28 Aug 2026" } ``` The envelope also carries `source` (the resolved position with its USD values), `hiddenForLiquidity`, and `excluded` — one entry per distinct drop reason, so a UI can explain a short list instead of silently showing one. > **Native-asset convention.** Every 1delta data payload spells the native asset as the ZERO ADDRESS. `0xEeee…EEeE` is an encoding-layer sentinel: it is accepted on action inputs and normalised away, but it is never served and never matches a data filter. A client filtering markets by `0xEeee…` silently gets no rows. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUidSourceCollateral` | query | string | yes | Collateral market of the position being moved (`lender:chainId:address`). | | `marketUidSourceDebt` | query | string | yes | Debt market of the position being moved (`lender:chainId:address`). Must be on the same chain as the collateral. | | `debtAmount` | query | string | no | Live debt of the position, in the debt asset’s wei. Supply it to filter out targets that cannot fund the whole borrow, to price each row AT this notional, and to get a resulting health factor per target. | | `collateralAmount` | query | string | no | Live collateral of the position, in the collateral asset’s wei. Needed (with `debtAmount`) for the per-target health factor. | | `convertLeg` | query | "collateral" \| "debt" | no | Ask for targets that CONVERT one leg via an aggregator swap. With `convertTo` omitted the response carries `convertibleAssets` — the assets that leg can convert into while still pairing with the fixed leg — so a picker can be populated without knowing which pairings exist. | | `convertTo` | query | string | no | Target asset address for the converted leg. Pins that leg to exactly this asset; the fixed leg keeps the source asset (native ⇄ wrapped-native included). | | `count` | query | integer | no | Maximum ranked targets to return (default 50). | | `includeIlliquid` | query | boolean | no | Keep targets whose borrow liquidity cannot fund `debtAmount` (they sort last and carry `migrate.sufficientLiquidity: false`). Default false — they are counted in `hiddenForLiquidity` instead. | | `maxRiskScore` | query | integer | no | Risk cap for candidate markets. Defaults to `100`, i.e. no cap: a migrate MOVES a position the caller already holds, so the pair browser’s default cap (which hides whole chains) would hide real destinations. Each row still carries its own `risk` breakdown. | | `collateralPriceUsd` | query | string | no | **Override.** USD price of the source collateral, for sizing the position. Resolved server-side. | | `debtPriceUsd` | query | string | no | **Override.** USD price of the source debt, for sizing the position. Resolved server-side. | **Response `200`** — Ranked migration targets for the given position | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/loop/refinance - operationId: `refinance-roll-over-move-debt-to-a-fixed-term` - docs: https://docs.1delta.io/1delta-api/refinance-roll-over-move-debt-to-a-fixed-term - tags: Loop (Actions) Refinance / roll-over (move debt to a fixed term) Move a user's fixed-term debt into a fresh term — "refinance" / "roll-over". Serves **two** lenders, each with its own mechanism (the response shape is the same: a transaction plus its permissions): - **Lista DAO brokered markets** — a flash-loan-backed 1delta composer bundle (repay the source loan, open the new fixed loan). - **Exactly** — the protocol's OWN periphery (`DebtManager` on Optimism, `DebtRoller` on Base): ONE direct transaction that flash-loans from Balancer, repays the source position and re-borrows into the target. Because it acts on `msg.sender`'s own position it must be sent by the borrower, and it needs a Market **borrow allowance** (returned as a permission). Maps `fromLoanId` → source maturity and `termId` → target maturity, with `termId=0` meaning "roll into the variable/floating position" and an absent `fromLoanId` meaning "roll FROM the floating position". Base ships only the fixed→fixed direction. The response adds an `exactly` block (`direction`, `percentage`, `rolledAssets`, `projectedFaceValue`). - **Refinance** (default, omit `fromLoanId`): roll the **dynamic/float** position into a fixed term — e.g. an expired fixed loan the keeper rolled into the dynamic bracket. Lista's own `refinanceMaturedFixedPositions` (matured fixed → dynamic) is keeper-only; this is the user-driven inverse. - **Roll-over** (`fromLoanId` = a fixed loan's posId): roll one **fixed** loan into a different term (rate/duration). Rolling a not-yet-matured fixed loan repays it early, so `amount` must also cover its accrued interest + early-repayment penalty. Same collateral, same principal, different rate bracket. **Flash-loan backed** (robust at any LTV). The flash comes free from the market's own Moolah singleton, and the new fixed loan repays it. The returned transaction is a single composer bundle: ``` flashLoan(loanToken, amount) from Moolah: approve loanToken → Moolah # so Moolah can pull the flash repayment broker.repay(amount, DYNAMIC, user) # repay the float position with the flashed funds broker.borrow(amount, termId, user, receiver=composer) # open the new fixed loan; repays the flash → sweep residual loanToken back to user ``` Because the dynamic is repaid **before** the fixed borrow, the borrow's health check sees the original (net) debt — no 2× peak — so it works regardless of LTV. Net debt is unchanged. A `setAuthorization(composer)` permission (on Moolah) is returned **only when the composer isn't already authorized** — the broker's on-behalf borrow requires it, but `setAuthorization` reverts `AlreadySet()` if re-applied, so the server reads `isAuthorized(user, composer)` on-chain and omits the permission when it's already set. `actions.permissions` is empty in that case. **Notes:** - Single-market, debt-side only — pass the **loan-token** `marketUid` of a brokered market. - **Full close (default — omit `amount`):** the server sizes the flash to the source loan's borrow balance + a small (0.05%) margin, clearing it to zero (the broker refunds the margin, swept back). The balance is the **max** of (a) the `borrowBalance` you POST in the body and (b) a fresh on-chain read — robust whether or not the worker's live RPC is current. Avoids the `REMAIN_BORROW_TOO_LOW` revert from a stale client snapshot `amount`. **Prefer POST** with `borrowBalance` (+ `earlyRepayPenalty` for a not-yet-matured fixed source) from `/v1/data/lending/user-positions`; a plain GET also works (on-chain read only). Never make the user hand-pick an over-funded amount. - **Partial re-fix:** pass an explicit `amount` (leave `isAll` unset) < the source outstanding. Both the new fixed (`amount`) and the remaining source must clear `minLoan`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `marketUid` | query | string | yes | Loan-token market identifier of a Lista brokered market (`lender:chainId:address`). | | `amount` | query | string | no | Flash / repay / new-fixed amount (loan-token wei). **Required only for a partial re-fix** (provide `amount`, leave `isAll` unset). For a full close, omit it — the server sizes the flash itself; if present alongside a full close it is used only as a floor hint. | | `isAll` | query | boolean | no | Force a full close even when `amount` is present. A full close is also the DEFAULT whenever `amount` is omitted. The server sizes the flash to the source loan's borrow balance — the max of the POST-body `borrowBalance` (+ `earlyRepayPenalty`) and a fresh on-chain read (dynamic = `getUserTotalDebt` minus each fixed position's current debt; fixed = that position's current debt + early-repay penalty) — plus a small (0.05%) margin. The repay clears the source to zero and the broker refunds the margin (swept back), so there is no sub-`minLoan` dust and no `REMAIN_BORROW_TOO_LOW`. Set `amount` (and leave this unset) only for a deliberate partial re-fix. | | `termId` | query | integer | yes | Fixed term to move the debt into, from the market's `terms[]` rate card (`MarketTerm.termId`). | | `fromLoanId` | query | string | no | Source loan to roll FROM: a fixed loan's `loanId` (posId) to roll one fixed loan into another term, or omit (defaults to `type(uint128).max`) to refinance the dynamic/float position. | | `operator` | query | string | yes | The borrower (and tx sender). Both the repaid source loan and the new fixed loan are this account. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `borrowBalance` | string | no | Source loan's current borrow balance (loan-token wei). | | `earlyRepayPenalty` | string | no | Source loan's early-repay penalty (loan-token wei) — fixed, not-yet-matured source only. | **Example request body** ```json { "borrowBalance": "100030000000000000", "earlyRepayPenalty": "0" } ``` **Response `200`** — Flash-loan composer transaction (repay source loan + borrow new fixed term) and the borrow-authorization permission | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Response from proxy-mode lending operations (via 1delta composer). | | `data.transaction` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.transaction.to` | string | Target contract address | | `data.transaction.data` | string | Encoded calldata | | `data.transaction.value` | string | ETH value to send with the transaction | | `data.transaction.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approval transactions that must be executed before the main transaction. Empty when the user already has sufficient allowances. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.rateImpact` | object[] | Projected interest-rate impact per market. Single-market actions produce 1 entry; loop actions produce 2. Null if IRM data is unavailable. | | `data.rateImpact[].marketUid` | string | Market identifier (format: `lender:chainId:address`) | | `data.rateImpact[].utilization` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].utilization.current` | number | Current value | | `data.rateImpact[].utilization.projected` | number | Projected value after the action | | `data.rateImpact[].borrowRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].borrowRate.current` | number | Current value | | `data.rateImpact[].borrowRate.projected` | number | Projected value after the action | | `data.rateImpact[].depositRate` | object | A current/projected pair for a single rate metric. | | `data.rateImpact[].depositRate.current` | number | Current value | | `data.rateImpact[].depositRate.projected` | number | Projected value after the action | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "transaction": { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" }, "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ], "rateImpact": [ { "marketUid": "AAVE_V3:8453:0x4200000000000000000000000000000000000006", "utilization": { "current": 1, "projected": 1 }, "borrowRate": { "current": 1, "projected": 1 }, "depositRate": { "current": 1, "projected": 1 } } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Swap ### GET /v1/actions/swap/spot - operationId: `spot-swap-meta-aggregator` - docs: https://docs.1delta.io/1delta-api/spot-swap-meta-aggregator - tags: Swap Spot swap (meta-aggregator) Execute a spot swap via the meta-aggregator. Omit `account` for quote-only. Include `account` to build full transaction calldata. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `tokenIn` | query | string | yes | Input token address | | `tokenOut` | query | string | yes | Output token address | | `amount` | query | string | yes | Amount in wei | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address. Include to build transaction, omit for quote-only. | | `receiver` | query | string | no | Receiver address | | `tradeType` | query | 0 \| 1 | no | Trade type (0=EXACT_INPUT, 1=EXACT_OUTPUT) | | `usePendleMintRedeem` | query | boolean | no | Use Pendle mint/redeem | **Response `200`** — Spot swap quote or full build | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.currencyIn` | object | Input currency info | | `data.currencyOut` | object | Output currency info | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].aggregator` | string | | | `data.quotes[].tradeInput` | number | | | `data.quotes[].tradeOutput` | number | | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "currencyIn": {}, "currencyOut": {}, "quotes": [ { "aggregator": "string", "tradeInput": 1, "tradeOutput": 1 } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/swap/x-chain - operationId: `cross-chain-swap-bridge-aggregation` - docs: https://docs.1delta.io/1delta-api/cross-chain-swap-bridge-aggregation - tags: Swap Cross-chain swap (bridge aggregation) Quote a cross-chain swap across all supported bridge aggregators (Across, LI.FI, Squid, Stargate, Symbiosis, XY Finance, DZap, …) and build the winning transactions. Omit `account` for quote-only. Include `account` to build full transaction calldata. Each build quote carries `approvalTarget`/`approvalRequired`, and `actions.permissions` holds one ERC-20 approve per unique spender (composed routes share the 1delta composer; plain bridges use their own deposit contract) with a `spender` field — execute only the permission whose `spender` equals your chosen quote's `approvalTarget`. When `fromChainId` equals `toChainId` the request falls back to the spot meta-aggregator (same response shape with `aggregator` instead of `bridge` per quote, marked `fallback: 'spot'`). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `fromChainId` | query | string | yes | Source chain ID | | `toChainId` | query | string | yes | Destination chain ID | | `tokenIn` | query | string | yes | Input token address on the source chain (zero address for native) | | `tokenOut` | query | string | yes | Output token address on the destination chain (zero address for native) | | `amount` | query | string | yes | Input amount in wei | | `slippage` | query | number | yes | Slippage tolerance (basis points) | | `account` | query | string | no | Account address on the source chain. Include to build transactions, omit for quote-only. | | `receiver` | query | string | no | Receiver address on the destination chain (defaults to account) | | `order` | query | "CHEAPEST" \| "FASTEST" | no | Route preference | | `bridges` | query | string | no | Comma-separated bridge filter (e.g. `Across,LI.FI`). Defaults to all supported bridges. | **Response `200`** — Cross-chain swap quote or full build | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `data.currencyIn` | object | Input currency info (source chain) | | `data.currencyOut` | object | Output currency info (destination chain) | | `data.quotes` | object[] | Candidate routes, best output first. Execute exactly one. | | `data.quotes[].bridge` | string | | | `data.quotes[].tradeInput` | number | | | `data.quotes[].tradeOutput` | number | | | `data.quotes[].estimatedDuration` | number | Estimated bridging duration in seconds | | `data.quotes[].approvalTarget` | string | This bridge's deposit contract — the ERC-20 approve spender | | `data.quotes[].approvalRequired` | boolean | False when the existing on-chain allowance already covers the input amount | | `data.quotes[].tx` | object | An EVM transaction ready to sign and broadcast. Send `to`, `data` and `value` as-is; do not re-encode them. | | `data.quotes[].tx.to` | string | Target contract address | | `data.quotes[].tx.data` | string | Encoded calldata | | `data.quotes[].tx.value` | string | ETH value to send with the transaction | | `data.quotes[].tx.description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `data.permissionTxns` | object[] | ERC-20 approves per bridge deposit contract; each is labeled with the bridge name — execute only the one matching the chosen quote | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `data.quotes[].aggregator` | string | | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "currencyIn": {}, "currencyOut": {}, "quotes": [ { "bridge": "string", "tradeInput": 1, "tradeOutput": 1, "estimatedDuration": 1 } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Vaults (Actions) ### GET /v1/actions/vaults/deposit - operationId: `vault-deposit` - docs: https://docs.1delta.io/1delta-api/vault-deposit - tags: Vaults (Actions) Vault deposit The **single deposit entry point** for every share-token vault. The protocol, interface, and underlying are resolved from the `vault` (share token), so a deposit needs only `vault` + `amount` + `operator`. **What it routes, all from the share token** - **ERC-4626 family** — savings, Morpho, Fluid, Euler-Earn, Silo, Gearbox, Lagoon, Yearn. Routes directly to `vault.deposit` when no wrap/swap is needed; otherwise the 1delta Composer (wraps native ETH, handles composition). - **LST / liquid-staking mints** — stETH, wstETH, weETH, rETH, stCELO, pumpBTC, Solv, Core, native-staked, … Resolved from the calldata-sdk registry by `vault` and built via the protocol's mint path, including protocol-specific prep (e.g. StakedCelo validator-group selection — see `validatorGroup`). - **ERC-7540** async and **ERC-7575** multi-asset vaults — detected via an ERC-165 probe. `underlying` and `interface` are read on-chain (`asset()` + ERC-165) when omitted; pass them explicitly to skip the reads. For Fluid **margin vaults** (NFT-position lending markets), use `/v1/actions/lending/deposit` instead. > **Not handled here:** GMX (GM/GLV) and Hypercore vaults are USD-denominated / multi-leg, not `asset()`-based share tokens, so they keep dedicated flows — GMX via [/v1/actions/vaults/gmx](/1delta-api/vaults-gmx), Hypercore via `interface=hypercore` below. Passing one to the auto path returns `UNRESOLVED_UNDERLYING`. > > `/v1/actions/vaults/lst` and `/v1/actions/vaults/savings` remain as back-compatible aliases for their specific flows. **Execution mode** (`mode` query param, ERC-4626 path) - `auto` (default) — direct when `payAsset === underlying` and not native, otherwise composer. - `direct` — force direct; returns 400 when not eligible (e.g. native `payAsset`). - `proxy` — force the composer (legacy behavior). The direct path is smaller (one call to the vault) and sidesteps the EVC indirection that the composer triggers. Approval target also changes: direct → the vault; proxy → the composer. **Native deposits** Native ETH is supported via the composer's wrap-then-deposit path (`mode=proxy`, or `auto` falls back automatically), and natively by most LST mints (`payAsset=0x0`). Fluid fToken vaults expose a payable `depositNative` that skips wrapping — opt in with `provider=fluid`. --- ## Async / multi-asset / Hypercore (`interface` query param) Auto-detected for ERC-7540/7575; only Hypercore needs an explicit `interface`: - `erc7540` — **async** vaults. Two-phase: `action=requestDeposit` (default, escrow assets) then `action=claimDeposit` (mint once fulfilled). Pass `controller` when it isn't `operator`. Track the pending request via [/v1/data/vaults/withdrawals](/1delta-api/vaults-withdrawals). - `erc7575` — **multi-asset** vaults (share ≠ entry token). `isShares` switches deposit-by-assets vs mint-by-shares. - `hypercore` — **HyperLiquid** multi-leg deposit route (explicit only). `amount` is uint64 micro-USD (USDC); `source` picks the funding origin and the response is a structured `legs[]` array (each with its own `chainId`/`async`) rather than `transactions[]`. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `vault` | query | string | yes | Share-token address — ERC-4626 vault or LST share token. The protocol/interface is resolved from it. (Alias: `shareToken`.) | | `underlying` | query | string | no | Vault's `asset()` (real ERC-20 — never the zero address). Resolved on-chain from `vault` when omitted; required only for vaults without an `asset()` getter. Not needed for LST share tokens. | | `amount` | query | string | yes | Amount in wei. Interpreted as assets unless `isShares=true`. | | `operator` | query | string | yes | User wallet executing the deposit (payer) | | `payAsset` | query | string | no | What the user actually pays. Defaults to `underlying`. Zero address or the `0xEEEE…` sentinel = native ETH (composer wraps before depositing). | | `receiver` | query | string | no | Share recipient. Defaults to `operator`. The composer mints shares directly to this address. | | `isShares` | query | boolean | no | When `true`, `amount` is treated as shares (mint) rather than assets (deposit). | | `isAll` | query | boolean | no | Full-balance deposit. Relaxes the exit-sweep tolerance so dust does not revert the tx. | | `provider` | query | "fluid" | no | Optional provider hint. Currently only `fluid` is recognized — it opts into Fluid's payable `depositNative` path when paying native ETH. | | `mode` | query | "auto" \| "direct" \| "proxy" | no | Execution mode. `auto` (default) routes direct when no wrap/swap is needed, composer otherwise. `direct` forces vault-direct (returns 400 if ineligible). `proxy` forces the composer. | | `interface` | query | "erc4626" \| "erc7540" \| "erc7575" \| "hypercore" \| "native-wnlp" | no | Vault interface. Auto-detected via ERC-165 when omitted (`erc4626`/`erc7540`/`erc7575`), or from the savings registry for Native `wNLP` (`native-wnlp` → `depositAndWrap`, which also fills in `underlying` — wNLP has no `asset()` to probe). Pass `hypercore` explicitly for HyperLiquid (USD multi-leg). LST share tokens are routed by registry regardless of this param. | | `action` | query | "requestDeposit" \| "claimDeposit" | no | `interface=erc7540` only — `requestDeposit` (default) escrows assets; `claimDeposit` mints once fulfilled. | | `controller` | query | string | no | `interface=erc7540` controller, when not `operator`. | | `validatorGroup` | query | string | no | StakedCelo (stCELO) only — validator group to vote for. A `changeStrategy(group)` step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; pass the zero address to force the default. Other LST options (`poolId`, `kind`, `referral`, …) from /vaults/lst are also accepted here. | | `minUsddOut` | query | string | no | sUSDD PSM zap only (`payAsset` = USDT/USDC into the sUSDD vault) — the 18-decimal USDD amount the deposit leg uses after the PSM swap. AUTO-QUOTED when omitted: the route reads the PSM’s live `tin` fee and the gem decimals and computes `amount·10^(18−dec) − fee`. Pass explicitly to pin a quote. | | `source` | query | "hypercore-perp" \| "hypercore-spot" \| "hyperevm" \| "arbitrum" | no | `interface=hypercore` deposit funding origin. | | `hyperEvmUsdc` | query | string | no | `interface=hypercore`, `source=hyperevm` — the HyperEVM USDC token address. | **Response `200`** — Transaction calldata + approval(s) for the vault deposit. `interface=hypercore` returns a structured `legs[]` route instead of `transactions[]`. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/vaults/gmx - operationId: `vaultsGmx` - docs: https://docs.1delta.io/1delta-api/vaults-gmx - tags: Vaults (Actions) GMX V2 GM / GLV deposit · withdraw · cancel Build calldata for **GMX V2** GM-market / GLV liquidity actions (Arbitrum `42161`, Avalanche `43114`). These are **async**: each call returns a single `ExchangeRouter` (GM) / `GlvRouter` (GLV) `multicall` transaction (plus any ERC-20 approval to the GMX Router), and a **keeper** executes the request a few seconds later. The deposit/withdraw tx must carry a native `executionFee` (the keeper's gas reimbursement) — GMX reverts if it's underpaid. ## Actions - `deposit` (default) — add liquidity. Needs `longToken` + `shortToken` (the market legs), `payAsset` (the token paid in), `amount`, `executionFee`. - `withdraw` — remove liquidity (burn GM/GLV tokens). Needs `amount` (GM/GLV tokens), `executionFee`. - `cancel` — cancel a still-pending deposit/withdrawal ticket. Needs `request=deposit|withdrawal` and the 32-byte `key` (from [/v1/data/vaults/gmx](/1delta-api/vaults-gmx)). ## GM vs GLV (`kind`) - `gm` (default) — a single GM market; `market` defaults to `vault`. - `glv` — an auto-rebalancing GLV vault; you **must** name the GM `market` within the GLV. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID — `42161` (Arbitrum) or `43114` (Avalanche). See the `ChainId` schema for the full set of supported chains. | | `action` | query | "deposit" \| "withdraw" \| "cancel" | no | Operation to build. | | `kind` | query | "gm" \| "glv" | no | Pool kind. | | `vault` | query | string | yes | GM market token (`gm`) or GLV token (`glv`). | | `operator` | query | string | yes | Caller wallet (deposit/withdraw). `receiver` defaults to it. | | `receiver` | query | string | no | Recipient. Defaults to `operator`. | | `amount` | query | string | no | deposit: input-token amount. withdraw: GM/GLV tokens to burn. Wei. | | `executionFee` | query | string | no | deposit/withdraw: native keeper fee (wei), forwarded as the tx `value`. GMX rejects underpaid requests — quote it from the GMX UI/SDK. | | `market` | query | string | no | GLV: **required** — the GM market within the GLV. GM: defaults to `vault`. | | `longToken` | query | string | no | deposit: **required** — the market long leg. | | `shortToken` | query | string | no | deposit: **required** — the market short leg. | | `payAsset` | query | string | no | deposit: token paid in. Zero / `0xEEEE…` = native. Defaults to `longToken`. | | `minOut` | query | integer | no | Slippage floor on output GM/GLV (deposit) or output token (withdraw). | | `minLongTokenAmount` | query | integer | no | withdraw: min long-token received. | | `minShortTokenAmount` | query | integer | no | withdraw: min short-token received. | | `isMarketTokenDeposit` | query | boolean | no | deposit: the input is already GM tokens (GLV deposit of an existing GM position). | | `shouldUnwrapNativeToken` | query | boolean | no | withdraw: unwrap WETH/WAVAX output to native. | | `uiFeeReceiver` | query | string | no | Optional UI-fee recipient. | | `callbackGasLimit` | query | integer | no | Optional gas limit for the keeper callback. | | `request` | query | "deposit" \| "withdrawal" | no | cancel: which pending ticket to cancel. | | `key` | query | string | no | cancel: 32-byte request key (from `/v1/data/vaults/gmx`). | **Response `200`** — A single `ExchangeRouter`/`GlvRouter` `multicall` transaction (plus any Router approval). A keeper executes the request shortly after. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/vaults/lst - operationId: `vaultsLst` - docs: https://docs.1delta.io/1delta-api/vaults-lst - tags: Vaults (Actions) LST / LRT mint · withdraw-request · claim · cancel Build calldata for **LST / LRT** (and Lagoon) actions — mint, withdraw-request, claim, and cancel — via the unified LST dispatchers. The protocol is resolved from the calldata-sdk registry by `(chainId, shareToken)`, or forced with `kind=` (required for Lagoon — `kind=lagoon&mode=sync|async` — and any unregistered vault). > **Deposits also work through the unified /v1/actions/vaults/deposit** — pass the LST share token as `vault` and it routes here automatically (no need to know it's an LST). This endpoint stays as the explicit LST route and is the home for the **exit-side** actions (`request-withdraw` / `claim` / `cancel`), which the generic deposit endpoint does not cover. --- ## How an integrator knows what to pay with (`acceptedInputs`) LSTs are **not** uniform ERC-4626 vaults — each protocol accepts a different set of pay assets (native ETH, an unwrapped sibling like stETH/eETH, or specific ERC-20s) and some paths require extra slippage/intermediate options. Rather than hard-coding this, **fetch the vault data first and let it drive the request**: 1. `GET /v1/data/vaults?chainId=…&providers=lst` → each LST carries a `providerMeta` block: - `isMintable` — `false` ⇒ no on-chain mint (e.g. cbETH); don't call this endpoint. - `mintContract` — the deposit target. - `exchangeRate` / `convertToShares` — to compute expected output and a `minOut`. - **`acceptedInputs[]`** — the machine-readable accept-set (see below). 2. Pick the `acceptedInputs` entry whose `asset` matches what the user holds. 3. Call this endpoint with `action=deposit`, `payAsset=`, and the entry's `needs[]` supplied as query params. ### `acceptedInputs[]` entry shape | field | meaning | |---|---| | `asset` | `"native"` (pay with the chain coin → pass `payAsset=0x000…000`) or a lowercased ERC-20 address to pass as `payAsset`. | | `symbol` | optional UI hint (e.g. `stETH`). | | `mode` | `direct` (single call) · `wrap` (approve + wrap a base LST the user already holds) · `submit-wrap` (native → base → wrapped; needs the realised base amount). | | `needs` | option keys the caller **must** pass for this path (e.g. `["minMETHAmount"]`, `["eEthAmount"]`, `["stEthAmount"]`). Absent ⇒ none. | **Example** — wstETH advertises three paths: ```json "acceptedInputs": [ { "asset": "native", "mode": "direct" }, { "asset": "0xae7ab9…", "symbol": "stETH", "mode": "wrap" }, { "asset": "native", "mode": "submit-wrap", "needs": ["stEthAmount"] } ] ``` - Pay with ETH → `payAsset=0x000…000` (one-step `receive()`). - Pay with stETH you already hold → `payAsset=0xae7ab9…` (approve + wrap). --- ## Multi-step results `wrap` / `submit-wrap` paths produce **multiple ordered transactions**. The response's `actions.transactions[]` is the sequence to execute **in order**, and `actions.permissions[]` carries any ERC-20 approvals to run **first**. Single-step mints return one transaction and (for native) no permissions. Always iterate `transactions[]`; never assume a single tx. --- ## Slippage / required options Paths whose `needs` includes a min-out (`minMETHAmount`, `minRSETHAmountExpected`, …) require the caller to compute the floor from the data's `exchangeRate` and pass it. Native one-step mints (stETH, ETHx, ezETH, ynETH, pufETH, wstETH-receive) need nothing beyond `amount`. --- ## Actions - `deposit` — mint. `amount` required; `payAsset` (default native); path options per `acceptedInputs[].needs`. - `request-withdraw` — start an exit (queue/cooldown). `amount` required; `inputAsset?`, `outputAsset?`, `owner?`. - `claim` — settle a matured exit. Identifier params: `requestIds`/`hints`/`amounts` (CSV), `tokenId`, `id`, `shares`, `assets`, `controller`, `user`, `recipient`. - `cancel` — cancel a pending request (same identifier params). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `action` | query | "deposit" \| "request-withdraw" \| "claim" \| "cancel" | no | Operation to build. | | `shareToken` | query | string | yes | LST share-token address (the token the user wants to mint / exit). | | `operator` | query | string | yes | User wallet executing the action (payer). `receiver` defaults to it. | | `receiver` | query | string | no | Recipient of the minted shares / claimed assets. Defaults to `operator`. | | `amount` | query | string | no | Required for `deposit` and `request-withdraw`. Wei, in the `payAsset` decimals. | | `payAsset` | query | string | no | deposit: what the user pays. Zero address (or `0xEEEE…`) = native; otherwise an ERC-20 from the LST's `acceptedInputs[].asset`. Defaults to native. | | `kind` | query | string | no | Protocol override — required for Lagoon (`lagoon`) and any vault not in the static registry. Otherwise resolved from `(chainId, shareToken)`. | | `mode` | query | "sync" \| "async" | no | Lagoon deposit mode. | | `minOut` | query | integer | no | Generic slippage floor (wei) where the protocol path accepts one. For protocol-specific names see the LST `acceptedInputs[].needs`. | | `referral` | query | string | no | Optional referral address (protocols that support it). | | `stEthAmount` | query | integer | no | wstETH `submit-wrap` path: the realised stETH amount (read `stETH.balanceOf` after the submit leg). | | `eEthAmount` | query | integer | no | weETH `submit-wrap` path: the realised eETH amount (read after the deposit leg). | | `vault` | query | string | no | StakeWise per-vault target (and other per-vault protocols). | | `poolId` | query | string | no | Solv pool selector. | | `validatorGroup` | query | string | no | StakedCelo (stCELO) deposit: validator group to vote for — a `changeStrategy(group)` step is prepended (account-wide). Auto-selected when omitted and the caller is on the (reverting) default strategy; zero address forces the default. | | `rewardVault` | query | string | no | BeraPaw reward-vault target. | | `stakingToken` | query | string | no | Bearn staking-token target. | | `inputAsset` | query | string | no | request-withdraw: asset being burned, when the protocol needs it disambiguated. | | `outputAsset` | query | string | no | request-withdraw / claim: desired exit asset, when the protocol supports a choice. | | `owner` | query | string | no | request-withdraw: position owner, when not `operator`. | | `requestIds` | query | string | no | claim/cancel: CSV of withdrawal-request ids. | | `hints` | query | string | no | claim/cancel: CSV of finalization hints (Lido). | | `amounts` | query | string | no | claim/cancel: CSV of per-request amounts. | | `tokenId` | query | integer | no | claim/cancel: NFT request id. | | `id` | query | integer | no | claim/cancel: numeric request id. | | `shares` | query | integer | no | claim: share amount (7540/4626 savings). | | `assets` | query | integer | no | claim: asset amount. | | `controller` | query | string | no | claim: 7540 controller, when not `receiver`. | | `user` | query | string | no | claim/cancel: position user, when not `operator`. | | `recipient` | query | string | no | claim: payout recipient, when supported. | **Response `200`** — Ordered `transactions[]` (execute in sequence) + ERC-20 `permissions[]` (execute first). Single-step mints return one transaction. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/vaults/savings - operationId: `vaultsSavings` - docs: https://docs.1delta.io/1delta-api/vaults-savings - tags: Vaults (Actions) Savings-vault request-withdraw · claim · deposit · cancel Build calldata for **savings-vault** exits — the cooldown / async-redeem mechanics that plain ERC-4626 `withdraw` can't express (Ethena `sUSDe`, `erc7540` async vaults, instant `erc4626` redeem, and Native Credit Pool `wNLP`) — plus the deposit leg for the one family that isn't ERC-4626. The protocol is resolved from the calldata-sdk savings registry by `(chainId, shareToken)`, or forced with `kind=ethena|erc7540|erc4626|native-wnlp`. > **ERC-4626 savings deposits go through /v1/actions/vaults/deposit.** Native `wNLP` works on *either* route — `/vaults/deposit` auto-detects it from the registry and needs no `underlying`. ## Actions - `request-withdraw` (default) — start the exit: - **Ethena** → `cooldownShares(amount)` (or `cooldownAssets` when `byAssets=true`); escrows the assets for the cooldown window. - **erc7540** → `requestRedeem`. - **erc4626** → instant `redeem` (no cooldown). - **native-wnlp** → `WithdrawQueue.requestWithdrawal(amount)` — the **free** leg; the payout is snapshotted at request time and claimable after the queue window. Pass `instant=true` for `instantRedeem` instead: one transaction, no wait, but it costs the vault's `withdrawFeeBps` (100 bps by default) — deducted from the underlying paid out, never charged as a separate transfer — and is capped by its reported `liquidity`. - `claim` — settle a matured exit: - **Ethena** → `unstake(receiver)`. - **erc7540 / erc4626** → `redeem` (pass `shares`). - **native-wnlp** → `claimWithdrawalTo(receiver)`; no `shares` — the queue always pays the full request. - `deposit` — **native-wnlp only** (`depositAndWrap(receiver, amount)`). Every other kind is a plain ERC-4626 mint and is rejected here with a pointer to `/vaults/deposit`. - `cancel` — **native-wnlp only**; withdraw an open queued request and take the shares back. One request per address, so cancel is also how you resize one. Track pending requests via [/v1/data/vaults/withdrawals](/1delta-api/vaults-withdrawals). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `action` | query | "request-withdraw" \| "claim" \| "deposit" \| "cancel" | no | Operation to build. `deposit` and `cancel` are Native `wNLP` only. | | `shareToken` | query | string | yes | Savings share-token address (e.g. sUSDe `0x9d39a5de30e57443bff2a8307a4256c8797a3497`). | | `operator` | query | string | yes | User wallet executing the action (share holder). `receiver` defaults to it. | | `receiver` | query | string | no | Recipient of the claimed assets. Defaults to `operator`. | | `kind` | query | "ethena" \| "erc7540" \| "erc4626" \| "native-wnlp" | no | Protocol override. Otherwise resolved from `(chainId, shareToken)`. | | `amount` | query | string | no | request-withdraw: shares to cool down (or underlying assets when `byAssets=true`). deposit: underlying to wrap. Wei. | | `byAssets` | query | boolean | no | request-withdraw, **Ethena only** — interpret `amount` as the underlying asset amount (`cooldownAssets`) instead of shares (`cooldownShares`). | | `instant` | query | boolean | no | request-withdraw, **native-wnlp only** — take the immediate `instantRedeem` instead of the free queue. Costs the vault’s `withdrawFeeBps` (deducted from the underlying paid out) and is capped by its `liquidity`; check both on [/v1/data/vaults](/1delta-api/vaults) first. | | `underlying` | query | string | no | deposit, **native-wnlp only** — the asset to wrap, when the pool is too new to be in the registry. Otherwise resolved automatically. | | `shares` | query | integer | no | claim: share amount to redeem (erc7540 / erc4626). | | `owner` | query | string | no | request-withdraw: share owner, when not `operator` (erc4626 redeem). | | `controller` | query | string | no | erc7540 controller, when not `operator`. | **Response `200`** — Ordered `transactions[]` + ERC-20 `permissions[]` (run first). Each step carries its builder label as `description`. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/vaults/withdraw - operationId: `vault-withdraw` - docs: https://docs.1delta.io/1delta-api/vault-withdraw - tags: Vaults (Actions) Vault withdraw Build calldata for an ERC-4626 vault withdraw. When the user wants the underlying back (no native unwrap), the dispatcher calls `vault.withdraw` / `vault.redeem` directly with no approval needed. When the receiver wants native ETH, falls back to the composer (unwraps WETH). This endpoint targets **passive ERC-4626 vaults**. For Fluid's NFT-position margin vaults use `/v1/actions/lending/withdraw`. **Execution mode** (`mode` query param) - `auto` (default) — direct when `receiveAsset === underlying` and not native, otherwise composer. - `direct` — force direct; returns 400 when not eligible. - `proxy` — force the composer (legacy behavior). Direct withdraw skips the share-token approval entirely — the user calls `vault.withdraw(assets, receiver, owner=operator)` themselves and the vault uses its own balance check (`msg.sender == owner`). **Assets vs shares** - `isShares=false` (default): `amount` is assets — issues `vault.withdraw(assets, receiver, owner)`. - `isShares=true`: `amount` is shares — issues `vault.redeem(shares, receiver, owner)`. **Withdraw all** (`isAll=true`) Two ways to drive a full-balance withdraw — both resolve the operator's vault-share balance and encode `vault.redeem(shares, …)`. They differ only in **where the share balance is read**: - **GET** + `isAll=true` — worker reads `balanceOf(vault, operator)` against its own configured RPC. Simple but only works when the worker can see the state (i.e. live mainnet, not fork). Returns `BALANCE_READ_FAILED` on RPC failure. - **POST** + `isAll=true` + body `{ "sharesRaw": "" }` — caller pre-reads the balance against any RPC (fork, custom, premium) and supplies it. The worker just trusts and encodes. Mirrors the lending simulation pattern (`SimulationBody`). The POST body's `amount` query param is ignored when `isAll=true`. --- ## Non-4626 interfaces (`interface` query param) Default `erc4626` is the composer/direct path above. Otherwise: - `erc7540` — **async** redeem. `action=requestRedeem` (default) burns shares into the queue; `claimRedeem` / `claimWithdraw` settle once fulfilled. `controller` when not `operator`. - `erc7575` — **multi-asset**. Requires `share` (the share-token address); `isShares` toggles assets-out vs shares-in. - `hypercore` — **HyperLiquid** multi-leg withdraw route. `amount` is uint64 micro-USD; `destination` picks where the funds land. Returns a structured `legs[]` array. (Withdrawing out to Arbitrum is an L1 signed action, not EVM calldata — not offered here.) > Savings cooldowns (sUSDe) use [/v1/actions/vaults/savings](/1delta-api/vaults-savings); LST exits use [/v1/actions/vaults/lst](/1delta-api/vaults-lst). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `vault` | query | string | yes | ERC-4626 share-token address | | `underlying` | query | string | yes | Vault's `asset()` | | `amount` | query | string | yes | Amount in wei. Interpreted as assets unless `isShares=true`. | | `operator` | query | string | yes | User wallet executing the withdraw (share holder) | | `receiveAsset` | query | string | no | What the user receives. Defaults to `underlying`. Zero address or the `0xEEEE…` sentinel = native ETH (composer unwraps before forwarding). | | `receiver` | query | string | no | Final recipient of the withdrawn assets. Defaults to `operator`. | | `isShares` | query | boolean | no | When `true`, `amount` is treated as shares (the composer calls `vault.redeem`). | | `isAll` | query | boolean | no | Full-balance withdraw. Relaxes the sweep tolerance so dust does not revert the tx. | | `mode` | query | "auto" \| "direct" \| "proxy" | no | Execution mode. `auto` (default) routes direct when no unwrap is needed, composer otherwise. `direct` forces vault-direct (returns 400 if ineligible). `proxy` forces the composer. | | `interface` | query | "erc4626" \| "erc7540" \| "erc7575" \| "hypercore" \| "native-wnlp" | no | Vault interface. `erc4626` (default) = composer/direct path. Others dispatch to dedicated builders (see description). Native `wNLP` is auto-detected from the savings registry, which also fills in `underlying`. | | `instant` | query | boolean | no | `interface=native-wnlp` only — take the immediate `instantRedeem` instead of the free queue. Costs the vault’s `withdrawFeeBps` (100 bps by default), deducted from the underlying paid out rather than charged separately, and is capped by its reported `liquidity`. The default is the free queued leg: a fee is never charged unless asked for. | | `action` | query | "requestRedeem" \| "claimRedeem" \| "claimWithdraw" | no | `interface=erc7540` only — `requestRedeem` (default), `claimRedeem`, or `claimWithdraw`. `interface=native-wnlp` — `requestWithdraw` (default), `claim`, or `cancel`. | | `controller` | query | string | no | `interface=erc7540` controller, when not `operator`. | | `share` | query | string | no | `interface=erc7575` — the share-token address (required for that interface). | | `destination` | query | "hypercore-perp" \| "hypercore-spot" \| "hyperevm" | no | `interface=hypercore` withdraw destination. | **Response `200`** — Transaction calldata + any approval(s) needed for the vault withdraw. `interface=hypercore` returns a structured `legs[]` route instead of `transactions[]`. | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/vaults/withdraw - operationId: `vault-withdraw-with-caller-supplied-share-balance` - docs: https://docs.1delta.io/1delta-api/vault-withdraw-with-caller-supplied-share-balance - tags: Vaults (Actions) Vault withdraw (with caller-supplied share balance) POST variant for `isAll=true` when the worker can't read the operator's share balance against its own RPC — fork tests, custom RPCs, sandbox endpoints. Same query params as GET; the body supplies the balance. When `isAll=true` the worker treats the body's `sharesRaw` as the truth and encodes `vault.redeem(sharesRaw, receiver, operator)`. The query `amount` is ignored on this path. When `isAll` is omitted/false the body is ignored (caller's `amount` is authoritative) — POST and GET behave identically. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID See the `ChainId` schema for the full set of supported chains. | | `vault` | query | string | yes | ERC-4626 share-token address | | `underlying` | query | string | yes | Vault's `asset()` | | `amount` | query | string | yes | Ignored when `isAll=true` is set. Otherwise: amount in wei (assets unless `isShares=true`). | | `operator` | query | string | yes | User wallet (share holder) | | `receiveAsset` | query | string | no | Underlying token to receive. Defaults to `underlying`. | | `receiver` | query | string | no | Final recipient. Defaults to `operator`. | | `isShares` | query | boolean | no | When `true`, `amount` is shares (ignored if `isAll=true`). | | `isAll` | query | boolean | no | Full-balance withdraw. Body must include `sharesRaw`. | | `mode` | query | "auto" \| "direct" \| "proxy" | no | Same as GET — execution mode selector. | **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `sharesRaw` | string | yes | Operator's current vault-share balance as a decimal uint string. The worker uses this directly as the redeem amount. | **Example request body** ```json { "sharesRaw": "993566017" } ``` **Response `200`** — Transaction calldata + any approval(s) needed for the vault withdraw | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Midnight ### GET /v1/actions/midnight/cancel - operationId: `midnight-cancel` - docs: https://docs.1delta.io/1delta-api/midnight-cancel - tags: Midnight Cancel offer Cancel one of the maker's open offers. Calls `cancelRoot(maker, root)` on the Midnight EcrecoverRatifier, invalidating the offer under that tree `root`. A plain on-chain transaction by the maker — no signature needed. Get the offer's `root` from [`/v1/data/lending/orders`](/1delta-api/lending-orders) (the order's `id`). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. | | `account` | query | string | yes | Maker (offer owner) address. | | `root` | query | string | yes | Offer tree root (bytes32) — the order `id` from `/v1/data/lending/orders`. | **Response `200`** — The `cancelRoot` transaction (in `actions.transactions`) | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/midnight/finalize - operationId: `midnight-finalize` - docs: https://docs.1delta.io/1delta-api/midnight-finalize - tags: Midnight Make offer (finalize + publish) **MAKE — step 2 of 2.** Ratify the maker's signature and encode the on-chain payload that publishes the offer to the Midnight mempool (where the offer API indexes it). POST the `inputs` returned verbatim by `/v1/actions/midnight/make` together with the maker's `signature`. The worker rebuilds the identical offer tree from `inputs` and binds the signature to it — any change to `inputs` fails ratification on-chain. Returns the single publish transaction in `actions.transactions`. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `inputs` | object | yes | Deterministic offer inputs. Returned verbatim by `GET /v1/actions/midnight/make`; POST them back **unchanged** to `/v1/actions/midnight/finalize` alongside the signature so the worker rebuilds the identical offer tree. Any tampering fails on-chain ratification. | | `inputs.chainId` | string | no | EVM chain id, as a decimal string. See the `ChainId` schema. | | `inputs.lender` | string | no | `MORPHO_MIDNIGHT_` lender key. | | `inputs.buy` | boolean | no | `true` = maker BUYS units (a **lend** offer / bid); `false` = maker SELLS units (a **borrow** offer / ask). | | `inputs.tick` | string | no | Order-book tick the APR snapped to. | | `inputs.start` | string | no | | | `inputs.expiry` | string | no | Offer expiry, unix seconds. | | `inputs.maxAssets` | string | no | Maker-side size in loan-token units. | | `inputs.maker` | string | no | Maker (offer owner) address. | | `signature` | string | yes | Maker signature over `typedData` (0x hex). | **Example request body** ```json { "inputs": { "chainId": "8453", "lender": "MORPHO_MIDNIGHT_0xABC…", "buy": true, "tick": "string", "start": "0", "expiry": "string", "maxAssets": "string", "maker": "string" }, "signature": "string" } ``` **Response `200`** — The mempool publish transaction (in `actions.transactions`) | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/midnight/make - operationId: `midnight-make` - docs: https://docs.1delta.io/1delta-api/midnight-make - tags: Midnight Make offer (build typed-data) **MAKE — step 1 of 2.** Build the EIP-712 typed-data for a limit offer at your own rate. **Morpho Midnight is an order-book lender** — liquidity is a book of maker offers, not a pool — so there are two ways to interact: - **TAKE** (fill existing offers): use the **standard lending actions**, which route to Midnight automatically for a `MORPHO_MIDNIGHT_` market. There is no separate "take" endpoint. - **lend** → [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) — fills the **ask** side (supply offers) - **borrow** → [`/v1/actions/lending/borrow`](/1delta-api/lending-borrow) — fills the **bid** side (demand offers) - **repay** / **withdraw** → [`/v1/actions/lending/repay`](/1delta-api/lending-repay) · [`/withdraw`](/1delta-api/lending-withdraw) - Read the live two-sided ladder from [`/v1/data/lending/latest?includeOffers=true`](/1delta-api/lending-latest) — each order-book market's loan leg carries `offers` (bids) and `lendOffers` (asks), best-first, with per-level `aprPct`, `assets`, and `cumulativeAssets`. - **MAKE** (post your own limit offer at a chosen rate): the endpoints in this section (`/v1/actions/midnight/*`) plus [`/v1/data/lending/orders`](/1delta-api/lending-orders) to list and cancel them. **Make flow (worker-assisted signing):** 1. `GET /v1/actions/midnight/make` → returns `typedData`, the echoed `inputs`, and a one-time `authorization` tx. 2. The maker signs `typedData` with their wallet (`wallet.signTypedData`). 3. `POST /v1/actions/midnight/finalize` with `{ inputs, signature }` → the on-chain transaction that publishes the offer to the Midnight mempool. If `authorization` is present and the maker has **not** yet authorized the ratifier (read `isAuthorized` on-chain), send that one-time `setIsAuthorized` transaction **before** finalizing. The APR you request is snapped to an order-book tick — `aprPctSnapped` is the exact rate the offer will quote. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID (alias: `chain`). Midnight is Base-only today. See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | `MORPHO_MIDNIGHT_` lender key (the market to post into). See the `LenderId` schema for the full set of accepted values. | | `side` | query | "lend" \| "borrow" | yes | `lend` posts a bid (you lend when taken); `borrow` posts an ask (you borrow when taken). | | `aprPct` | query | number | yes | Your target APR in percent (alias: `rate`). Snapped to an order-book tick; see `aprPctSnapped` in the response. | | `size` | query | string | yes | Offer size in loan-token units (integer wei). | | `expiry` | query | integer | yes | Offer expiry, unix seconds. Must be in the future and ≤ the market maturity. | | `account` | query | string | yes | Maker (offer owner) address. | **Response `200`** — Offer typed-data, echoed inputs, and one-time authorization | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Everything the frontend needs to sign and publish a maker offer (step 1 of the make flow). `actions` is `null` — the publish transaction is produced by `/finalize` after signing. | | `data.typedData` | object | EIP-712 typed-data to sign with `wallet.signTypedData` (bigints serialized as strings — sign the response as-is). | | `data.inputs` | object | Deterministic offer inputs. Returned verbatim by `GET /v1/actions/midnight/make`; POST them back **unchanged** to `/v1/actions/midnight/finalize` alongside the signature so the worker rebuilds the identical offer tree. Any tampering fails on-chain ratification. | | `data.inputs.chainId` | string | EVM chain id, as a decimal string. See the `ChainId` schema. | | `data.inputs.lender` | string | `MORPHO_MIDNIGHT_` lender key. | | `data.inputs.buy` | boolean | `true` = maker BUYS units (a **lend** offer / bid); `false` = maker SELLS units (a **borrow** offer / ask). | | `data.inputs.tick` | string | Order-book tick the APR snapped to. | | `data.inputs.start` | string | | | `data.inputs.expiry` | string | Offer expiry, unix seconds. | | `data.inputs.maxAssets` | string | Maker-side size in loan-token units. | | `data.inputs.maker` | string | Maker (offer owner) address. | | `data.authorization` | object | One-time `setIsAuthorized(ecrecoverRatifier, true)` transaction on the Midnight core. Send FIRST, only if the maker has not authorized the ratifier yet (read `isAuthorized` on-chain). | | `data.authorization.to` | string | | | `data.authorization.data` | string | Informational payload. `null` when the endpoint only builds calldata. | | `data.authorization.value` | string | Native-token value to send with the transaction, in wei. | | `data.authorization.ratifier` | string | | | `data.aprPctSnapped` | number | The exact APR (percent) after tick-snapping — what the offer will actually quote once posted. | | `data.maturity` | number | Market maturity, unix seconds. | | `actions` | null | | **Example response** ```json { "success": true, "data": { "typedData": {}, "inputs": { "chainId": "8453", "lender": "MORPHO_MIDNIGHT_0xABC…", "buy": true, "tick": "string", "start": "0", "expiry": "string", "maxAssets": "string", "maker": "string" }, "authorization": { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "1000000000000000000", "ratifier": "string" }, "aprPctSnapped": 3.49, "maturity": 1 } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Term ### POST /v1/actions/term/bid - operationId: `term-bid` - docs: https://docs.1delta.io/1delta-api/term-bid - tags: Term Lock borrow bids (auction) **AUCTION BORROW — step 1 of 2.** Build the `lockBids` transaction that submits sealed borrow bids (escrowing collateral) to the repo's active `TermAuctionBidLocker`. Reveal them via `/v1/actions/term/reveal-bids`. **Term Finance is a fixed-rate tri-party-repo lender** (NOT a Morpho Blue fork) with two lend surfaces: - **Secondary order book** (`RepoTokenLinkedList`): buy/sell repo tokens continuously. LEND (buy a repo token) routes through the **standard lending action** [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) for a `TERM_FINANCE_` market. List/cancel your own repo tokens with `/v1/actions/term/list` · `/unlist`, and read your listings + auction submissions from the unified [`/v1/data/lending/orders`](/1delta-api/lending-orders). - **Primary auctions** (sealed-bid): submit a lend **offer** or borrow **bid**, then **reveal** it. The endpoints in this section (`/v1/actions/term/*`) build those transactions. **Servicing** (repay / redeem / collateral) always uses the standard lending actions: [repay](/1delta-api/lending-repay) · [withdraw](/1delta-api/lending-withdraw) · [deposit](/1delta-api/lending-deposit) (collateral leg). **Sealed commitments:** `offerPriceHash` / `bidPriceHash` = `keccak(price, nonce)` are computed **client-side** so the server never sees your secret price/nonce before reveal. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Protocol identifier. See the `LenderId` schema. | | `submissions` | object[] | yes | | | `submissions[].id` | string | no | bytes32 — omit / zero for a new bid. | | `submissions[].bidder` | string | yes | Bid owner address. | | `submissions[].bidPriceHash` | string | yes | bytes32 commitment = `keccak(price, nonce)`, computed client-side. | | `submissions[].amount` | string | yes | Borrow size in purchase-token units (integer wei). | | `submissions[].collateralAmounts` | string[] | yes | Collateral amounts to escrow, aligned with `collateralTokens`. | | `submissions[].collateralTokens` | string[] | yes | Collateral token addresses. | | `submissions[].purchaseToken` | string | no | Optional; defaults to the repo's purchase token. | | `referral` | string | no | Optional referral address. | **Example request body** ```json { "chainId": "1", "lender": "TERM_FINANCE_0xABC…", "submissions": [ { "id": "string", "bidder": "string", "bidPriceHash": "string", "amount": "1000000000000000000", "collateralAmounts": [ "1000000000000000000" ], "collateralTokens": [ "string" ], "purchaseToken": "string" } ], "referral": "string" } ``` **Response `200`** — The `lockBids` transaction + per-collateral approvals | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/term/list - operationId: `term-list` - docs: https://docs.1delta.io/1delta-api/term-list - tags: Term Create a secondary listing List repo tokens for sale on the secondary `RepoTokenLinkedList` order book (early exit). Escrows the repo token, so the response includes a repo-token approval. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | `TERM_FINANCE_` lender key. See the `LenderId` schema for the full set of accepted values. | | `amount` | query | string | yes | Amount to list, repo-token units (integer wei). | **Response `200`** — The `createListing` transaction + repo-token approval | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/term/offer - operationId: `term-offer` - docs: https://docs.1delta.io/1delta-api/term-offer - tags: Term Lock lend offers (auction) **AUCTION LEND — step 1 of 2.** Build the `lockOffers` transaction that submits sealed lend offers to the repo's active `TermAuctionOfferLocker`. Reveal them after the auction's reveal window opens via `/v1/actions/term/reveal-offers`. **Term Finance is a fixed-rate tri-party-repo lender** (NOT a Morpho Blue fork) with two lend surfaces: - **Secondary order book** (`RepoTokenLinkedList`): buy/sell repo tokens continuously. LEND (buy a repo token) routes through the **standard lending action** [`/v1/actions/lending/deposit`](/1delta-api/lending-deposit) for a `TERM_FINANCE_` market. List/cancel your own repo tokens with `/v1/actions/term/list` · `/unlist`, and read your listings + auction submissions from the unified [`/v1/data/lending/orders`](/1delta-api/lending-orders). - **Primary auctions** (sealed-bid): submit a lend **offer** or borrow **bid**, then **reveal** it. The endpoints in this section (`/v1/actions/term/*`) build those transactions. **Servicing** (repay / redeem / collateral) always uses the standard lending actions: [repay](/1delta-api/lending-repay) · [withdraw](/1delta-api/lending-withdraw) · [deposit](/1delta-api/lending-deposit) (collateral leg). **Sealed commitments:** `offerPriceHash` / `bidPriceHash` = `keccak(price, nonce)` are computed **client-side** so the server never sees your secret price/nonce before reveal. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Protocol identifier. See the `LenderId` schema. | | `submissions` | object[] | yes | | | `submissions[].id` | string | no | bytes32 — omit / zero for a new offer (the locker assigns it). | | `submissions[].offeror` | string | yes | Offer owner address. | | `submissions[].offerPriceHash` | string | yes | bytes32 commitment = `keccak(price, nonce)`, computed client-side; revealed later. | | `submissions[].amount` | string | yes | Offer size in purchase-token units (integer wei). | | `submissions[].purchaseToken` | string | no | Optional; defaults to the repo's purchase token. | | `referral` | string | no | Optional referral address. | **Example request body** ```json { "chainId": "1", "lender": "TERM_FINANCE_0xABC…", "submissions": [ { "id": "string", "offeror": "string", "offerPriceHash": "string", "amount": "1000000000000000000", "purchaseToken": "string" } ], "referral": "string" } ``` **Response `200`** — The `lockOffers` transaction + purchase-token approval | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/term/reveal-bids - operationId: `term-reveal-bids` - docs: https://docs.1delta.io/1delta-api/term-reveal-bids - tags: Term Reveal locked bids **AUCTION BORROW — step 2 of 2.** Reveal previously-locked bids after the reveal window opens. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Protocol identifier. See the `LenderId` schema. | | `ids` | string[] | yes | bytes32 offer/bid ids. | | `prices` | string[] | yes | Revealed prices (integer). | | `nonces` | string[] | yes | Revealed nonces. | **Example request body** ```json { "chainId": "1", "lender": "TERM_FINANCE_0xABC…", "ids": [ "string" ], "prices": [ "string" ], "nonces": [ "string" ] } ``` **Response `200`** — The `revealBids` transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/term/reveal-offers - operationId: `term-reveal-offers` - docs: https://docs.1delta.io/1delta-api/term-reveal-offers - tags: Term Reveal locked offers **AUCTION LEND — step 2 of 2.** Reveal previously-locked offers (opens the sealed price + nonce) after the reveal window opens. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Protocol identifier. See the `LenderId` schema. | | `ids` | string[] | yes | bytes32 offer/bid ids. | | `prices` | string[] | yes | Revealed prices (integer). | | `nonces` | string[] | yes | Revealed nonces. | **Example request body** ```json { "chainId": "1", "lender": "TERM_FINANCE_0xABC…", "ids": [ "string" ], "prices": [ "string" ], "nonces": [ "string" ] } ``` **Response `200`** — The `revealOffers` transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/term/unlist - operationId: `term-unlist` - docs: https://docs.1delta.io/1delta-api/term-unlist - tags: Term Cancel a secondary listing Cancel one of your secondary-market listings by `listingId` (the order `id` from [`/v1/data/lending/orders`](/1delta-api/lending-orders)). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | `TERM_FINANCE_` lender key. See the `LenderId` schema for the full set of accepted values. | | `listingId` | query | string | yes | The listing id to cancel. | | `skipRedeem` | query | boolean | no | Skip auto-redeem of the returned repo token (default false). | **Response `200`** — The `cancelListing` transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/term/unlock-bids - operationId: `term-unlock-bids` - docs: https://docs.1delta.io/1delta-api/term-unlock-bids - tags: Term Unlock (cancel) bids Cancel unrevealed bids, reclaiming escrowed collateral. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | `TERM_FINANCE_` lender key (the repo/auction). See the `LenderId` schema for the full set of accepted values. | | `ids` | query | string | yes | Comma-separated bytes32 offer/bid ids to unlock. | **Response `200`** — The `unlockBids` transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/term/unlock-offers - operationId: `term-unlock-offers` - docs: https://docs.1delta.io/1delta-api/term-unlock-offers - tags: Term Unlock (cancel) offers Cancel unrevealed offers, reclaiming the escrowed purchase token. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain ID (alias: `chain`). See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | `TERM_FINANCE_` lender key (the repo/auction). See the `LenderId` schema for the full set of accepted values. | | `ids` | query | string | yes | Comma-separated bytes32 offer/bid ids to unlock. | **Response `200`** — The `unlockOffers` transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Actions › Allocate ### POST /v1/actions/allocate - operationId: `allocate-multi-op-batch` - docs: https://docs.1delta.io/1delta-api/allocate-multi-op-batch - tags: Allocate Allocate (multi-op batch) Bundles multiple lending and token operations into a single composer transaction. Useful for portfolio rebalances, atomic deposit-then-borrow flows, or wrap/unwrap + deposit combos that should not be split across separate user signatures. **Request body:** `{ chainId, operator, actions[] }`. Each `actions[]` entry is `{ type, params }` where `type` is one of `Deposit | Withdraw | Borrow | Repay | Transfer | Wrap | Unwrap | Sweep`. The `params` shape is action-specific (asset, amount, market, etc.) — see the `AllocationAction` schema. **Response:** a single composer-call payload (`operations` / `data` / `value`) ready to send to the composer contract, plus `permissionTxns` for any required ERC20 approvals or borrow delegations. Returns 422 with field-level details if validation fails (unknown action type, missing required params, incompatible chain/lender combo). **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `operator` | string | yes | | | `actions` | object[] | yes | | | `actions[].type` | "Deposit" \| "Withdraw" \| "Borrow" \| "Repay" \| "Transfer" \| "Wrap" \| … (8 values) | yes | | | `actions[].params` | object | yes | | **Example request body** ```json { "chainId": "1", "operator": "0xOperatorAddress", "actions": [ { "type": "Deposit", "params": {} } ] } ``` **Response `200`** — Allocation transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | | | `data.operations` | string | | | `data.data` | string | Informational payload. `null` when the endpoint only builds calldata. | | `data.value` | string | Native-token value to send with the transaction, in wei. | | `data.permissionTxns` | object[] | Approvals needed for this specific quote. Most integrators should use the deduplicated envelope-level `actions.permissions` instead. | | `data.permissionTxns[].to` | string | Target contract address | | `data.permissionTxns[].data` | string | Encoded calldata | | `data.permissionTxns[].value` | string | ETH value | | `data.permissionTxns[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `data.permissionTxns[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": { "operations": "string", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "1000000000000000000", "permissionTxns": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] }, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `422`** — Validation failed (e.g. unknown action type, missing required params) **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Other ## Other › Data › Bridge ### GET /v1/data/bridge/status - operationId: `bridge-transfer-status` - docs: https://docs.1delta.io/1delta-api/bridge-transfer-status - tags: Data › Bridge Bridge transfer status Tracks a bridge transfer started via `/v1/actions/swap/x-chain` by polling the bridge's own tracking API. `status` is one of `PENDING`, `DONE`, `FAILED`, `TRANSFER_REFUNDED`, `INVALID`, `NOT_FOUND`, `PARTIAL_SUCCESS`. `NOT_FOUND` is normal in the first seconds after submission (indexer lag) — keep polling. `toHash` is the destination-chain transaction when the tracker exposes it. Responses are not cached. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `bridge` | query | string | yes | The `bridge` value from the executed quote | | `fromChainId` | query | string | yes | Source chain ID of the transfer | | `toChainId` | query | string | yes | Destination chain ID | | `txHash` | query | string | no | Source-chain transaction hash of the executed bridge transaction (required unless `orderId`) | | `tokenIn` | query | string | no | Bridged input token address — REQUIRED for Stargate (pool-keyed tracker), ignored by most bridges | | `tokenOut` | query | string | no | Bridged output token address — REQUIRED for Stargate | | `orderId` | query | string | no | Intent order id for order-based bridges (Mayan) | **Response `200`** — Transfer status | Field | Type | Description | | --- | --- | --- | | `success` | boolean | | | `data` | object | Informational payload. `null` when the endpoint only builds calldata. | | `data.bridge` | string | | | `data.status` | "PENDING" \| "DONE" \| "FAILED" \| "TRANSFER_REFUNDED" \| "INVALID" \| "NOT_FOUND" \| … (7 values) | | | `data.message` | string | | | `data.fromHash` | string | | | `data.toHash` | string | Destination-chain tx hash when known | | `data.details` | object | The tracker's raw response payload | **Example response** ```json { "success": true, "data": { "bridge": "string", "status": "PENDING", "message": "string", "fromHash": "string", "toHash": "string" } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Other › Actions › Liquity ### POST /v1/actions/liquity/adjust-zombie - operationId: `liquity-adjust-zombie` - docs: https://docs.1delta.io/1delta-api/liquity-adjust-zombie - tags: Actions › Liquity Re-adjust a zombie trove Bring a ZOMBIE trove (redeemed below the deployment minDebt — status 4, removed from the rate-ordered list) back above the floor. `adjustZombieTrove` is the only adjustment entry for zombie troves; it re-inserts at the trove's current rate. Collateral top-ups add the collateral approval; debt increases charge the upfront fee. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Protocol identifier. See the `LenderId` schema. | | `troveId` | string | yes | | | `collChange` | string | no | Collateral delta, raw units | | `isCollIncrease` | boolean | no | | | `boldChange` | string | no | Stable-debt delta, raw units | | `isDebtIncrease` | boolean | no | | | `maxUpfrontFee` | string | no | | **Example request body** ```json { "chainId": "1", "lender": "AAVE_V3", "troveId": "string", "collChange": "string", "isCollIncrease": true, "boldChange": "string", "isDebtIncrease": true, "maxUpfrontFee": "string" } ``` **Response `200`** — Zombie-adjust transaction + approvals | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/liquity/claim-surplus - operationId: `liquity-claim-surplus` - docs: https://docs.1delta.io/1delta-api/liquity-claim-surplus - tags: Actions › Liquity Claim liquidation collateral surplus Claim the caller's post-liquidation collateral surplus on a branch (collateral above the liquidation penalty is escrowed in the CollSurplusPool). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | Per-branch key See the `LenderId` schema for the full set of accepted values. | **Response `200`** — Claim transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/liquity/close - operationId: `liquity-close` - docs: https://docs.1delta.io/1delta-api/liquity-close - tags: Actions › Liquity Close a trove Close a trove: burns the FULL live `entireDebt` (incl. per-block interest accrual — keep a small stable buffer above any quote) from the sender and returns all collateral plus the gas compensation. Equivalent to `lending/repay` with `isAll=true`. **Liquity V2 family is a pooled CDP** — one branch per collateral, troves = sub-accounts (`troveId`, the sub-account id from user data), user-set adjustable interest rates, and a per-branch Stability Pool as the stable-token earn side. Deployments: `LIQUITY_V2` (Ethereum) + friendly forks (`USDAF`, `FELIX`, `NERITE`, `QUILL`, `ENOSYS_LOANS`, `SONETA`, `EBISU`) — all share this surface; per-fork parameters (min debt, rate bounds, gas compensation) come from metadata. **Standard lending actions cover the day-to-day ops** for a `__` market key: - stable-token deposit/withdraw → Stability Pool (earn; `isAll` withdraw uses the protocol sentinel) - collateral deposit/withdraw → `addColl`/`withdrawColl` (pass `troveId`) - borrow → `withdrawBold` (pass `troveId`; upfront-fee guard quoted automatically, override with `maxUpfrontFee`) - repay → `repayBold` clamped to `entireDebt − minDebt`; `isAll=true` routes to `closeTrove` (burns the full live debt from the wallet, returns collateral + the WETH gas compensation) The endpoints in this section handle the trove lifecycle ops that need more than one amount or no amount at all. Fees to know: the upfront borrowing fee (≈7 days of average branch interest on any debt increase) and the premature rate-adjustment fee (same formula on the WHOLE debt when changing the rate within the cooldown). Repaying itself is always free. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | Per-branch key, e.g. LIQUITY_V2_1_0 See the `LenderId` schema for the full set of accepted values. | | `troveId` | query | string | yes | Trove id (sub-account id from user data) | **Response `200`** — Close-trove transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/liquity/open - operationId: `liquity-open` - docs: https://docs.1delta.io/1delta-api/liquity-open - tags: Actions › Liquity Open a trove Open a trove: deposit collateral and mint stable debt at a user-set annual interest rate. **Liquity V2 family is a pooled CDP** — one branch per collateral, troves = sub-accounts (`troveId`, the sub-account id from user data), user-set adjustable interest rates, and a per-branch Stability Pool as the stable-token earn side. Deployments: `LIQUITY_V2` (Ethereum) + friendly forks (`USDAF`, `FELIX`, `NERITE`, `QUILL`, `ENOSYS_LOANS`, `SONETA`, `EBISU`) — all share this surface; per-fork parameters (min debt, rate bounds, gas compensation) come from metadata. **Standard lending actions cover the day-to-day ops** for a `__` market key: - stable-token deposit/withdraw → Stability Pool (earn; `isAll` withdraw uses the protocol sentinel) - collateral deposit/withdraw → `addColl`/`withdrawColl` (pass `troveId`) - borrow → `withdrawBold` (pass `troveId`; upfront-fee guard quoted automatically, override with `maxUpfrontFee`) - repay → `repayBold` clamped to `entireDebt − minDebt`; `isAll=true` routes to `closeTrove` (burns the full live debt from the wallet, returns collateral + the WETH gas compensation) The endpoints in this section handle the trove lifecycle ops that need more than one amount or no amount at all. Fees to know: the upfront borrowing fee (≈7 days of average branch interest on any debt increase) and the premature rate-adjustment fee (same formula on the WHOLE debt when changing the rate within the cooldown). Repaying itself is always free. Validates the deployment's min debt + rate bounds, quotes SortedTroves insert hints and the `maxUpfrontFee` guard on-chain, and picks the next free owner index. Returns the transaction plus the collateral (+ gas-compensation WETH) approvals. `interestRate` is OPTIONAL: omit it and the trove opens at the **branch average** user-set rate (the rate the market data quotes as the branch borrow rate — mid-pack in the redemption queue). The applied rate is returned as `interestRate` in the response `data`; change it later with `POST /v1/actions/liquity/set-rate`. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Per-branch key, e.g. LIQUITY_V2_1_0 | | `account` | string | yes | Trove owner (tx sender) | | `collAmount` | string | yes | Collateral amount, raw units | | `amount` | string | yes | Stable debt to mint, raw units (≥ deployment minDebt) | | `interestRate` | string | no | Optional user-set annual rate, WAD (1e16 = 1%). Default: the branch average rate. | | `ownerIndex` | string | no | Optional explicit owner index (default: next free) | | `maxUpfrontFee` | string | no | Optional fee-guard override, raw stable units | **Example request body** ```json { "chainId": "1", "lender": "LIQUITY_V2_1_0", "account": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "collAmount": "1000000000000000000", "amount": "1000000000000000000", "interestRate": "60000000000000000", "ownerIndex": "string", "maxUpfrontFee": "string" } ``` **Response `200`** — Open-trove transaction + approvals | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/liquity/set-rate - operationId: `liquity-set-rate` - docs: https://docs.1delta.io/1delta-api/liquity-set-rate - tags: Actions › Liquity Adjust the user-set interest rate Change a trove's user-set annual interest rate. Free after the deployment's cooldown (7 days vanilla); within it, the upfront fee applies to the WHOLE debt — the `maxUpfrontFee` guard is quoted accordingly. Lower rates increase redemption risk (redemptions hit lowest-rate troves first). **Liquity V2 family is a pooled CDP** — one branch per collateral, troves = sub-accounts (`troveId`, the sub-account id from user data), user-set adjustable interest rates, and a per-branch Stability Pool as the stable-token earn side. Deployments: `LIQUITY_V2` (Ethereum) + friendly forks (`USDAF`, `FELIX`, `NERITE`, `QUILL`, `ENOSYS_LOANS`, `SONETA`, `EBISU`) — all share this surface; per-fork parameters (min debt, rate bounds, gas compensation) come from metadata. **Standard lending actions cover the day-to-day ops** for a `__` market key: - stable-token deposit/withdraw → Stability Pool (earn; `isAll` withdraw uses the protocol sentinel) - collateral deposit/withdraw → `addColl`/`withdrawColl` (pass `troveId`) - borrow → `withdrawBold` (pass `troveId`; upfront-fee guard quoted automatically, override with `maxUpfrontFee`) - repay → `repayBold` clamped to `entireDebt − minDebt`; `isAll=true` routes to `closeTrove` (burns the full live debt from the wallet, returns collateral + the WETH gas compensation) The endpoints in this section handle the trove lifecycle ops that need more than one amount or no amount at all. Fees to know: the upfront borrowing fee (≈7 days of average branch interest on any debt increase) and the premature rate-adjustment fee (same formula on the WHOLE debt when changing the rate within the cooldown). Repaying itself is always free. **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Protocol identifier. See the `LenderId` schema. | | `troveId` | string | yes | | | `interestRate` | string | yes | New annual rate, WAD | | `maxUpfrontFee` | string | no | Optional fee-guard override | **Example request body** ```json { "chainId": "1", "lender": "LIQUITY_V2_1_0", "troveId": "string", "interestRate": "string", "maxUpfrontFee": "string" } ``` **Response `200`** — Rate-adjust transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ## Other › Actions › River ### GET /v1/actions/river/claim-surplus - operationId: `river-claim-surplus` - docs: https://docs.1delta.io/1delta-api/river-claim-surplus - tags: Actions › River Claim collateral surplus Claim the caller's post-liquidation/redemption collateral surplus on a market (`TroveManager.claimCollateral`). Surplus balances are visible in user data (`riverInfo.collateralSurplus`). **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | Per-market key See the `LenderId` schema for the full set of accepted values. | | `operator` | query | string | yes | Recipient (the surplus owner) | **Response `200`** — Claim transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### GET /v1/actions/river/close - operationId: `river-close` - docs: https://docs.1delta.io/1delta-api/river-close - tags: Actions › River Close the trove Close the caller's trove on a market: burns `entireDebt − gasCompensation` satUSD from the wallet, returns all collateral. Blocked in Recovery Mode (global TCR < 150%). Equivalent to `lending/repay` with `isAll=true`. **River (rebranded Satoshi Protocol) is a Prisma-lineage pooled CDP** minting satUSD behind one SatoshiXApp diamond per chain (BNB, Base, Hemi). One TroveManager per collateral = one `RIVER__` market; troves are keyed by OWNER ADDRESS — at most one per user per market, no ids. Interest is protocol-set (currently 0%); the only borrowing cost is a one-off decaying-baseRate mint fee (0.5%–5%) on open/borrow-more, guarded by `maxFeePercentage` (quoted automatically). **Standard lending actions cover the day-to-day ops:** - satUSD deposit/withdraw → the single per-chain Stability Pool (attached to market index 0; zero approvals) - collateral deposit/withdraw → `addColl`/`withdrawColl` (no troveId — address-keyed) - borrow → `withdrawDebt` (mint fee applies) - repay → `repayDebt` clamped to `entireDebt − gasComp − minNetDebt`; `isAll=true` routes to `closeTrove` (burns `entireDebt − gasComp` from the wallet, returns all collateral; blocked in Recovery Mode) The 2-satUSD debt-side gas compensation is minted on open and burned from the GasPool on close — it never touches the wallet. **Parameters** | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `chainId` | query | string | yes | Chain id See the `ChainId` schema for the full set of supported chains. | | `lender` | query | string | yes | Per-market key, e.g. RIVER_8453_0 See the `LenderId` schema for the full set of accepted values. | | `operator` | query | string | yes | Trove owner | **Response `200`** — Close-trove transaction | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400. ### POST /v1/actions/river/open - operationId: `river-open` - docs: https://docs.1delta.io/1delta-api/river-open - tags: Actions › River Open a trove Open a trove on a River market: deposit collateral, mint satUSD. **River (rebranded Satoshi Protocol) is a Prisma-lineage pooled CDP** minting satUSD behind one SatoshiXApp diamond per chain (BNB, Base, Hemi). One TroveManager per collateral = one `RIVER__` market; troves are keyed by OWNER ADDRESS — at most one per user per market, no ids. Interest is protocol-set (currently 0%); the only borrowing cost is a one-off decaying-baseRate mint fee (0.5%–5%) on open/borrow-more, guarded by `maxFeePercentage` (quoted automatically). **Standard lending actions cover the day-to-day ops:** - satUSD deposit/withdraw → the single per-chain Stability Pool (attached to market index 0; zero approvals) - collateral deposit/withdraw → `addColl`/`withdrawColl` (no troveId — address-keyed) - borrow → `withdrawDebt` (mint fee applies) - repay → `repayDebt` clamped to `entireDebt − gasComp − minNetDebt`; `isAll=true` routes to `closeTrove` (burns `entireDebt − gasComp` from the wallet, returns all collateral; blocked in Recovery Mode) The 2-satUSD debt-side gas compensation is minted on open and burned from the GasPool on close — it never touches the wallet. Validates the diamond-level minNetDebt and rejects paused/sunsetting markets; quotes the mint-fee guard live. Returns the transaction plus the collateral approval (to the diamond). **Request body** (`application/json`) | Field | Type | Required | Description | | --- | --- | --- | --- | | `chainId` | string | yes | EVM chain id, as a decimal string. See the `ChainId` schema. | | `lender` | string | yes | Per-market key, e.g. RIVER_8453_0 | | `account` | string | yes | Trove owner (tx sender) | | `collAmount` | string | yes | Collateral amount, raw units | | `amount` | string | yes | satUSD debt to mint, raw units (net ≥ minNetDebt) | | `maxFeePercentage` | string | no | Optional mint-fee guard override, WAD percentage | **Example request body** ```json { "chainId": "8453", "lender": "RIVER_8453_0", "account": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "collAmount": "1000000000000000000", "amount": "1000000000000000000", "maxFeePercentage": "string" } ``` **Response `200`** — Open-trove transaction + approval | Field | Type | Description | | --- | --- | --- | | `success` | true | | | `data` | object | Informational data (quotes, simulation results, etc.) | | `actions` | object | Transaction calldata and approvals. Null for quote-only responses (no account provided). | | `actions.transactions` | object[] | Pre-trade setup transactions (e.g. e-mode switch, collateral enable). Execute these before the main swap. Empty when no setup is needed. | | `actions.transactions[].to` | string | Target contract address | | `actions.transactions[].data` | string | Encoded calldata | | `actions.transactions[].value` | string | ETH value to send with the transaction | | `actions.transactions[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.alternatives` | object[] | DEX aggregator swap transactions sorted by best output (descending). Each entry's `description` is the aggregator name. The client should pick one to execute. Present on loop action endpoints. | | `actions.alternatives[].to` | string | Target contract address | | `actions.alternatives[].data` | string | Encoded calldata | | `actions.alternatives[].value` | string | ETH value to send with the transaction | | `actions.alternatives[].description` | string | Human-readable label. For `alternatives`, this is the aggregator name (e.g. "Paraswap"). For `transactions`, describes the setup action (e.g. "Switch e-mode to 1"). | | `actions.permissions` | object[] | Approval/delegation transactions that must execute before both `transactions` and `alternatives`. Includes ERC20 allowances (targeting the composer contract) and lender borrow/withdrawal delegations (targeting the lending protocol contract directly). Filtered against on-chain state so only missing approvals are returned. Null when no approvals are needed. | | `actions.permissions[].to` | string | Target contract address | | `actions.permissions[].data` | string | Encoded calldata | | `actions.permissions[].value` | string | ETH value | | `actions.permissions[].description` | string | Human-readable description of the approval (e.g. "Approve borrow for AAVE_V3", "Approve ERC20") | | `actions.permissions[].spender` | string | ERC-20 approve spender (x-chain permissions). Match it against the selected quote's `approvalTarget` — several bridges can share one spender, so do not match by description. | **Example response** ```json { "success": true, "data": {}, "actions": { "transactions": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "alternatives": [ { "to": "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string" } ], "permissions": [ { "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "data": "0x617ba037000000000000000000000000c02aaa39b2", "value": "0", "description": "string", "spender": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2" } ] } } ``` **Response `400`** — Validation error **Response `429`** — Rate limited. Unauthenticated callers share a per-IP budget; send an `x-api-key` header to lift it. Retry with exponential backoff. **Response `500`** — Unexpected server error. Safe to retry with backoff. **Response `502`** — An upstream data source or protocol origin failed (`error.code` is `ORIGIN_FAILED`). `error.details` carries the per-origin status. This is also what a missing or malformed required parameter currently returns, rather than a 400.