
Tripwire
Self-hosted circuit breaker for smart contracts: checks all states, pauses before humans can react.
Demo
About
Tripwire is a circuit breaker for smart contracts that runs on your own machine. It watches your contracts on every block and transactions, checks safety rules you define, alerts you the moment one breaks, and can pause the contract before an exploit drains it. The problem: exploits run on block time, but incident response runs on human time. By the time someone notices, finds the signers and gets a pause through, the vault is often already empty. Most attacks take more than one transaction, so every block you shave off response time is money that stays put. How it works: you add a contract by address (the ABI is pulled from Sourcify) and describe what must stay true, for example "totalAssets never drops below totalBorrows", "the oracle is never more than an hour old", "price stays within 2% of its 20-minute average", or "OwnershipTransferred is never emitted". Rules can read contract state, decoded event arguments, history-aware metrics (TWAP, moving average, all-time high, windowed drops), values from other contracts, and simulations run on a local fork of the chain (for example "a 1 ETH withdrawal must not revert"). Every rule is checked against the live chain before it is saved. When a rule trips, Tripwire records the violation with its evidence (values, block, transaction), alerts you on Telegram, Slack, Discord, email or webhooks, and, if you allow it, calls your contract's own pause function with a key that holds pause rights and nothing more. The response is simulated before it is sent. You choose how far it goes: alert only, prepare the pause for a human to approve, or pause automatically. It also watches the mempool, so a harmful pending transaction can be flagged before it lands. It is one command (tripwire start): a native engine that follows the chain and signs responses, plus a dashboard, local API, CLI and an MCP server. Through MCP, an AI agent can read your verified contracts and propose rules; agent rules always arrive switched off and alert-only until a person turns them on. Your RPC, your database, your keys. No SaaS and no one else holding a key to your protocol. For the demo we deployed four contracts on Ethereum mainnet that mirror live protocols (Chainlink and Uniswap prices, Aave's WETH market, a Uniswap pool), each with a switch that breaks it on purpose. We drain the vault, Tripwire trips at block N and the vault is paused at block N+1, with no one pressing a button. The demo contracts can be found here and can be added to a users tripwire deployment for visual testing. Otherwise an identical set can be deployed by users for in depth testing: Mirror Feed: 0x6F056044835bfd063494BF4745A9a0ba517cc42B Mirror Vault: 0xc8BBaF62b62A5e49DCe39dc86842a524dCFB8148 Mirror Pool: 0xeCF93c65C853f44C529edc376088C815281c3763 Demo Token: 0x9C81A3336599E1FF5a847A6221C3fdC7AC66B7Db
How it's made
Tripwire was built spec-first. Our team has spent 8 years in the low-level blockchain space, and the main lesson from that time is that monitoring fails quietly: a dropped websocket, a missed reorg or a stuck transaction looks exactly like "nothing is wrong". So before writing code we wrote a spec sheet for every part of the engine: chain ingest, rules, storage, evaluation, metrics, the control interface, keys, response, notifications, mempool and release. Each sheet ends in a checkpoint proven against a real chain or a real database, not a mock. The app side got the same treatment, one spec per screen, and the rule language, the database views and the API are published as versioned contract files that both halves are built against. Architecture: two processes behind one command. The engine is Rust (tokio, alloy): it follows every block, keeps a local fork of chain state, evaluates rules, records history, holds the keys and signs responses. It is the only writer to Postgres. The app is a TypeScript monorepo (Fastify server, React dashboard with TanStack Router and Query, viem, a CLI and an MCP server). It installs and supervises the engine, serves the dashboard and a local API, and delivers alerts, but never touches the chain or a key. The two talk over a loopback control interface guarded by a per-install secret, and the app reads everything else straight from versioned SQL views. Because that boundary is a published contract (an OpenAPI file, a view reference and a JSON schema), the release pipeline refuses to ship an engine whose contract files drifted from what the app expects. The rule language: rules are JSON documents, not code, so they can be written by hand, in the dashboard's rule wizard, or by an AI agent, and validated the same way. Values are view calls, event arguments, arithmetic, sums, decimal scaling, block time, historical metrics (TWAP, moving average, all-time high, previous block, windowed change and drop) and fork simulations; conditions are comparisons, deviation bands, reverted simulations and boolean logic. All numbers are exact 256-bit decimals carried as strings, because JSON numbers silently lose precision past 2^53 and token amounts don't forgive that. Two safety properties are part of the language: anything that cannot be known yet (a metric still warming up, an RPC error) evaluates to false, so uncertainty never pauses your protocol, and validation returns every problem at once with its exact location, which doubles as the editor's error UI. Detection and response: each block is evaluated as one unit of work, with reorgs rolled back and re-evaluated, so a violation is recorded with the exact values, block and transaction that caused it. Rules that read simulations run the call on the local fork, so "a 1 ETH withdrawal must not revert" is checked every block without spending gas. When a rule trips, the response is built, simulated first (a pause that would revert is caught before it is sent, with the decoded reason) and then either held for a person to approve or signed and sent at once, with fee escalation if it gets stuck and a check that the pause actually took effect on chain. The response state machine is crash-safe: we killed the engine mid-flight at every stage in drills and it never sent a duplicate transaction. Pending transactions from the mempool are judged the same way before they land, as early warning on top of the block path, which stays the guarantee. Submission goes through private relays by default so an attacker watching the public mempool never sees the pause coming. The details of how candidates are picked, simulated and raced into a block are the part we keep closed. Keys and trust: keys are standard encrypted keystores, the passphrase is never stored or logged, and the dashboard reads the key's actual on-chain powers and warns if it holds more than pause rights. The engine ships as static binaries for x86-64 and ARM64 with minisign-signed checksums; the app verifies signature, checksum and version before it will run one. The rule compiler and ABI decoder were fuzzed for millions of runs and every dependency is checked against known vulnerabilities and licenses before a release. Partner and ecosystem tech: Sourcify gives us verified ABIs and source by address, which is what lets both the setup flow and the MCP server understand a contract with no copy-paste. The MCP server (Model Context Protocol) lets any AI agent list contracts, read their verified source and live values, and submit rules; every agent rule is validated by the engine, lands switched off and alert-only, and only a person can turn it on or give it pause power. The hacky bits: the default install needs no database at all. We run Postgres compiled to WebAssembly (PGlite) inside the app and put our own transaction-boundary pooler in front of it, so the Rust engine talks to it over the normal Postgres wire protocol as if it were a real server. Our demo contracts are "mirrors": their view functions read live mainnet contracts (Chainlink ETH/USD, Uniswap pools, Aave's WETH market) and apply a chaos layer lazily inside the view, so the charts move every block with no keeper bot, and a slow price bleed costs one transaction to start and nothing to sustain.