# DeFi on ChainRender — Complete Capability Guide

ChainRender can build **fully on-chain DeFi frontends**: apps that render live market data, a user's actual
positions, and pre-trade quotes, then let the user act — all as `eth_call` renders plus declared, decoded actions.
This page is the comprehensive reference for what ChainRender can and cannot do with DeFi, how each piece works, and
the honest boundaries.

## The mental model: render + declare, never *become* the protocol

ChainRender does two things for DeFi, and deliberately not a third:

1. **Render on-chain DeFi state** — prices, positions, quotes, approvals, pool state — as a free `view` call. No
   server, no indexer; the data is read from the protocol's own contracts during the render.
2. **Declare DeFi actions** — a button carries a declared `{to, sig, value, args}` (a swap, mint, approve, deposit),
   decoded into plain English before the user signs, governed by the capability envelope.
3. **It does NOT become a DEX / lending protocol / bridge.** ChainRender renders and triggers DeFi; it never holds
   funds, runs an AMM, or custodies anything. An app *built with* ChainRender can present a Uniswap swap — but the
   swap executes on Uniswap, not on ChainRender.

This separation is the whole safety story: rendering is trustless (a `view`), and actions can only do exactly what
they declare (enforced by the capability system + the action decoder).

## What ChainRender can RENDER (the resolver suite)

Each resolver is an immutable, ownerless, **view-only, fail-closed** contract: a reverting/missing target renders
`"unavailable"` rather than breaking the page. An app references a resolver by address + kind in a slot; the
interpreter calls `resolve(kind, args)` at render time.

### Market data
| Resolver | Kind | Renders |
|---|---|---|
| ChainlinkFeedResolver | `price` | An AggregatorV3 oracle price with freshness/staleness |
| UniswapV3PriceResolver | `uniV3Price` | Live V3 pool spot price (slot0 sqrtPriceX96) |
| UniswapV4PriceResolver | `uniV4Price` | Live V4 pool spot price (StateView.getSlot0) — additive to V3, both kept |
| AaveReserveResolver | `aaveSupplyApy` | Aave reserve rates (supply APY etc.) |
| CurvePoolResolver | `curvePool` | Curve pool get_dy quote + balances (stable pools) |

### A user's positions (the qualitative jump — not just prices, *your* holdings)
| Resolver | Kind | Renders |
|---|---|---|
| UniswapV3PositionResolver | `uniV3Position` | An LP NFT: pair, fee tier, tick range, liquidity, uncollected fees |
| AavePositionResolver | `aavePosition` | A lending position: collateral, debt, borrowing power, **health factor** (liquidation risk; `∞` when no debt) |

### Pre-trade + flow control
| Resolver | Kind | Renders |
|---|---|---|
| UniswapQuoteResolver | `uniQuote` | Expected swap output ("swap X → receive ~Y") before signing, via QuoterV2 |
| ApprovalStateResolver | `approvalState` | Whether a spender is approved for enough of a token — gates "Approve" vs "Swap" |
| PortfolioResolver | `portfolio` | An aggregated **total** summing many numeric reads (portfolio value across positions) |

### Generic (any protocol, no purpose-built resolver needed)
| Resolver | Kind | Renders |
|---|---|---|
| CallResolver | `staticread` | Any contract's view function — read any DeFi protocol, hook, or token |
| MultiCallResolver | `multiread` | Several reads joined side by side (a dashboard row) |

So for a protocol ChainRender doesn't ship a dedicated resolver for (Balancer, Compound, a new AMM), `staticread`
reads it generically — the purpose-built resolvers just add nicer formatting for the common cases.

### Intent orders (CoW Protocol)
Beyond spot swaps and positions, ChainRender renders **intent-based** DeFi — CoW Protocol's programmatic/conditional
orders — and verifies the document a user is about to sign, all as trustless `view` reads:

| Resolver | Kind | Renders |
|---|---|---|
| CowTwapResolver | `cowTwap` | a TWAP order's live schedule (part X/N, next-slice countdown, per-part limit) from its definition + `block.timestamp` |
| CowConditionalOrderResolver | `cowOrder` | live tradeability this block via a STATICCALL to the real **ComposableCoW**, fail-closed to `"not active"` |
| CowIntentVerifyResolver | `cowIntent` | on-chain `keccak256(fullAppData) == order.appData` → `"verified"` / `"app-data mismatch"` — "verify what you sign" |

These render the on-chain truth of an intent order; ChainRender never becomes the solver or the off-chain batch
auction. Full treatment, including the ⚙ client hook decoder, in **[Intent DeFi & CoW Protocol](./intent-defi-cow.md)**.

## What ChainRender can DECLARE (the action layer)

A DeFi action is a button with `action: {to, sig, value, args}`:
- **Swap** — `to` = router, `sig` = `swapExactTokensForTokens(...)` (or the V4/universal-router swap)
- **Approve** — `to` = token, `sig` = `approve(address,uint256)`
- **Deposit / withdraw / borrow / repay** — the protocol's method
- **Mint / claim / stake** — the same shape

The action layer enforces honesty:
- **Capability envelope** — a write action requires the app to declare `WRITE_CHAIN`; sending value requires
  `TRANSFER_VALUE`; batching (approve+swap) requires `BATCH_EXECUTE`; EIP-712 permits require `SIGN_MESSAGE`. The
  validator *rejects* an app whose actions exceed its declared capabilities, and rejects over-declaration too.
- **Bound interfaces** — an action can only call a `sig` on a `to` that the app manifest declares. No smuggled calls.
- **The action decoder** — before signing, the user sees a plain-English decode: *"Swap 1.0 WETH → 0x…, min out
  2950 USDC"*. Swaps carry an **honesty flag** because the raw params don't self-label the slippage minimum or the
  token path — so the decode tells the user to verify those.

## The honest, complete DeFi swap flow

Putting it together, a swap app on ChainRender does the honest thing end to end:

1. **Render the quote** — `uniQuote` (or `curvePool` get_dy): "you'll receive ~2950 USDC".
2. **Render approval state** — `approvalState`: show "Approve" if the router isn't approved, else "Swap".
3. **Declare the action** — the swap button, with a **slippage minimum** the user controls.
4. **Decode before signing** — the action decoder shows exactly what's being signed, with the swap honesty flag.
5. **Execute** — via the wallet (`eth_sendTransaction`); the swap runs on the DEX, not on ChainRender.

Every step is visible, every risk is flagged, and nothing is claimed beyond what the code enforces.

## The honest boundaries (read these)

- **Quotes and get_dy are ESTIMATES.** They reflect current pool state; the actual output can differ because price
  moves between the quote and execution. This is exactly why the swap action must still carry a slippage minimum —
  the resolver shows the expected output, it does not guarantee it.
- **Rendering is free; only *acting* costs gas.** A DeFi dashboard that only renders positions/prices costs the user
  nothing — it's a `view`. Gas is only spent when the user signs an action (swap, approve, deposit).
- **The resolver needs the protocol to exist on the target chain.** A resolver is correct code, but it can only
  return data if the Uniswap/Aave/Curve instance it points at exists on the chain you're on. See
  [Sepolia DeFi Addresses](./sepolia-defi-addresses.md) — Chainlink/Aave/Uniswap V3 exist on Sepolia; Curve is thin
  there and may need an L2/mainnet to test live.
- **ChainRender blesses no protocol.** The resolvers take the pool/feed/pool address as a caller argument —
  ChainRender doesn't endorse any oracle, DEX, or lending market; the app author chooses, and the user verifies.
- **No cross-chain position aggregation yet.** Rendering a user's positions *across* chains needs trustless state
  proofs. That machinery is live for **token balances**: [Proven Balances](./cross-chain-balances.md) proves a
  Sepolia token's balance on Sepolia and, since Milestone 2, on Robinhood Chain Testnet, against Sepolia's own
  state. Since Milestone 3 it also covers **already-deployed** tokens — a snapshot of the token's own `balanceOf`
  (`xchain-snapshot-balance`) or an adoption claim about its storage layout (`xchain-adopted-balance`, always ≤ C) —
  and Milestone 4 proves a hash-timelock swap lock (`swap-lock`). Multi-protocol *position* aggregation (LP shares,
  lending positions) is not built. Per-chain DeFi reads work today.

## What's NOT built (honest gaps)

- **Balancer resolver** — `staticread` reads Balancer's Vault generically today; a purpose-built one is a future add.
- **Uniswap V4 LP position** — V4's singleton architecture differs; the V4 *price* resolver exists, a V4 *position*
  resolver is a follow-up.
- **Curve crypto-pool (uint256 index) variant** — the shipped `curvePool` targets classic int128 stable pools.
- **Cross-chain position state** — not built. Cross-chain reads are live for token balances (Sepolia →
  Robinhood Chain Testnet, [Proven Balances](./cross-chain-balances.md)); DeFi positions across chains need
  per-protocol position adapters, which are designed (doc 175 §11.3) but not built.

## Trust grade for DeFi apps

DeFi reads are on-chain `view` calls, so a DeFi app that renders positions/prices/quotes grades **A (Trustless)** on
its data edge — the data is read from the protocol's own contracts, no off-chain dependency. Actions don't lower the
render grade (rendering stays a `view`); they're governed separately by the capability envelope. An app that pulled a
price from an *off-chain* API instead would grade ≤ C — but the ChainRender resolvers all read on-chain, so they
stay A.

## Payments

Beyond swaps and positions, ChainRender apps can take **payments** — a crypto payment (trustless, Grade A) plus an
optional card/fiat on-ramp (honestly graded off-chain) so non-native users can pay by card. See
[Payments](./payments.md).

> All the resolvers on this page are now deployed on **all three testnets** (Sepolia, Robinhood, Circle Arc), and
> they're **caller-supplied-address** — they read whatever pool/position/token the caller points at, and fail closed
> to `"unavailable"` if it isn't there.

## Where to go next
- **[Intent DeFi & CoW Protocol](./intent-defi-cow.md)** — render + verify CoW conditional/TWAP orders and "verify what you sign".
- **[Resolvers](./resolvers.md)** — how the resolver mechanism works in general.
- **[RWA Capabilities](./rwa-capabilities.md)** — Proof-of-Reserve, ERC-3643 permission display, credential lifecycle.
- **[Reputation Capabilities](./reputation-capabilities.md)** — EFP social graph, delegated vouching, aggregate, ERC-725Y/735 account reads (same-chain).
- **[Integrations & Libraries](../reference/integrations.md)** — every integration + library + SDK/skill/MCP at a glance.
- **[Actions & Signing](./actions.md)** — the declared-action model + the "you see what you sign" decoder.
- **[Rendering Uniswap Hooks](./rendering-uniswap-hooks.md)** — reading V4 hook state via `staticread`.
- **[Sepolia DeFi Addresses](./sepolia-defi-addresses.md)** — which protocols exist on Sepolia + per-resolver readiness.
- **[Trust Grade](./trust-grade.md)** — why on-chain DeFi reads grade A.
- **Reference: [Resolver Catalog](../reference/resolvers.md)** — every resolver + kind + args.
