KEEL
docs

What Keel is, and how to use this site.

Everything on this site is explained here in plain language: the problem, the fix, what each page shows, and how to check the on-chain proof yourself.

Keel in one minute

On lending protocols like Aave, a loan is safe while its health factor (HF) stays above 1.0. If the collateral price falls far enough, the loan is liquidated and the borrower pays a penalty. So borrowers run defense bots: when HF drops to some trigger level, the bot adds collateral or repays debt.

The problem: everything the bot does is public. Watch when it acts and when it stays quiet, and you can work out its trigger, then push the price to that exact level to drain its reserve. Hiding the trigger in secure hardware does not help, because the bot's behavior still leaks the number.

Keel is a defense bot whose trigger cannot be worked out from watching it, and which still proves afterward that it followed one fixed, pre-committed policy the whole time. It runs as a Chainlink CRE confidential workflow, built for the ETHOnline 2026 Chainlink challenge.

The problem it solves

In the official challenge, health factor is a straight line in price: HF = price / 1794.87. The position opens at $2,000 (HF 1.114) and is liquidated near $1,795 (HF 1.00). The whole game happens inside that $205 window.

A bot with a fixed trigger gives one bit of information at every price level: it acted, or it did not. Each observation narrows the range where the trigger can be. Three or four well-chosen price pushes locate a fixed trigger to within a few dollars. After that, an attacker can tap the price to just below the trigger, force a spend, let the price recover, and repeat until the defender has nothing left for the real crash.

The bot's reserve is a public token balance, so the attacker always knows how much is left to drain. The only thing that can stay secret is when the bot will act, and only if it is built so that acting does not give the secret away.

How Keel works

1. The trigger moves, upward only

Keel's trigger is not one number. Each time the price changes, the trigger is re-drawn: a secret base level, plus a volatility term, plus a random offset derived from a secret salt. The offset only ever raises the trigger, so randomness can make Keel act earlier but never later. It never costs survival. And because every price level gets a fresh independent draw, no amount of watching narrows the base below the offset's width. The algorithm is public; the secrecy lives entirely in the salt.

2. The policy is sealed before the market moves

Before the scenario starts, Keel posts a hash of its entire policy (all parameters plus the salt) to a PolicyCommit contract on Sepolia. Think of it as a sealed envelope handed to the referee before the match. The policy cannot be swapped later without breaking the hash.

3. Every action carries a receipt, and the seal opens after

Each defense transaction is followed by an EIP-712 receipt, signed by a key derived from the same salt inside the enclave. After the challenge, Keel reveals the policy and salt. Anyone can then recompute every round's trigger from public price logs and check that every action, and every non-action, matched the sealed policy. That is the difference between private and provably unchanged.

Where it runs

The decision code runs inside a Chainlink CRE confidential workflow (handlerInTee, AWS Nitro enclave). Policy parameters, the salt, the wallet key and the RPC credential are Vault DON secrets, released only to the enclave. The handler reads the chain, decides, defends if needed, and reports a single word: IDLE, SAFE or DEFENDED. No number ever leaves the enclave.

Using this site

The three demo pages are a tour. Take them in order:

ReplayThe same falling market, played against two defenders side by side: the official starter bot (fixed threshold) and Keel (sealed policy).
  • 1.Pick a scenario and press PLAY. Each chart shows one bot's health factor falling as the price drops; markers are its defense actions.
  • 2.The colored strip under each chart is the attacker's live estimate of that bot's trigger. The starter's strip collapses to a point; Keel's stays wide.
  • 3.The scorecards use the official challenge scoring: surviving matters most, spending less capital and acting less often matter too.
  • 4.Switch the source to CHAIN to see Keel's real recorded Sepolia run, every action linked to Etherscan.
HunterA real Bayesian attacker that watches both bots across every market and then tries to drain them.
  • 1.The headline number is the “next-trigger band”: how precisely the attacker can predict each bot's next move. Smaller is worse for the defender.
  • 2.The starter's band collapses to a point: its fixed trigger is found and stays found. Keel's band is floored by its per-level random jitter, no matter how long the Hunter watches.
  • 3.Press ATTACK to watch the Hunter tap the price at the starter's discovered trigger, forcing spend after spend until the reserve is gone.
  • 4.The ×1000 toggle scales the dollar figures to a realistically sized position, where this attack is worth real money.
VerifyThe proof. Everything on this page is reconstructed live from Sepolia events by an independent verifier package.
  • 1.The verdict at the top is the whole story: ALL ROUNDS CONSISTENT means the sealed policy provably produced every action.
  • 2.Section 1 is the commitment: the policy hash was posted on-chain before any action, so it could not be swapped after seeing the market.
  • 3.Section 2 lists the signed receipts. Each signature recovers to the exact signer address committed up front.
  • 4.Section 3 is the reveal audit: each round's trigger is recomputed from public price logs and checked against what the bot actually did. Every row links to Etherscan.
PitchThe 10-slide story for judges.
  • 1.Arrow keys, scroll or the side dots step through the slides.

Glossary

Health factor (HF)How safe a loan is. Above 1.0 the loan is fine; at 1.0 or below it can be liquidated. Here HF = price / 1794.87, so HF is just the price in disguise.
bp (basis points)Hundredths of a percent. 100 bp of HF = 0.01 HF. A 300 bp band means the trigger is only known to within 0.03 HF, roughly a $54 price range.
Trigger / armThe HF level at which the bot defends. Keel re-draws it at every price level.
TargetThe HF level the bot restores to after defending, set above the trigger so it does not immediately re-fire.
JitterKeel's secret random offset, drawn per price level from HMAC(salt, level). Upward only: it can move an action earlier, never later.
HunterThe attacker model shipped with the project. It infers triggers from public data only, the same way a real stop-hunter would.
M1 / M2The Hunter's two models. M1 assumes a fixed threshold, which is right for the starter. M2 knows Keel's algorithm (threshold plus jitter) and still cannot narrow the base below the jitter width.
Posterior / bandThe attacker's belief about where the trigger is, after watching. A narrow band means the bot is predictable; a wide band means it is not.
Hunt priceHow deep an attacker must push the price to be ~90% sure of forcing the bot to spend.
CommitThe hash keccak(policy ‖ salt) posted on-chain before the scenario starts. Seals the policy without revealing it.
ReceiptAn EIP-712 message posted after each defense, signed by a key derived from the salt inside the enclave. Ties the action to the sealed policy.
RevealPublishing the policy and salt after the challenge, which lets anyone re-check every round against the commitment.
TEE / enclaveTrusted execution environment (here AWS Nitro). Hardware that runs code without even its operator seeing the data inside.
CREChainlink Runtime Environment: the platform that runs Keel's workflow on a decentralized oracle network, with secrets held in a Vault DON.

Verify it yourself

You do not have to trust this site. Three checks, all from public data:

  1. 1.The commitment came first. On PolicyCommit, the commit block number precedes the scenario start block. The policy was sealed before the market moved.
  2. 2.Receipts are signed by the committed key. Each receipt on Receipts recovers to the signer address stored with the commitment, and its action transaction sits at the previous nonce of the same wallet.
  3. 3.The reveal matches. After reveal, hash the revealed policy and salt: it must equal the on-chain commitment. Then recompute each round's trigger from public PriceUpdate logs and check every action against it. The Verify page runs all three checks live, but nothing stops you from doing them by hand.

Run it locally

The repo is public: github.com/sairammr/keel. No policy parameter or salt is committed anywhere in it.

git clone https://github.com/sairammr/keel && cd keel && bun install
bun run test          # 44 unit tests: controller + scenario + hunter
bun run e2e           # full lifecycle on a local Anvil chain, ends E2E PASSED
bun run tune          # grid search over policies vs starter baselines
bun run replay --vs starter   # text side-by-side replay
(cd app && bun run dev)       # this site on :3000

# CRE confidential workflow (simulation needs no deploy approval)
cre workflow simulate workflow --target staging-settings \
  --non-interactive --trigger-index 0

the handler only ever logs one word: COMMITTED / IDLE / SAFE / DEFENDED