About the project
TRY IT
Live demo: https://cerrojo-app.vercel.app
THE PROBLEM
Hand a payroll to an AI agent and it holds your keys. The only thing between the spreadsheet and your money is a paragraph telling the model to behave — and anyone who can type into a cell can argue with it.
HOW IT WORKS
The model proposes. WDK decides.
The model reads the spreadsheet and writes a proposed list of payments. It never signs, sends, holds a key, or learns the limits.
Every line is then judged by five policies registered with the WDK policy engine:
- Per-transfer cap: 500 USDT
- Daily cap: 1,500 USDT
- Recipient allowlist
- Token pin
- Transfer-only: every other wallet operation denied by default
Each run writes a receipt. Every line ends as executed, denied, or not attempted, and each denial names the policy, rule, and reason. If the three outcomes do not add up to the line count, no receipt is issued.
THE AGENT CHANNEL
Cerrojo is also an MCP server: nine tools, none of which send and none of which approve.
An agent's best outcome is a voucher that expires in 15 minutes. Funds move only when a person runs:
cerrojo aprobar <id> --live --confirmo
At that point, the policy engine is asked again.
A prompt cannot pay itself.
DOES IT WORK?
- One real transaction:
0xbd7b969752593948e034fcdea1837c521e33ca711b1b773e752172c62bae84c5— 150 USDT, Sepolia block 11,548,511. Proposed by an agent over MCP, approved by a human, re-validated by policy, signed by WDK. - Eval: 20 cases × 5 runs, 20/20. False permits: 0.
- Injection: Three poisoned cells, identical verdict on all 12 lines. Dangerous drift: 0.
- 166 tests, all offline. Point the RPC at a dead port and the limits still hold.
/proof#policies— Ask the lock about any payment, live, no account required./proof#agent— Config to point your own MCP client at the running engine.
WDK INTEGRATION
@tetherto/wdk1.0.0-beta.16@tetherto/wdk-wallet-evm1.0.0-beta.17@tetherto/wdk-cli1.0.0-beta.3
This is not a wrapper around one call:
registerPolicy()runs before any account exists.- Every verdict shown anywhere is the return value of
account.simulate.transfer(). - Mainnet uses
toReadOnlyAccount(), which has no write methods. cerrojo paridadhands Tether's own WDK CLI only the approved lines.
The WDK CLI itself has no cap and no allowlist — which is exactly why the lock sits in front of it. Permalinks are in the README.
NETWORK AND TOKEN
- Network: Ethereum Sepolia (
11155111) - Mock USD₮:
0xF60443fF8F3d1Dd9FB553f7735A9236eb4F01ee5 - Decimals: 6
- Source:
contracts/MockUSDT.sol
Minting is open so a clean clone can fund itself.
SETUP
cd code npm install cp .env.example .env node src/cli.js policy # the rules. No seed, no network needed node src/cli.js demo # the whole argument in six acts
LIMITATIONS
Dry run is the default. Exactly one live transfer has been executed.
The daily counter is ours, not WDK's: rule.onSuccess is inert in this beta. Full list in DEV.md.
Hacki