⚠️ Alpha · testnets only. ChainRender is in active alpha and deployed on testnets only — Ethereum Sepolia, the Robinhood Chain Testnet, and the Circle Arc Testnet — not on any mainnet. Contracts, addresses, and APIs may change. Do not use with real funds or production assets.
Concepts

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.

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 — 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 proves a Sepolia token's balance on Sepolia and, since Milestone 2, on Robinhood Chain Testnet, against Sepolia's own state. It covers tokens made by ChainRender's factory; proving an already-deployed token, and multi-protocol position aggregation (LP shares, lending positions), are 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); 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.

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