Tested on a Base mainnet forkMainnet launch is next. Every decision below was recorded on that fork.Follow the build
AGENTICAn AI treasury for tokenized stocks on Base

The AI agent that knows when not to trade.

Claude proposes every move. An onchain mandate weighs it against market hours, live prices and hard limits. One failed check and the vault says no, on the record.

CHECKS PER TRADE
9
TYPED REFUSALS
19
RULE TIMELOCK
24h
DECISION ENGINEreplay · Base fork · block 53,551,627
INTENT · PROPOSED BY CLAUDEBUY GOOGLc · $10
Sat 7 Nov · weekend
  1. Token allowedGOOGLc in mandatePASS
  2. Token not pausedtransfers activePASS
  3. Vault policyauthorizedPASS
  4. Market sessionSaturday · NYSE closedFAIL
  5. Feed freshnessnot reachedSKIP
  6. Multiplier stablenot reachedSKIP
  7. DEX premiumnot reachedSKIP
  8. Size limitsnot reachedSKIP
  9. Concentrationnot reachedSKIP
VAULT DECISIONRefused
MARKET_CLOSEDDecision logged · gas 111,116
BUILT ONBaseB20 stocksChainlinkAerodromeAave V4Coinbase CDPClaude
The problem

Tokenized stocks trade 24/7. Their prices don't.

An agent that only reads a DEX price will buy on a Saturday, chase a pool that drifted from fair value, or trade through a stock split. Maat turns each trap into a rule the contract enforces.

01 · MARKET HOURSMARKET_CLOSED

The price feed sleeps every weekend.

MonTueWedThuFriSatSunfrozenfeed liveNYSE 09:30–16:00 ET

The vault reads the NYSE calendar onchain, holidays and early closes included. No session, no trade.

02 · PREMIUMPREMIUM_TOO_HIGH

The pool can drift from fair value.

AAPLc29 bpsGOOGLc49 bpsNVDAc53 bpslimit 100 bps

Each buy compares a 30-minute Aerodrome TWAP with Chainlink. We measured these premiums in session before setting the limit.

03 · CORPORATE ACTIONSMULTIPLIER_COOLDOWN

A split quietly changes the math.

NVDAc · uiMultiplier1.000537939576369481
change detected24h pause

When the B20 multiplier moves, the vault records it and pauses that token for 24 hours while prices settle.

How it works

The model may advise. The contract decides.

Claude never holds the keys to the rules. It writes intents. The vault checks them against a mandate it cannot change, then emits a Decision either way.

  1. 01Intent[]

    Claude proposes

    Every 15 minutes in session, Claude reads the vault, the market and the mandate, and returns intents with a rationale.

  2. 02eth_call

    Preview as executor

    Each intent is simulated against the live contract from the executor address, under the exact rules that will apply.

  3. 03execute()

    The vault weighs it

    Nine checks in order, from market session and feed age to premium, caps and weight. Credit moves also check health factor. One fails, it stops.

  4. 04Decision

    Recorded either way

    Allowed or refused, the Decision event lands onchain with its reason code, the rationale hash and a Builder Code.

IMandateVaultEvents.solsolidity 0.8.28
event Decision(
    bytes32 indexed intentId,
    Action  action,
    address indexed token,
    uint256 amount,
    bool    allowed,
    Reason  reason,
    bytes32 rationaleHash
);
DECODED · SAT 7 NOV · BASE FORK
action
BUY
token
GOOGLc
amount
10.00 USDC
allowed
false
reason
MARKET_CLOSED
rationaleHash
[from mainnet tx]

Every transaction carries a Base Builder Code (ERC-8021), so each decision is attributable to Maat onchain.

Refusals

Nineteen typed ways to say no.

A refusal is not an error log. It is a reason code inside the Decision event, readable by anyone, from a dashboard or another agent.

Market

5
  • MARKET_CLOSED
  • FEED_STALE
  • BAD_PRICE
  • PREMIUM_TOO_HIGH
  • MULTIPLIER_COOLDOWN

Token and policy

5
  • VAULT_PAUSED
  • ACTION_NOT_SUPPORTED
  • TOKEN_NOT_ALLOWED
  • TOKEN_PAUSED
  • POLICY_BLOCKED

Limits

4
  • SIZE_LIMIT
  • CONCENTRATION
  • INSUFFICIENT_BALANCE
  • PAYEE_NOT_ALLOWED

Credit

3
  • HEALTH_FACTOR_LOW
  • DERISK_WINDOW
  • CREDIT_FAILED

Execution

2
  • SWAP_FAILED
  • TRANSFER_FAILED
The decision ledger

Every answer is public. Especially no.

TIME (ET)INTENTDECISIONNOTEGAS USED
Thu 5 Nov 10:30BUY NVDAc · $20ALLOWED · OKNVDAc under its 33% target weight.758,192
Thu 5 Nov 10:30SUPPLY NVDAc · $15ALLOWED · OKPosted as collateral on Aave V4.286,707
Thu 5 Nov 10:30BORROW USDC · $5ALLOWED · OKCompute runway, health factor above 2.0.484,173
Sat 7 NovBUY GOOGLc · $10REFUSED · MARKET_CLOSEDWeekend. Refused and logged once.111,116

Recorded by the agent loop on a fork of Base mainnet at block 53,551,627, against the real B20 tokens, Aerodrome pools and the Aave V4 Equities Hub. Mainnet rows will link to Basescan.

The mandate

Rules the agent can't loosen.

The owner commits the mandate onchain. Any change is queued in public with its full contents and waits 24 hours, so neither the agent nor a stolen key can relax a limit in the moment.

  • timelock 24h
  • executor can only call execute()
  • mandateHash [after deploy]
mandate · Maat #1Base mainnet
sessionMode
REGULAR
maxStaleness
3600 s
maxPremiumBps
100
maxSlippageBps
100
twapWindow
1800 s
multiplierCooldown
24 h
perTradeCapUsd
$50
dailyCapUsd
$100
maxWeightBps (per token)
4000
minHealthFactor
1.5
targetHealthFactor
2.0
deriskWindow
8 h before Fri 20:00 ET
The treasury loop

An agent that pays its own way.

  1. 01 · EARN

    x402 revenue

    Other agents pay about one cent to ask whether a stock trade is safe right now. USDC lands in the vault.

  2. 02 · BUY

    B20 stocks

    Equal-weight NVDAc, GOOGLc and AAPLc, rebalanced past a 5% drift, only in session.

  3. 03 · SUPPLY

    Aave V4

    Stocks become collateral on the Equities Hub.

  4. 04 · BORROW

    USDC runway

    A small loan covers compute, never below the target health factor.

  5. 05 · PAY

    Its own bill

    Claude usage is paid onchain to an allowlisted payee.