Arkify
Verified source, signed on Arkiv
Created on 15th October 2026
•
Arkify
Verified source, signed on Arkiv
The problem Arkify solves
When a block explorer marks a contract's source as "verified", people act on it. Users sign approvals because the source looks harmless, auditors review that source instead of the bytecode, and wallets repeat the badge. That badge comes from one operator's database, which can be wrong, compromised, pressured to remove an entry, or offline. We built a Soroban verifier before (Sorofy): its results lived in our own SQLite file, so we could have edited, deleted or invented any of them and no reader could tell.
Arkify removes that single point of trust and of censorship:
- Independent verifiers recompile the source with the official solc release and compare it with the deployed runtime bytecode. Each signs an attestation on Arkiv from its own wallet.
- Readers choose whose word counts. Only attestations whose on-chain
$creatoris in the reader's trusted list are counted. The filter runs on the Arkiv node, so a forged attestation from any other account is never counted, only shown apart as untrusted. - No green tick for a contradiction. A contract is Verified only when at least two trusted verifiers matched the same source, and Disputed if trusted verifiers disagree.
- Scoped to the code that runs. Every attestation carries the keccak256 of the code it checked, so it never carries over to different code at the same address.
- Readable without us. The web app is static files with no backend, and every page prints the exact Arkiv query and a
curlthat reproduces it. If our site and verifiers vanished, the answers would still be on Arkiv.
Live app: https://arkify-one.vercel.app · Demo:
Challenges I ran into
Each issue below is logged in arkiv/friction.md with versions and steps to reproduce.
- Our first create failed. The draft schema used camelCase attribute names (
chainId,codeHash). The SDK accepts them, but the Tiramisu engine rejects any uppercase letter, and the SDK's revert message even says uppercase is allowed (F-010). We moved to snake_case. - Solidity sources do not fit raw. The public RPC refuses bodies over about 256 KiB, which caps a payload near 129 KB once it is hex-encoded (F-011). A 2.1 MB multi-file input is 353 KB with gzip but 41 KB with brotli, so we compress with brotli. The SDK ships brotli but never uses it (F-002).
- A drained query budget looked like a hang. The anonymous RPC allows about 100
arkiv_querycalls per hour, and viem's transport silently sleeps for the fullRetry-After. Our verifiers froze with no error (F-013). We wrote a transport that fails fast and turns the 429 into "try again in N minutes". The web app needs about five queries per contract page and takes live updates from WebSocket events, which are not metered. - Events carry no attributes.
EntityCreateddoes not say which type was created, so a naive listener reads back every entity created on the chain (F-005). We derive each Arkify type's exact lifetime and creation flags from the event and drop foreign creates without a read. - A refused WebSocket handshake silenced the watcher for good. The gateway caps concurrent sockets per address, and the SDK's watcher never recovered (F-015). Our subscription owns the connection, reconnects with backoff, and catches up with a cursor-paginated scan.
- Compiling untrusted sources safely. A heavy solc-js compile could starve a verifier's heartbeat and leak memory. The engine runs in a child process with a timeout and a memory ceiling, and loads only official solc releases whose SHA-256 matches the official list.
- Three verifiers, one compiler cache. While recording the demo, one verifier attested
error. The three honest verifiers share a solc cache, downloaded a new compiler at the same moment, and collided on one temporary file. We reproduced it in a test, gave each download its own temporary file, and the next live request came back 3 of 3.
Tracks Applied (2)
