Intent DeFi & CoW Protocol
Most DeFi is transactional: you sign a specific swap at a specific block. Intent-based DeFi is different — you express what you want ("sell 10 WETH for USDC over the next day, never below this limit") and a network of solvers competes to fill it. CoW Protocol is the canonical intent layer: its ComposableCoW framework lets a single signed order describe a programmatic or conditional order — a TWAP, a stop-loss, a good-till-cancelled limit — that becomes tradeable only when its on-chain conditions hold.
Intent orders are exactly the kind of thing users sign without being able to read. ChainRender's job here is the one it
always has: render the on-chain truth of the intent, and verify what the user is about to sign — trustlessly, as a
free view — and never pretend to be the solver, the settlement layer, or CoW's order book. Three resolvers cover
the lifecycle, each ownerless, immutable, view-only, and fail-closed.
The mental model: render + verify the intent, never become the auction
CoW settlement happens in an off-chain batch auction: solvers find coincidences of wants, and the winning
settlement is submitted to CoW's settlement contract. That auction is not something any eth_call can see, and
ChainRender does not fake it. What is on-chain and readable:
- The order definition — a TWAP/conditional order's parameters (schedule, limits) are deterministic data. Rendering
the schedule is pure arithmetic over that data +
block.timestamp. - Tradeability this block — ComposableCoW itself exposes a
viewthat returns the discrete order a conditional order would emit right now (or reverts if none is valid yet). That is a trustless read of "is this live?". - App-data integrity — a CoW order commits to a
keccak256of its full app-data document (metadata + pre/post hooks). Recomputing that hash on-chain proves the human-readable document you are shown is the exact one the order bound.
What is not a floor fact, and is never rendered as one: whether a batch will actually settle, at what price, and when — that depends on solver competition in the off-chain auction. A "ready/settled" badge would be a labelled client enhancement over CoW's Order Book API, not part of this on-chain floor.
cowOrder — live tradeability (the real ComposableCoW)
CowConditionalOrderResolver STATICCALLs the real ComposableCoW — getTradeableOrderWithSignature(owner, (handler, salt, staticInput), offchainInput, proof) — and renders the discrete GPv2Order the conditional order would emit this
block. When no order is valid yet (the normal "not yet executable" state), the call reverts and the resolver fails
closed to "not active" — never a fabricated order.
| kind | renders |
|---|---|
cowOrder |
a field of the tradeable GPv2Order this block — sell amount, buy amount, validTo, or partially-fillable — or "not active" |
Args are caller-supplied: abi.encode(composableCow, owner, receiver, salt, staticInput, offchainInput, proof[], sellDecimals, buyDecimals, field). Because the result is a view recomputable by anyone against the real ComposableCoW,
an honest tradeability read grades A (Trustless). The resolver renders what ComposableCoW returns — it does not
assert the order is registered, nor that a batch will settle it; it answers exactly one question: would this order be
tradeable right now?
ComposableCoW is deployed deterministically at the same address on every supported chain:
0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74. The resolver takes it as an argument — ChainRender hardcodes nothing.
cowTwap — the schedule (pure, trustless arithmetic)
CowTwapResolver decodes a TWAP order definition (TWAP.Data: part sell amount, minimum part limit, start t0,
number of parts n, interval t, and span) and projects it against block.timestamp to render the human schedule:
which part is active, the countdown to the next slice, the per-part sell size, and the per-part limit.
| kind | renders |
|---|---|
cowTwap |
part X / N, next-slice countdown, per-part sell amount, per-part minimum limit, or a status label |
Args: abi.encode(twapData, sellDecimals, buyDecimals, field). This is pure arithmetic over the definition plus the
block clock — nothing but block.timestamp is read, so it is fully recomputable via eth_call and grades A. The
honest caveat is stated on every card: cowTwap renders the schedule the definition encodes; it is not proof the
order was registered with ComposableCoW. Pair it with cowOrder (which does read the real ComposableCoW) for the full
picture — the schedule story next to live tradeability.
cowIntent — "verify what you sign" (on-chain integrity + a client decoder)
This is the user-protection piece. A CoW order commits to order.appData == keccak256(fullAppData) (per CoW's app-data
SDK). CowIntentVerifyResolver recomputes that hash on chain and compares it to the hash the order bound:
| kind | renders |
|---|---|
cowIntent (field 0) |
"verified" if keccak256(fullAppData) == expected, else "app-data mismatch" |
cowIntent (field 1) |
the computed keccak256 of the presented document, as hex |
Args: abi.encode(fullAppData, expected, field). Flip one byte of the document and "verified" becomes
"app-data mismatch". Crucially, the verdict is an integrity statement, never a safety one — it proves the document
you are shown is byte-identical to the one the order committed to; it never says "safe to sign." Grade A, fail
closed.
The ⚙ client decoder (cr-cow-intent.js)
A CoW app-data document carries the atomic plan — pre/post CoW Hooks, each {target, callData, gasLimit} — that will
run around the swap. On-chain JSON parsing is impractical, so decoding the plan into plain English is a client
enhancement (Grade ⚙), not a floor read. cr-cow-intent.js does exactly that, under strict rules that keep it honest:
- It only runs after the on-chain
cowIntentslot returned"verified". If the hash did not match, it refuses to decode — the document is not the one the order committed to. - It decodes known selectors (
approve,transfer,transferFrom,permit,withdraw,stake, …) into a readable step; any unknown selector is markedOPAQUEand surfaced, never guessed. - It fails closed and never emits "safe to sign." The worst case is an honest "this step could not be decoded — verify it manually."
This is the msg-712 / sig-1271 split in miniature: the trustless floor proves integrity (the bytes are the committed bytes), and a clearly-labelled client layer adds legibility (what those bytes do) over the already-verified document. The enhancement can only ever make a verified document more readable — it can never upgrade an unverified one.
Putting it together — the trustless order monitor
The Explorer ships two CoW example cards built entirely from these reads:
- Trustless CoW order monitor —
cowTwaprenders the schedule (live viablock.timestamp) besidecowOrder, which STATICCALLs the real ComposableCoW for live tradeability, failing closed to"not active". The schedule story next to the live-tradeability truth, with zero client trust. - Verify what you sign —
cowIntentshows a matching document rendering"verified"and a tampered hash rendering"app-data mismatch"side by side; the hook plan is decoded client-side (cr-cow-intent.js) only after the on-chain verdict.
Both are free eth_call renders — no server, no CoW API key, no indexer.
The honest boundaries (read these)
- Settlement is off-chain and is not rendered as a floor fact. CoW fills orders in an off-chain batch auction; whether/when/at-what-price a batch settles depends on solver competition. ChainRender renders tradeability and the schedule (both on-chain), not a settlement guarantee. A "settled/ready" badge would be a labelled client layer over CoW's Order Book API.
cowTwaprenders the definition, not proof of registration. It is the schedule the parameters encode; usecowOrderagainst the real ComposableCoW to confirm the order is actually live.cowIntentproves integrity, not safety. A"verified"document is the one the order bound — it is not a judgment that signing is wise. The decoder reinforces this: unknown calls areOPAQUE, and it never says "safe."- ChainRender blesses no order or handler. Every ComposableCoW address, owner, handler, and app-data document is a caller argument; nothing is hardcoded or endorsed.
What this is not
ChainRender is not a CoW solver, does not run or replace CoW's off-chain batch auction or Order Book API, does not custody funds, and does not settle trades. It renders the on-chain truth of an intent order and verifies the document behind it — the trustless half — and is deliberately silent on the off-chain auction it cannot see.
Deployed (Sepolia)
CoW intent-DeFi resolvers are deployed on Ethereum Sepolia (where ComposableCoW lives); they are portable to any
chain where ComposableCoW is deployed, since the ComposableCoW address is a caller argument. Verify against
deployment/additive/addresses.json before integrating.
| Resolver | Kind(s) | Sepolia address | Grade |
|---|---|---|---|
| CowConditionalOrderResolver | cowOrder |
0x752AcEd4a7D7bD9Bd604c3d7adD38373Eed3b6c1 |
A |
| CowTwapResolver | cowTwap |
0xF949E6fB52Df34Dcc86F674E51327567cD964395 |
A |
| CowIntentVerifyResolver | cowIntent |
0xCaa6E85510f6FDDA54Be92AaEb95e6779bdc1AB2 |
A |
| ComposableCoW (CoW Protocol, external) | — | 0xfdaFc9d1902f4e0b84f65F49f244b32b31013b74 |
— |
Where to go next
- DeFi Capabilities — the full render-and-declare DeFi model this builds on.
- Actions & Signing — the declared-action decoder;
cowIntentis its intent-order analogue. - The Floor — why integrity is the floor and the hook decode is a ⚙ enhancement.
- Trust Grade — why these on-chain reads grade A.
- Reference: Resolver Catalog — exact kinds + arg shapes · Integrations.