
presign
Agents send the unsigned tx, get a risk verdict with data provenance. Stale data can't say safe.
Demo
About
An autonomous agent holding a key signs whatever its planner hands it. presign answers one question before that signature - is this safe to sign? - and returns the thing nobody else does: how stale the evidence behind the answer was. The whole project in one line, live on the landing page right now: same call to the Aave V3 pool, freshness budget 30s -> low same call, same data, same rules, budget 1s -> unavailable unavailable is a tier, not an error. A rule that cannot get fresh protocol data has no honest way to report "nothing found", so a green verdict without fresh evidence is impossible by construction. Everyone else returns a verdict computed on six-hour-old context that looks exactly like a fresh one. An agent POSTs an unsigned transaction (from, to, value, data, chainId). The service simulates it on a mainnet fork, reads the state diff, and runs four rules over it: approvals that are unlimited or reach a listed address, mutable logic behind a proxy, protocol invariants from indexed data, and unidentified counterparties. Back comes a tier, the findings, and provenance: which deployment answered, its lag behind chain head in seconds, and the age of the simulated block. CHECK IT YOURSELF - nothing here needs a key or an account: https://presign.dev three transactions judged by that instance while you read, with the freshness slider that produces the pair above https://presign.dev/quote?to=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 the price before payment, itemised: simulation plus one unit per indexed deployment the verdict will read. Try a different address and the price moves https://presign.dev/health live sources, the Substreams watch window, the journal topic https://presign.dev/llms.txt the same service written for an agent rather than a person https://hashscan.io/testnet/topic/0.0.10413192 every verdict this instance has issued, refusals included, timestamped by Hedera rather than by us. Same thing as raw JSON, if you prefer curl: https://testnet.mirrornode.hedera.com/api/v1/topics/0.0.10413192/messages?limit=5&order=desc https://basescan.org/address/0xCa73Fe3ccc9FB581Ef9C624a9D0B9EEAFAD0cDDa the address that pays The Graph for the data behind those verdicts https://github.com/n0ctr1/presign npm run safety - the rules over twelve undisputed mainnet contracts (12 low, zero refusals); npm run latency; npm run coverage BY TRACK The Graph - an operational layer over indexed data, not a subgraph query. Discovery is not rebuilt: a registry supplies candidates, and on top of it conformance is checked by issuing the real query, liveness comes from _meta against an independently obtained chain head, and selection is capability-bound - "which deployments can answer this rule right now within N seconds of lag". Proxy-upgrade history streams from Substreams. The layer ships standalone as an MCP server with a SKILL.md. Fail-closed makes it load-bearing rather than decorative: no fresh indexed data, no green verdict. Hedera - x402-gated per call through the Blocky402 facilitator, priced by the data each verdict actually reads and quotable for free beforehand. Every verdict, refusals included, is journalled to HCS under a salted commitment to the paying transaction: checkable without exposing the payer, impossible to backdate. The service also pays The Graph on Base over x402, so both sides of the cost of one answer are visible. Ledger - the device is not a notification. medium blocks until a human approves the decoded transaction on a Nano X, a decline reads as 6985 (a decision, not a fault), and high never reaches the device at all. Keys live in the Ledger Key Ring rather than a .env; a ring that refuses to decrypt stops startup instead of falling back to a plaintext copy. The signing broker buys its own verdict for the exact transaction rather than trusting the one a model handed it. The service never holds a key and never broadcasts. It advises; the signature stays where the key is.
How it's made
TypeScript throughout, an npm-workspaces monorepo of thirteen packages, no framework beyond Hono for the HTTP service. Simulation: an Anvil mainnet fork with 'debug_traceCall' and the prestate tracer in diff mode, so rules read the actual state diff rather than the calldata. That distinction is load-bearing - an approval buried inside a smart account's 'execute' is still an approval, and the diff shows it while the calldata does not. Mapping slots are resolved by computing keccak(key ‖ slot), with a bounded candidate scan; when candidates are truncated the rule returns 'unavailable' rather than a confident guess. The Graph is the data layer, and an operational layer sits on top of it. Discovery is not rebuilt - 'subgraph-registry' runs as an MCP subprocess and supplies candidates - but its reliability score is economics, not liveness. So conformance is checked by issuing a real query for the fields a rule needs, liveness comes from '_meta { block hasIndexingErrors }' compared against an independently obtained chain head, and selection is capability-bound: the question is not "what is this subgraph" but "which deployments can answer this rule right now within N seconds of lag". Lag is read from the same GraphQL document as the data it qualifies, so the number cannot drift from the answer. Proxy-upgrade history streams from Substreams over gRPC. The whole layer ships standalone as an MCP server with a SKILL.md, so another team can ask that question without touching the rules. Hedera carries the money and the record. Inbound payments are x402 through the Blocky402 facilitator on testnet; pricing is metered - a base charge plus one unit per indexed deployment the verdict will read, counted before payment and quotable for free at GET /quote?to=<address>. Outbound, the service pays The Graph on Base over x402 (EIP-3009, facilitator submits), so both sides of the cost of one answer are visible. Verdicts go to an HCS topic under a salted commitment to the paying transaction: checkable without exposing the payer, and impossible to backdate. Ledger is used as two primitives, not branding. Device Management Kit over node-HID clear-signs 'medium' escalations - the human sees on the device screen what is being signed, and a decline reads as 6985, a decision rather than a fault. Service secrets live in the Ledger Key Ring instead of a .env: the key ring is consulted before any file, and a ring that refuses to decrypt stops startup rather than falling back to a plaintext copy. Two things worth flagging as hacky-but-deliberate. First, the signing broker does not trust the verdict a model hands it - it buys its own verdict for the exact transaction and signs only through that, which is why each signature leaves two entries in the journal. Second, the escalation signs a non-broadcastable approval nonce rather than the transaction itself wherever a signature would otherwise be broadcastable. Everything claimed is a command: 'npm run safety' runs the rules over twelve undisputed mainnet contracts (12 low, zero refusals), 'npm run latency' times whole verdicts cold and warm, 'npm run coverage' counts conforming deployments by querying them. The false-positive run is a release gate - it exits non-zero if anything reaches 'high'.