Search projects, hackathons, sponsors and tech

    ← All projects

    Plain Safe

    A local-first, privacy-focused Safe multisig UI with no backend.

    Demo

    About

    Plain Safe is a static, local-first interface for Safe multisigs. It replaces the hosted transaction service with a direct connection to an RPC chosen by the user. Add or create a Safe, build a transaction, review the exact call and its hashes, collect owner signatures through a link, code, or JSON file, and execute once the threshold is met. A co-signer can open a shared transaction and recompute its hashes and recover its signatures before connecting a wallet or making a network request. The review screen checks the Safe proxy and implementation against known code hashes, decodes calldata, highlights sensitive actions such as owner changes and delegatecalls, and simulates execution where the RPC supports it. It displays the EIP-712 domain hash, message hash, and Safe transaction hash so signers can compare them independently. The app also offers token balances, a local queue, onchain history rebuilt from RPC logs, an offline Verify page, and Uniswap swaps quoted from onchain contracts. There is no backend, analytics, or Safe Transaction Service. An in-app network guard allows the chosen RPC by default, blocks other destinations unless the user enables an explicit capability, and shows every attempted request in a live log. The app can be built as static files and distributed through IPFS.

    How it's made

    Plain Safe is a Vite/React/TypeScript static app. viem handles chain reads, Safe transaction hashing, ABI encoding and decoding, and contract calls; wagmi is used only for wallet connection, signing, chain switching, and sending transactions. Effect provides schemas for validating saved records and shared packages and services for RPC-backed work. IndexedDB stores settings, Safes, the transaction queue, and local history. TanStack Query coordinates reads, and wouter handles fragment routes so a compressed transaction package can travel after the URL's # without being sent to the host. We built a network guard that installs before the app and wraps fetch, WebSocket, XMLHttpRequest, EventSource, and sendBeacon. It starts with an empty allowlist, logs allowed and blocked attempts, and permits only configured RPC origins plus capabilities the user enables. Safe authenticity is inferred from the proxy and singleton bytecode hashes rather than trusting VERSION(). Imported packages are schema-checked, all three EIP-712 hashes are recomputed, signatures are recovered, and owners are checked against pinned-block chain state. Safety warnings come from decoded calldata rather than descriptive text. Simulation uses eth_simulateV1 where available and a Safe fallback otherwise. The Uniswap flow reads v3/v4 quotes onchain and builds a transaction, then decodes Universal Router commands for review. A Web Worker scans Safe events backward to reconstruct onchain history without an indexer. Tests cover pure transaction logic and Mainnet integration paths; the release tooling computes a reproducible IPFS CID.