Borrower
Your wallet, on the lending chain
Can
- Authorize LeveeUnwind with your trigger, target, price bound, collateral and pool
- Set the aToken allowance to it
- Revoke at once, without NEAR
Testnet
Four lines, one terminus
Levee repays your Aave debt from your own collateral when your health factor falls below a trigger you set. The position stays in your wallet, and every sale is checked on chain against your trigger and your price bound. This is the whole line, as specified and as measured on testnet.
Times are medians from the 7 testnet rescues from collateral. The square stop is the helper, LeveeUnwind, on the lending chain.
Your position · Base, once
Once, from your own wallet on Base: authorize(rescuer, maxSlippageBps, triggerHf, targetHf, collateral, poolFee) on LeveeUnwind, and a capped approval of the collateral’s aToken to it. There is no Safe, module or credit delegation. revoke() or a zero allowance stops it at once, without NEAR.
Keeper · Off chain
Every 5 seconds, from at least two RPC endpoints on Base or Arbitrum. It acts only when they agree within 0.5% and the reads are under 30 seconds old. One of the reserve-mode runs stopped here, because two RPCs disagreed.
Keeper · Off chain
Below your trigger, it works out the USDC repay that brings health factor back to your target, within your caps and your USDC debt, and quotes the sale on Uniswap’s QuoterV2 from every RPC. If the quote is past your price bound against Aave’s oracle, it stops and sends nothing. One testnet run stopped here. Otherwise it sets max_sold to the quote plus 0.5%.
Levee contract · NEAR
The keeper calls rescue_from_collateral(id, amount, max_sold, fees) with a key that can do nothing else. It sends no calldata, no target and no payload. The contract checks the per-rescue cap, the daily cap, the cooldown and the fee ceilings, then builds the transaction itself.
1.6 s to NEAR, median of 7. Slowest 1.9 s.
MPC network · NEAR Chain Signatures
The contract asks the MPC network to sign LeveeUnwind.unwind(borrower, collateral, amount, poolFee, maxSold) from the rescuer address derived for your position, path levee/v1/{id}. The borrower, collateral and pool fee come from your registration. Most of a rescue’s time is spent here.
5.2 s to signature, median of 7. Slowest 6.7 s.
Your position · Base or Arbitrum
The keeper checks the signer and broadcasts. Anyone could: the signature is public. On Base, LeveeUnwind requires health factor below your trigger, and the collateral and pool you authorized. The pool sends the USDC first; the helper repays your debt, takes the aTokens the pool is owed and withdraws them to the pool. The sale must be within your bound against Aave’s oracle and within max_sold, and health factor must rise without passing far beyond your target.
0.5 s to inclusion, median of 7. Slowest 1.6 s.
Keeper · Evidence
The keeper reads health factor again and writes the run to the evidence folder with its timings, transactions and the sale, whether it landed or not. The proof page is built from those files.
One terminus
LeveeUnwind.unwind(borrower, collateral, amount, poolFee, maxSold)The only call a rescue from collateral can make. The keeper sends a position id, an amount, max_sold and fees, and the borrower, collateral and pool are fixed at registration. On Base, before anything moves, the helper checks:
LeveeUnwind has no owner and cannot be upgraded.
To reach target T with debt D and borrowing capacity C × L, selling a collateral with liquidation threshold L_c at a total cost s, all in Aave’s base currency.
R = (T × D − C × L) / (T − L_c × (1 + s))
The keeper takes s as the pool fee plus your bound. The bound already includes the fee, so this counts it twice, and the keeper lands slightly above target. The 7 testnet rescues aimed at 1.80 and landed at 1.802 to 1.804. The helper’s bound allows exactly this. R is capped by your caps and your USDC debt, and the collateral it implies must fit your aToken balance and allowance. The trigger, the target and the RPC list are read from the helper and the keeper’s config. No language model is involved.
Each actor has one job. The helper on Base and the contract on NEAR enforce the limits, so a stolen keeper key stays inside them.
Your wallet, on the lending chain
The helper on Base. No owner
Key limited to rescue_from_collateral
levee-core-v2-1503.testnet
NEAR Chain Signatures
The NEAR account that registers
Worst caseA stolen keeper key can act only while your health factor is below your trigger, only on the collateral and pool you named, and not much past your target. Each sale is at most your bound worse than Aave’s oracle, up to the daily cap. It can also burn rescuer gas up to the fee ceiling. revoke() or a zero allowance stops it at once.
| A stolen keeper key tries to | Result | The rule that refuses it |
|---|---|---|
| Sell while you are above the trigger | Refused | LeveeUnwind reads your health factor from Aave before anything moves, and reverts at or above the trigger you set (AboveTrigger). |
| Sell other collateral, or in another pool | Refused | The collateral and pool fee are fixed at registration on NEAR, and the helper checks them against your authorize on Base (TermsMismatch). |
| Sell past your price bound | Refused | Each sale must be within your bound against Aave’s oracle (SlippageExceeded) and within max_sold (MaxSoldExceeded). The keeper can raise max_sold only up to your bound. |
| Sell far past your target | Refused | After the sale, health factor must have risen and must not pass far beyond your target (NoImprovement, OverSold). |
| Send funds anywhere else | Refused | rescue_from_collateral takes a position id, an amount, max_sold and fees. The contract writes the call itself, unwind repays only your USDC debt, and the sold collateral goes straight to the pool. Nothing stays in the helper. |
| Change the code | Refused | Neither contract account on NEAR has a key left. LeveeUnwind has no owner, no admin method and no upgrade. |
These are the rules in docs/SPEC.md, sections 2 and 9, and the claims ledger ties each to a test. Caps bound what gets signed. A signature already issued stays valid until its nonce is used, and it can still only repay the registered borrower’s debt.
Levee is one of several ways to protect a position in place. DeFi Saver protects Aave v3 positions held in an EOA on Base and Arbitrum, through a Safe operator and an aToken approval.
A rescue is a race, and it can be lost. These are the conditions we know of.
| Condition | What happens | What you see |
|---|---|---|
| The pool is too thin or off the oracle | The sale would pass your bound, so the keeper sends nothing. If the pool moves after the quote, unwind reverts and only gas is spent. | An aborted run, quote_over_slippage_bound. One testnet run stopped this way. In the backtest it was the commonest reason a liquidated position was missed in 10 to 11 Oct 2025. |
| A liquidator wins the race | A move can outrun the rescue, and a liquidator can act first once health factor reaches 1.00. | The run is recorded as failed, with its timings. |
| Another collateral at LTV 0 | Aave refuses the aToken transfer of any collateral with a non-zero LTV, so every unwind would fail. | The keeper records ltv_zero_collateral and sends nothing. Withdraw or disable that asset. |
| Collateral paused, or the sequencer down | The helper refuses paused or inactive collateral, and refuses while Aave’s price oracle sentinel stops liquidations. | unwind reverts, and nothing moves. |
| NEAR, the MPC network or the RPCs down | With no signature, or no agreed read, nothing is sent. | A rescue_failed event on NEAR, or no run at all. |
| Keeper down | The trigger is read by the keeper. If it stops, nothing fires. | No run at all. Silence is a failure too. |
| RPCs disagree | The keeper acts only when two endpoints agree within 0.5% and are under 30 seconds old. | The keeper holds until they agree. One reserve-mode run stopped this way. |
| Allowance used up, or no gas | The aToken allowance to the helper caps what it can sell, and the rescuer pays gas. | unwind reverts, or the transaction cannot be paid for. |
| A cap is reached | Per-rescue cap, daily cap and cooldown are checked by the contract. A rescue past any of them is refused. | The contract rejects the call, and a position may stay below its target. |
| Reserve mode: the reserve runs out | There is no USDC at the rescuer to repay with. | Applies only to the second mode. |
Every run on Base Sepolia, from one position. With this few runs the p95 is the slowest run. The keeper also reads every 5 seconds, which this table does not include. Nothing here has been measured on a mainnet or during a crash.
| Hop | From collateral, 7 runs | From a reserve, 13 runs | ||
|---|---|---|---|---|
| Median | p95 | Median | p95 | |
| Detection to the rescue call on NEARKeeper and NEAR | 1.6 s | 1.9 s | 1.7 s | 3.5 s |
| Rescue call to signatureMPC network | 5.2 s | 6.7 s | 5.3 s | 6.9 s |
| Signature to sentKeeper | under 0.1 s | under 0.1 s | under 0.1 s | under 0.1 s |
| Sent to includedLending chain | 0.5 s | 1.6 s | 1.5 s | 1.5 s |
| Detection to inclusionAll of it | 7.9 s | 9.2 s | 8.4 s | 10.2 s |
Every run, with its transactions, is on the proof page.
The same keeper and contract can repay from USDC held at the rescuer, with no collateral sold. The backtest found that the same USDC repaid upfront protects one position as well as a reserve, so the reserve is the second mode. Its last stop is planned, and its quote is live.
Levee contract · NEAR
The keeper calls rescue(id, amount, fees) with a key that can do nothing else. The repay is R = D - (C * L) / T, capped by the per-rescue cap, the rescuer’s USDC and allowance, and the USDC debt. The contract checks the same caps, cooldown and fee ceilings.
1.7 s to NEAR, median of 13. Slowest 3.5 s.
MPC network · NEAR Chain Signatures
The MPC network signs Pool.repay(USDC, amount, 2, borrower) from the rescuer address, which holds the USDC. No collateral moves.
5.3 s to signature, median of 13. Slowest 6.9 s.
Your position · Base or Arbitrum
The keeper checks the signer and broadcasts. Aave applies the USDC to your debt, and your collateral stays where it is.
1.5 s to inclusion, median of 13. Slowest 1.5 s.
NEAR Intents · Planned
Planned and not built. USDC held off the lending chain would go back to the rescuer through NEAR Intents, to pinned destinations only. It needs partner access. Until then the rescuer holds the USDC it repays with.
Dry quote. 20 USDC from Arbitrum to Base, asked of NEAR Intents 1Click from this page. Nothing moves, and the reserve layer is not built yet.
Asking for a quote.
Reserve terminus
Pool.repay(USDC, amount, 2, borrower)The only call a rescue from a reserve can make, from USDC held at the rescuer. The keeper sends a position id, an amount and fees, and the borrower is fixed at registration.
R = D - (C * L) / T
In this mode the keeper converts R to USDC at Aave’s oracle price, rounding up, and adds 2 base units, because Aave rounds the debt it burns down.
Both modes run on testnet. The rest is built and untested live, or planned, and this page says which.
| Phase | State | Scope |
|---|---|---|
| Repay from collateral | Built, live on testnet | The main mode. LeveeUnwind on Base Sepolia and Levee v0.2 on NEAR testnet: 7 rescues and 1 run the keeper stopped. |
| Repay from a reserve | Built, live on testnet | The second mode, from USDC held at the rescuer. Levee v0.1 on NEAR testnet: 13 rescues and 1 run the keeper stopped. |
| Arbitrum | Built, no live runs | The contracts support it, and fork tests cover both modes there. |
| Reserve layer | Not built | An off-venue reserve in a NEAR Intents Agent API wallet with pinned destinations. It needs partner access. The dry quote above is the route it would use. |
| Hyperliquid | Not built | The site reads Hyperliquid, but Levee does not act on it. Isolated positions would stay uncovered, because a credit to the account does not reach isolated margin. |
| Mainnet | Not deployed | No mainnet contract, no external audit and no reproducible build yet. On mainnet the last full-access key is deleted after deployment, as it was on both testnet contracts. |
The address tool places every position on one line by the price move that would liquidate it.
The order is a percentage move in price. It says nothing about likelihood: a 12% fall in WETH and a 43% rise in AERO share one line, and they are not equally likely.
On Aave the distance is 1 - 1/HF. It holds for volatile collateral against stable debt, when all collateral falls together and the debt keeps its value. The tool checks what each position holds and says when that is not the case. A wstETH position against WETH debt, for one, moves only when one asset moves against the other.
Repay figures use Aave oracle prices and assume no further price move. Levee repays USDC debt only, so the tool shows how much of a repay USDC debt can cover. A grey ring is a position Levee cannot reach.
On Hyperliquid, margin ratio is equity divided by maintenance margin, and liquidation is at 1.00. The account mode, from userAbstraction, decides where equity is read. Unified accounts keep it in the spot balance. Portfolio margin needs borrow caps and oracle prices, so those positions show without a ratio.
For scale: the worst 15-minute drops on 2025-10-10 were 11.74% for BTC, 13.02% for ETH and 28.8% for SOL, on Binance perpetual futures.
GET /api/risk?address=0x...&target=1.5 returns what the reading page shows. No key is needed.
The target is optional, from 1.05 to 3. Results are cached for up to 15 seconds, or 5 when some figures are missing, and one connection can make 30 reads a minute.
A bad address or target returns 400 with error.code. Past the limit it returns 429. If no source answers, the same shape comes back with status 503. A null is a missing figure, and it stays null. The shape below is shortened, and schema changes only when a field is removed or changes meaning.
{
"schema": "levee.risk.v2",
"address": "0x...", // EIP-55
"generatedAt": "...", // ISO 8601, UTC
"status": "ok", // ok, partial or unavailable
"target": 1.5, // health factor used for repay
"failures": [], // what is missing, and why
"nearest": { "venue": "aave.base", "standing": "open", "fall": 0.12 },
"aave": {
"base": {
"status": "ok",
"blockNumber": "...", // every figure was read at this block
"position": {
"standing": "open", // none, open, close or liquidatable
"healthFactor": 1.138, // null with no debt
"collateralUsd": 0,
"debtUsd": 0,
"liquidationThreshold": 0.84,
"dropToLiquidation": { "fraction": 0.12, "formula": "1 - 1/HF", "assumptionHolds": true },
"repay": { "target": 1.5, "usd": 0, "usdcDebtUsd": 0, "usdcCovers": true },
"reserves": { "collateral": [], "debt": [], "liquidationBonus": 0.05 },
"raw": { "healthFactor": "..." } // exact contract outputs
}
},
"arbitrum": {}
},
"hyperliquid": {
"status": "ok",
"mode": "unified", // standard, unified, portfolio, dex-abstraction or unknown
"marginRatio": 3.01, // equity / maintenance, null if not worked out
"pools": [],
"positions": [
{ "market": "BTC", "margin": "cross", "liquidationPrice": 0, "distance": 0.91, "covered": true }
]
}
}