Permission to fill: how autonomous agents execute DeFi on the 1delta API
Two hackathon projects - Verato on Celo and USDT007 on Arbitrum - independently arrive at the same primitive: let an agent execute a user's lending strategy under cryptographic permission, and feed it the cross-protocol view it needs to decide via the 1delta API.

The first two articles in this series made a data argument: on-chain lending is fragmented, every protocol speaks its own dialect, and the 1delta API collapses 3,000+ disjoint markets into one queryable surface. That normalization is useful for a front-end. It turns out to be essential for an agent.
This piece is a case study - actually two. During back-to-back hackathons, two teams built the same thing on two different chains without sharing a line of execution code:
- Verato - a settlement gateway on Celo, built for the Synthesis hackathon. Live · source.
- USDT007 - "Permission to Fill" - a settlement primitive on Arbitrum One, built for the Tether WDK hackathon. Source.
Both let a user delegate complex DeFi operations - repay, withdraw, deposit, borrow, swap, leveraged rebalances - to an autonomous AI agent, without handing that agent the keys to their wallet. Both prove real migrations on-chain. And both share the unglamorous dependency we care about here: before an agent can execute anything, it has to decide - and to decide well it needs a clean read of the user's positions and every live rate on the chain. In both projects, that read comes from the 1delta API.
The delegation problem
Letting an agent manage your DeFi positions has, until now, meant one of two bad options:
- Grant blanket approvals and trust the agent (and its keys, and its prompt) not to misbehave. One bug or one prompt injection and the position is gone.
- Approve every transaction by hand, which defeats the entire point of automation.
Both projects give the same answer: make the permission cryptographic instead of custodial. The user signs a single off-chain EIP-712 order encoding a Merkle tree of permitted operations - every action they authorize, across as many destination protocols as they like. That one 32-byte root is the agent's entire mandate. An agent - a "solver," or in USDT007's framing a "filler" - can only execute an operation whose Merkle proof verifies against the user-signed root. It chooses which pre-approved route to take and when; it cannot deviate from the leaf set. Every settlement is atomic: it completes inside the user's safety bounds (health-factor floor, max fee, oracle-checked slippage) or it reverts whole.
No key delegation. No blanket approvals. Just cryptographically scoped permission - the user defines the boundaries, the agent optimizes within them.
That contract design is the trust layer. But a Merkle tree of permitted operations doesn't tell the agent which operation is worth doing. For that, the agent needs market data - and this is where most "agentic DeFi" projects quietly fall over.
Why an agent needs an aggregator, specifically
The decision both agents make is a yield migration: should the user's collateral (and debt) move from one lender to another for a better net rate? Answering that means knowing, for one account on one chain:
- every position the user holds - token, amount, USD value, and per-lender health factor;
- every pool on the chain - deposit APY, variable borrow APY, available liquidity, and whether the asset can be used as collateral or borrowed at all.
If an agent had to gather that itself, it would be re-implementing the exact normalization problem the first article describes - different ABIs, different rate encodings, different definitions of "health" - inside a Cloudflare Worker, per protocol, per chain. Neither team did. Both ship a thin portal proxy: a Worker that forwards to https://portal.1delta.io and injects the x-api-key as a server-side secret, so the agent (and the frontend) talk to one normalized surface without ever holding the key.
frontend / agent → portal-proxy (adds x-api-key) → portal.1delta.io
Behind that proxy, both agents hit the same family of endpoints:
| Endpoint | What it returns |
|---|---|
/v1/data/lending/pools · /lending/latest | Every pool/market on the chain - depositRate, variableBorrowRate, totalLiquidityUsd, collateral/borrow flags, underlying asset metadata, marketUid like AAVE_V3:42161:0x… |
/v1/data/lending/user-positions | The user's positions across every indexed lender, with health factor and per-token deposits/debt in USD |
Every record comes back in the same shape regardless of which protocol it originated from - Aave's getUserAccountData, a Compound V3 comet, a Morpho Blue market, a Silo V2 vault, Celo's Moola fork - all surface as the same position and pool objects. That uniformity is the whole point: the agent's logic never branches on "which protocol is this."
The two projects differ only in how they pull positions, and the difference is a nice illustration of the API's range:
- USDT007 uses the one-shot form -
GET /v1/data/lending/user-positions?account=…&chains=42161- and gets parsed positions straight back. - Verato uses a three-step handshake for maximum control:
GET /user-positions/rpc-callreturns a batch ofeth_callspecs (the API knows which calls to make across a dozen layouts); the agent executes them against any RPC it likes, retrying across endpoints; thenPOST /user-positions/parsedecodes the raw responses into normalized, USD-denominated positions. The API does the hard part - knowing what to call and how to decode it - while never needing your keys or a node of its own.
Either way, the agent ends up with the same thing: a clean, comparable read of the chain it can actually reason over.
From raw data to a decision a small model can make
Here's the part that makes these agents actually work. A raw positions response is a deeply nested blob - accounts, positions, underlying-asset records, oracle prices. You can hand that to a frontier model, but a lightweight model - the kind you want running cheaply in a loop - will choke on parsing it, and burn tokens doing so. So the agent inserts an interpret → evaluate step between the API and the LLM. Verato's pipeline is the clearest example:
Interpret collapses the API response into a flat summary: for each lender, the health factor, total deposits and debt in USD, NAV, and a sorted list of token balances. No oracle structs, no nesting - just the numbers a decision needs.
Evaluate then turns that summary plus the pool list into a ranked set of concrete migration candidates, and - crucially - it cross-references the order's Merkle leaves so it only ever proposes operations the user actually signed off on:
- Collateral-only (no debt): find a token the user can
WITHDRAWfrom lender A andDEPOSITinto lender B at a strictly higher deposit APY. Rank by improvement. No flash loan needed. - Cross-asset swap: same idea, but the destination pool is a different token, so the path includes an oracle-verified swap.
- Debt migration: the user has a leveraged position. Compute net yield -
(depositAPR·deposits − borrowAPR·debt) / NAV- at the source and at every permitted destination, and rank by the delta. Executing it needs a flash loan to atomically repay, withdraw, re-deposit, and re-borrow.
By the time anything reaches the language model, the hard analysis is done in plain, auditable TypeScript. The model's job is deliberately tiny - it's handed a flat list of pre-scored options and asked to pick the best one:
You are an AI settlement agent. All market data has been pre-fetched.
Your only job: pick the best migration option and call propose_migration once.
OPTION [0]: FROM Moola → TO AAVE_V3
improvement: +0.0182 (source net: 0.0121 dest net: 0.0303)
...
Pick the option with the highest positive improvement value.
If no option has improvement > 0, do NOT call propose_migration.
That's a decision a cheap, fast model makes reliably - because the data underneath it is normalized and comparable. Hand the same model three raw protocol responses and ask it to compute net yields across them, and reliability collapses. The aggregation layer isn't a convenience here; it's what moves the problem into a model's competence.
Same primitive, two ecosystems
What makes these two projects interesting together is that they took the identical core and pointed it at different stacks:
| Verato | USDT007 - Permission to Fill | |
|---|---|---|
| Chain | Celo mainnet | Arbitrum One |
| Hackathon | Synthesis | Tether WDK |
| Permission model | Merkle-scoped EIP-712 order | Merkle-scoped EIP-712 order |
| Data layer | 1delta portal API (3-step positions) | 1delta portal API (one-shot positions) |
| Protocols | Aave V3, Moola, Morpho Blue | Aave V3, Compound V3, Morpho Blue, Silo V2 |
| Swaps | Uniswap Trading API (oracle-verified) | Velora DEX (via WDK) |
| Reasoning | OpenAI / Anthropic | GPT-4o |
| Agent identity | Celo ERC-8004 reputation registry | open / permissionless |
| Wallet & infra | viem | Tether WDK modules |
| Fee | borrowed-amount surplus, capped by maxFeeBps | borrowed-amount surplus, capped by maxFeeBps |
USDT007's twist is the economically self-sustaining agent. Built on Tether's Wallet Development Kit, the agent isn't just a strategy loop - it's an autonomous economic actor that manages its own treasury between fills: it uses the WDK's Velora module to swap USDT→ETH when its gas balance runs low, deposits idle USDT into Aave V3 for yield, and runs GPT-4o portfolio reasoning each cycle to weigh swap costs, yield rates, and treasury health. It earns by borrowing slightly more than the user's original debt - the surplus is its fee, capped on-chain by the user's signed maxFeeBps. Because the protocol is permissionless, any agent can pick up an open order, and the ones that find better rates and cheaper gas earn more. The 1delta API is what lets every competing agent see the same honest, comparable rate surface to bid against.
What actually settles on-chain
Once an agent picks an option, it builds the multicall and submits it through the settlement contract. The contract re-verifies every operation's Merkle proof against the user's signed root, runs solver-provided calldata in a sandboxed environment (isolated from token approvals), checks swap outputs against an oracle within the user's signed tolerance, enforces zero-sum per-asset accounting, and checks the health-factor floor after all legs execute. Anything out of bounds reverts the whole bundle.
Both teams proved it on mainnet. Verato landed all three settlement shapes on Celo:
- Same-token collateral migration, Moola → Aave V3 (tx)
- Cross-asset swap + deposit - CELO → USDC via Uniswap, into Aave V3 (tx)
- Full debt-position migration with a Morpho flash loan, Aave V3 → Moola (tx)
And USDT007 ran a live fill on Arbitrum: agent 0xFE54…2148 filled a migration for user 0x0000…C6ff, took a 0.051515 USDT fee, and paid about $0.03 in gas (tx). In every one of these, the choice of where to migrate came from data the 1delta API served - and the safety of the execution came from the user's signed permissions.
The takeaway for integrators
Two teams, two chains, two wallet stacks, zero shared execution code - and they converged on the same architecture. That convergence is the lesson. Split any agent that touches lending into two layers:
- The trust layer decides what an agent is allowed to do - Merkle-scoped EIP-712 orders, fee caps, optional on-chain reputation. That's yours to design, and both projects show it's tractable.
- The data layer decides what an agent should do - and that needs a normalized, cross-protocol read of positions and rates. That's what the 1delta API is for.
The reason a lightweight agent can run this loop at all is that it never sees the fragmentation. It sees one position shape, one pool shape, one health factor, one comparable APY - across Aave, Compound, Morpho, Silo, and Moola alike. Everything the aggregation and Aave-unification articles built toward is, in the end, what lets an agent reason cheaply and act safely. The settlement primitive is the part that gets the headlines; the comparable data underneath is the part that makes it work.
Where to go next
- Verato - Synthesis listing · live app · source.
- USDT007 - Permission to Fill - DoraHacks listing · source.
- API reference - the
/v1/data/lending/*endpoints, response shapes, andx-api-keysetup both agents rely on. - Docs site - supported protocols, network coverage, and the rest of this series.