Sentinel

Autonomous liquidation network on the Agentic L1.

Sentinel coordinates four specialised agents around a single on-chain orchestrator. Two of them run as TypeScript binaries where milliseconds win MEV races; the other two run as Somnia native agents where validator consensus wins trust. Every transition lands as an event on chain.

New to the protocol? Open the dashboard for the live event stream, then drive a full case end to end with the deployer-gated Case Console panel.

Layout

Four agents. Two surfaces.

The split is deliberate. Detection and execution need to win speed races. Scoring and routing need to win trust battles. Sentinel does not collapse those into a single design.

The four agents

Off-chain · TypeScript

Watcher

Subscribes to LendingPool events over WSS, mirrors active borrower balances in memory, and polls health factor. When a position drops below threshold it submits the Scorer prompt through flagPosition.

On-chain · Somnia native

Scorer

Receives the position snapshot inside an inferNumber payload and returns a uint256 risk score in [0, 10000]. Below-threshold scores cancel the case without penalty.

On-chain · Somnia native

Router

Receives the scored position and returns the debt-to-cover amount in the debt asset's base units. Bounded by the reserve's close-factor cap so the Executor cannot over-liquidate.

Off-chain · TypeScript

Executor

Watches the Coordinator's Routed event and races every other Executor in the network to call execute(caseId). The first transaction in earns the settlement reward for the operator.

Two execution surfaces

Off-chain TypeScript binaries handle the latency-sensitive ends of the pipeline. The Watcher subscribes to LendingPool events over WSS and reacts to a position drifting below its health threshold inside a single block. The Executor races every other Executor in the network to call execute(caseId) the moment a case is Routed - whoever lands first earns the settlement fees for the operator.

Somnia native agents handle the trust-sensitive middle. Scorer and Router are invoked through ISomniaAgents.createRequest; a randomly elected three-validator subcommittee runs the inference, reaches consensus, and ships the result back as a callback transaction. The on-chain Response receipt is the trust anchor third parties cite.

Pipeline

Five transitions, every one an event.

The Coordinator advances each case through a deterministic state machine. Reaching the next state requires either a validator callback or a permissionless on-chain push - never a private off-chain decision.

Case state machine

None ─► Flagged ─(Scorer callback)► Scored ─(advanceToRouter)► Routed ─(execute)► Executed

                          └─(below-threshold score or revert)──► Cancelled

flagPosition opens a case and submits the Scorer prompt to the Somnia platform. After validator consensus the handleScorerResponse callback transitions to Scored or Cancelled (low score, agent error, or empty result). Any keeper - typically the same Watcher that flagged the position - then calls advanceToRouter to dispatch the Router request. After the Router callback the case is Routed and gated for execution.

Wire format

The Coordinator is a payload pass-through. Callers build the bytes off-chain in the exact shape the configured Somnia base agent expects. The agent today is llm-inference, which accepts an inferNumber(string,string,int256,int256,bool) calldata payload and returns a clamped 32-byte int256.

// Scorer payload: range [0, 10000]
encodeInferNumber({
  prompt: buildScorerPrompt(positionSnapshot),
  system: "Return a single integer between minValue and maxValue.",
  minValue: 0n,
  maxValue: 10_000n,
});

// Router payload: range [1, debtBalance * closeFactorBps / 10000]
encodeInferNumber({
  prompt: buildRouterPrompt({ ...positionSnapshot, score }),
  system: "Return a single integer between minValue and maxValue.",
  minValue: 1n,
  maxValue: closeFactorCap,
});
Both responses decode as int256 on the Coordinator and reject negatives with NegativeAgentResponse. The full encoder ships with the off-chain agent runtime under packages/agents/src/prompts/payload.ts and is shared between the Watcher and any keeper that calls advanceToRouter.

Lending

Aave-V2-lite, interest-free.

Sentinel ships with a minimal lending pool: one collateral reserve, one debt reserve, no interest accrual. Plain Solidity with the same liquidation math production protocols use.

Reserves

The pool tracks one collateral asset (WETH) and one debt asset (USDC) on the deployed testnet instance. Each reserve carries its own liquidation threshold, liquidation bonus, and close factor. The Coordinator can be re-pointed at additional reserves by the protocol owner without redeploying.

ReserveLiquidation thresholdLiquidation bonusClose factor
WETH75%5%-
USDC--50%

Liquidation math

Health factor is computed against the on-chain oracle:

HF = (collateralValueUSD × LT_bps / 10_000) / debtValueUSD

A position is liquidatable when HF < 1.
The Coordinator's flagPosition reverts above 1 with PositionHealthy(hf).

A liquidation seizes collateral worth debtToCover × (1 + bonus) and capped at the borrower’s remaining collateral. The Executor cannot cover more than debtBalance × closeFactorBps / 10_000 in a single pass - the Router enforces this in its own output range, and the LendingPool double-checks it at execute time.

Payout

60 / 30 / 10.

Every successful case routes its seized collateral through a single Splitter contract. The split is deterministic, on-chain, and pull-payment - no off-chain bookkeeping, no escrow contract upgrade path.

60%

Agent operators

Split four ways among Watcher, Scorer, Router and Executor of the case. Reputation-weighted; equal split when all scores tie.

30%

Protocol treasury

Owned by the AgentRegistry deployer at testnet. Held in the Splitter until withdrawn through a pull payment.

10%

Bounty pool

Reserved for community-submitted specialist agents. Held by the Splitter; release rules live with the AgentRegistry owner.

Splitter is asset-agnostic. The same contract handles WETH today and any future debt-token denomination as the protocol grows - no Splitter change required to support stage-3 Router output that includes a DEX swap path.

Trust

A counter, not a market.

Each agent ID has two counters on the Reputation contract: successes and failures. The score is a clamped affine of the two. The Coordinator is the only writer; every transition that closes a case credits all four participating agents.

function recordSuccess(uint256 agentId) external onlyCoordinator;
function recordFailure(uint256 agentId) external onlyCoordinator;
function performanceOf(uint256 agentId) external view
    returns (uint256 successes, uint256 failures, uint256 score);

// score = max(0, successes * REWARD - failures * PENALTY)

The Splitter reads the reputation score when distributing the agent tranche, weighting payouts toward operators that have historically settled cases without faulting. Agents with zero score still earn at parity if no other agent has a positive score - this seeds the system fairly for new joiners.

Try it

Drive a full case from the console.

The Case Console panel on the dashboard exposes every transition as a single signature. Connect the deployer wallet to unlock the oracle and flag actions; any wallet can deposit, borrow, repay and withdraw.

  1. Step 01

    Open Position

    Reset the oracle to $3,000, mint 10 WETH from the faucet, deposit, then borrow 15,000 USDC. Five sequential signatures, finishes in seconds.

  2. Step 02

    Crash Oracle

    Drop the WETH oracle to the price that puts the connected wallet's HF at 0.85. Computed from live position state, so it works for any borrower regardless of how much collateral they have accumulated.

  3. Step 03

    Trigger flagPosition

    Submit the Scorer prompt. The Coordinator dispatches a Somnia createRequest; the validator subcommittee callback lands within seconds, transitioning the case to Scored.

  4. Step 04

    Advance to Router

    Push the case forward. The Coordinator dispatches the second createRequest; the Routed callback lands within seconds, locking in the debt-to-cover.

  5. Step 05

    Execute

    Settle the case. LendingPool.liquidate runs, the seized collateral is forwarded to the Splitter, and Reputation credits +100 to all four participating agents.

  6. Step 06

    Close Position

    Clear any leftover debt and withdraw the remaining collateral. The console mints any USDC shortfall from the faucet, approves the pool, repays in full, then withdraws every unit of WETH - up to four signatures, each awaited before the next so the solvency post-check on withdraw always passes.

  7. Step 07

    Reset Oracle

    Restore the WETH price to $3,000 between runs so the next case starts from a clean slate.

In the autonomous configuration the Watcher binary observes Scored events directly and calls advanceToRouter without manual intervention. The Executor binary watches Routed and races to settle. Both processes are shipped under packages/agents in the source tree.

FAQ

Sharp questions, sharp answers.

Why split agents across two execution surfaces?
Detection and execution lose to MEV if they wait for validator consensus. Scoring and routing lose to opaqueness if they run on a private bot server. Sentinel does not collapse those into a single trade-off.
Is the Scorer running a real LLM?
Yes. Both Scorer and Router point at Somnia's public llm-inference base agent. A randomly elected three-validator subcommittee runs the inference and reaches consensus on the numeric result. Validator latency on the testnet is consistently under three seconds.
What happens if a Scorer prompt fails?
The Coordinator marks the case Cancelled and records a failure against the configured Scorer Sentinel agent ID. Failures decay the agent's reputation score and reduce its share of future Splitter payouts. No funds are at risk.
Can I replace the Watcher or Executor with my own?
Yes. Anyone can register a new agent through AgentRegistry, run a binary that subscribes to the relevant events, and race for the settlement reward. The Coordinator gates writes to flagPosition and execute on owned-agent checks but does not whitelist operators.
Why hasn't Sentinel registered a custom Somnia agent?
Custom agent registration on the Agentic L1 was not open for public use at the time of writing. Sentinel uses the public llm-inference base agent with role-specific prompts; the Coordinator's scorerSomniaAgentId and routerSomniaAgentId slots are owner-settable, so the cutover to a registered custom agent is a single transaction.
Built on Somnia. Watching, never sleeping.