Lucas de Almeida

Aegis

Spending limits for an AI agent's wallet: small payments go through, large ones wait for a human.

Context
Solana Student Hackathon, 2025
Stack
Rust, Anchor
Links
codedemo

The problem

AI agents are starting to hold keys. An agent with a hot wallet and a swap router can drain itself in one bad loop, or be steered into a manipulated pool. Aegis puts the guardrails on-chain, where the agent can't talk its way around them.

How it works

One Anchor program with three parts:

  • Policy vaults. An agent's funds sit in a vault with a daily spending limit and a large-transaction threshold. Swaps under the threshold run immediately; above it they become a PendingAction that a human must approve; anything over the daily limit is rejected.
  • Constant-product AMM. Pools with configurable fees, LP tokens, and a minimum first deposit so the pool can't be initialised at a manipulated ratio.
  • Oracle checks. A Pyth reader with a configurable staleness bound, meant to compare the pool price against the market before a swap goes through.
agent ── request_swap(amount) ──► daily window reset? ──► over daily limit → reject
                                                     └─► over threshold   → PendingAction
                                                     └─► otherwise        → swap
human ── approve_pending_action ──► swap

Design decisions

  • The 24-hour window resets from on-chain time. The vault stores last_reset_timestamp from the Clock sysvar, so an agent can't fake the clock.
  • The threshold must sit below the daily limit, checked at vault creation, so every vault has a path where a human sees a large trade.
  • Swaps take min_amount_out. Slippage protection is enforced in the program, not left to the client.

What could go wrong

The spending policy was the whole point of the project, and it wasn't reachable: the vault instructions weren't exported from the program, swaps were simulated, and pending actions could be any account passed in by the caller.

VectorStatus
Policy not reachableFixed: vault instructions are part of the program and move real SOL
Pending action overwrittenFixed: each request is its own account at [action, vault, nonce]
Approval paying the wrong addressFixed: approval pays only the destination recorded in the request, with a test
Agent approving itselfFixed: approval is bound to the owner's key; tested
Vault drained below rentFixed: payouts stop at the rent-exempt minimum
Sandwich and slippage on the AMMMitigated: min_amount_out enforced on every swap
Oracle not compiledOpen: the Pyth reader still isn't wired in

Where it stands

A hackathon project, reworked and redeployed to Solana devnet. The vault has 8 tests and a page where you play the agent and the owner. The older AMM pages are hidden: they pointed at pools from the first deployment, which the new program doesn't have.