Pre-signing transaction review for MetaMask users, powered by Sourcify verified contract intelligence.
SignGuard is a browser-extension-first transaction safety layer. It pauses a MetaMask-compatible request before the final wallet confirmation, analyzes the transaction with deterministic evidence, explains the result at the right depth for the user, and then lets the user either continue in MetaMask or stop the request.
The current MVP focuses on one practical signing problem: MetaMask can show calldata and contract prompts, but users still need a clear answer to questions like "What am I allowing?", "Who is the spender?", "Is this a proxy?", "Was the contract verified?", and "Does verified source expose risky privileged capabilities?" SignGuard answers those questions with Sourcify data, RPC simulation, deterministic risk rules, and optional AI narration that never becomes the source of truth.
- Why This Matters
- Current Product Snapshot
- Sourcify Bounty Fit
- User Flow
- System Architecture
- Analyzer Pipeline
- Repository Layout
- Quick Start
- Browser Extension Demo
- Backend And AI Proxy
- Swarm Audit Storage
- MetaMask Snap Demo
- SDK Usage
- Environment
- Quality Checks
- Troubleshooting
- Known Limitations
- License
In 2025, Web3 losses again showed that the weak point is often the signing moment, not the chain itself. CertiK reported more than $3.35B lost across hacks, scams, and exploits, with phishing as the most frequent attack vector: 248 incidents and more than $722M in losses. Scam Sniffer also reported wallet-drainer phishing affecting more than 106K users, including a $6.5M single theft through a Permit signature.
SignGuard focuses on this moment before confirmation. Instead of asking users to understand selectors, approval calldata, proxy contracts, and raw addresses, it gives them a structured review of what the request can do and what evidence supports that conclusion.
Sources: CertiK 2025 Web3 Security Report, Scam Sniffer 2025 phishing report.
The current version is centered on the browser extension in apps/browser-extension.
Main capabilities:
- Intercepts MetaMask-compatible
eth_sendTransactionrequests before MetaMask continues. - Opens a SignGuard transaction review popup or reuses the main extension surface.
- Lets the user select expected intent before analysis, such as approve, swap, bridge, mint, send, stake, claim, connect/login, or not sure.
- Compares expected intent with detected operation and surfaces mismatches.
- Runs the analyzer through
@analyzer/sdkwith Sourcify lookup and RPC simulation. - Shows three explanation levels:
Beginner: plain language and minimal technical burden.Regular: wallet-user details about assets, permissions, simulation, and contract identity.Developer: deterministic evidence, decoded calldata, trace graph, effect graph, Sourcify data, ENS, risks, raw evidence, and copyable technical values.
- Adds a floating transaction Q&A panel for all explanation levels.
- Stores local Activity history and opens full details for past reviews.
- Saves and restores audit reports through Swarm when Bee is available, with local fallback when it is not.
- Uses optional backend AI only for explanation wording and Q&A. Deterministic analysis remains usable without an LLM.
Sourcify is a central component of SignGuard, not a cosmetic "verified" label.
The analyzer uses Sourcify's verified contract data for:
-
ABI decoding
SignGuard fetches verified ABI data from Sourcify and decodes calldata against the target contract. If Sourcify exposes proxy resolution, the analyzer also tries the implementation ABI and marks the decode source as
sourcify-implementation. -
Proxy resolution
The analyzer uses Sourcify proxy data to identify when the user is interacting with a proxy shell and to fetch implementation contract metadata.
-
Source-level capability detection
Verified source files are scanned for risky capabilities such as privileged token recovery,
selfdestruct, blacklist/blocklist controls, pause controls, minting logic,tx.originauthentication, and signature replay patterns. -
Contract metadata and identity
Compiler metadata, match status, contract name, optimizer settings, verification timestamp, ABI functions, and Sourcify source URLs become part of the normalized
ContractInfo. -
Source-grounded AI explanation
When AI narration is enabled, the backend receives compact deterministic evidence and relevant source excerpts. It can explain verified source findings, but it cannot invent risk severity, amounts, addresses, or final recommendations.
Relevant implementation:
| Area | File |
|---|---|
| Browser Sourcify provider | packages/sdk/src/providers/sourcifyProvider.ts |
| Backend Sourcify provider | packages/sdk-backend/src/providers/sourcify.ts |
| Contract metadata normalization | packages/core/src/analysis.ts |
| Source-pattern risk rule | packages/core/src/risks/sourcePatterns.ts |
| Analyzer orchestration | packages/core/src/explainer.ts |
The Sourcify request shape is:
GET /v2/contract/:chainId/:address?fields=all
flowchart TD
dapp["dApp calls window.ethereum.request"]
hook["SignGuard MAIN-world hook pauses request"]
content["Content script forwards request"]
bg["Background worker stores request"]
review["Transaction Review opens"]
intent["User selects expected intent"]
analyze["SignGuard analyzes request"]
ui["Beginner / Regular / Developer review"]
qa["Optional transaction Q&A"]
decision{"User decision"}
mm["Continue in MetaMask"]
stop["Reject original request"]
dapp --> hook --> content --> bg --> review --> intent --> analyze --> ui
ui --> qa
ui --> decision
decision -->|Continue| mm
decision -->|Stop| stop
The key product behavior is that MetaMask remains paused until the user decides. If the user continues, SignGuard returns the original provider request back to the dApp and MetaMask opens normally. If the user stops, the original request is rejected.
flowchart LR
subgraph Browser["Browser extension"]
inject["MAIN-world provider hook"]
content["Isolated content script"]
worker["Service worker"]
popup["Popup / side panel UI"]
history["Local activity history"]
end
subgraph Analyzer["Analyzer stack"]
sdk["@analyzer/sdk"]
core["@analyzer/core"]
presentation["Presentation model"]
end
subgraph Backend["Optional backend"]
proxy["@analyzer/sdk-backend"]
ai["OpenAI / Anthropic compatible LLM"]
end
subgraph External["External evidence"]
sourcify["Sourcify API"]
rpc["JSON-RPC simulation endpoint"]
swarm["Swarm Bee node"]
end
inject --> content --> worker --> popup
popup --> sdk --> core --> presentation --> popup
sdk --> sourcify
sdk --> rpc
popup --> proxy --> ai
popup --> swarm
popup --> history
The core analyzer is pure TypeScript. It does not perform network calls directly. Runtime packages inject providers for Sourcify, RPC simulation, optional selector registry lookups, optional ENS enrichment, optional phishing lists, and optional narration.
The diagram below shows the internal analyzer flow: contract intelligence, ENS checks, Sourcify source verification, simulation analysis, evidence synthesis, risk analysis, and explanation generation.
Core guarantees:
- Deterministic fields are the source of truth:
effects,risks,recommendedAction,auditLog, andauditHash. - LLM output is presentation only.
- Sourcify failures do not abort analysis; they reduce confidence.
- Selector-registry fallback is conservative and does not decode arguments.
- The audit hash is independent of audience-specific wording.
.
|-- apps/
| |-- browser-extension/ Current primary SignGuard UX
| |-- drainer-demo/ Demo dApp and analyzer graph surface
| |-- metamask-snap/ MetaMask Flask Snap demo
| |-- metamask-site/ Local Snap install/config site
| `-- contracts/ Foundry scenarios and exploit/safe-path tests
|-- packages/
| |-- core/ Pure deterministic analyzer engine
| |-- sdk/ Browser-safe SDK
| |-- sdk-backend/ Server SDK, AI proxy, CSV/audit helpers
| `-- sdk-swarm/ Swarm audit storage and verified fetch helpers
|-- scripts/dev/ Local demo orchestration scripts
|-- docs/
| `-- signguard-analysis-architecture.svg
|-- package.json
`-- README.md
Requirements:
- Node.js
>=18.6.0(.nvmrccurrently uses Node20) - Yarn
3.2.1 - Chrome or Chromium for the browser extension demo
- MetaMask installed in the browser
- Optional: Bee CLI for Swarm upload demos
- Optional: MetaMask Flask for the Snap demo
- Optional: Foundry for Solidity scenario tests
Install dependencies:
yarn installFor Windows PowerShell, use yarn.cmd if script execution blocks yarn.ps1:
yarn.cmd installBuild the Chrome extension:
yarn build:extension:chromeWindows PowerShell:
yarn.cmd build:extension:chromeLoad the extension:
- Open
chrome://extensions. - Enable Developer mode.
- Click
Load unpacked. - Select
apps/browser-extension/dist. - Reload the dApp tab after loading the extension.
Run the extension dev stack:
yarn dev:extensionThis starts the extension build/watch flow, SDK backend, optional local Swarm Bee, and demo dApp.
Useful extension commands:
yarn workspace @analyzer/extension build:chrome
yarn workspace @analyzer/extension build:firefox
yarn workspace @analyzer/extension watch:chrome
yarn workspace @analyzer/extension watch:firefoxAfter every rebuild, reload the unpacked extension in chrome://extensions.
The backend package is optional for deterministic analysis, but required for AI-generated beginner/regular copy and Q&A.
Run the local backend:
yarn workspace @analyzer/sdk-backend serveWindows PowerShell:
yarn.cmd workspace @analyzer/sdk-backend serveLocal endpoints:
| Endpoint | Purpose |
|---|---|
GET /healthz |
Liveness check |
POST /api/explain |
AI narration from analyzer evidence |
POST /api/question |
Transaction Q&A |
POST /api/beginner |
Beginner explanation |
POST /api/regular |
Regular explanation |
POST /api/full |
Full server-side analysis |
LLM safety rule: API keys live only in the backend. Browser extension code never receives OpenAI, Anthropic, or OpenRouter keys.
The current extension can save analyzed transaction reports to Swarm through packages/sdk-swarm.
Current behavior:
- Uploads history entries to a Bee
/bytesendpoint when Bee is reachable. - Creates a local Bee dev stamp automatically when possible.
- Supports encrypted Bee upload for private storage.
- Falls back to local extension storage when Bee is unavailable.
- Shows verification state:
verified,unverified,failed, orlocal. - Lets the Activity screen restore saved reports from the local Swarm index or by reference.
Start a local Bee dev node:
yarn swarm:devThe default Bee URL is:
http://127.0.0.1:1633
The browser extension is the current primary demo. The repository still includes a MetaMask Snap demo surface for MetaMask Flask.
Start the full Snap stack:
yarn dev:startWindows PowerShell:
.\scripts\dev\start-dev.ps1The stack exposes:
| Service | URL |
|---|---|
| SDK backend | http://127.0.0.1:3000 |
| Drainer demo | http://127.0.0.1:5174 |
| Snap server | http://localhost:8080 |
| Snap install site | http://127.0.0.1:8000 |
| Swarm Bee, when enabled | http://127.0.0.1:1633 |
Then open http://127.0.0.1:8000 in MetaMask Flask, install the Snap, and run demo transactions from http://127.0.0.1:5174.
Browser SDK:
import { TxExplainer } from '@analyzer/sdk';
const explainer = new TxExplainer({
rpcUrl: 'https://ethereum-sepolia.publicnode.com',
sourcifyUrl: 'https://sourcify.dev/server',
llmProxyUrl: 'http://localhost:3000/api/explain',
});
const result = await explainer.explain({
from: '0x0000000000000000000000000000000000000001',
to: '0x0000000000000000000000000000000000000002',
data: '0x',
value: 0n,
chainId: 11155111,
profile: 'regular',
});
console.log(result.recommendedAction.level);
console.log(result.risks);
console.log(result.auditHash);Backend SDK:
import { TxExplainerBackend, llmConfigFromEnv } from '@analyzer/sdk-backend';
const llm = llmConfigFromEnv(process.env);
const backend = new TxExplainerBackend({
rpcUrl: process.env.RPC_URL!,
sourcifyUrl: process.env.SOURCIFY_URL,
...(llm ? { llm } : {}),
});
const result = await backend.explain({
from,
to,
data,
value: 0n,
chainId,
profile: 'expert',
});Copy the example env file:
cp .env.example .envMinimal local configuration:
SEPOLIA_RPC_URL=https://ethereum-sepolia.publicnode.com
VITE_SEPOLIA_RPC_URL=https://ethereum-sepolia.publicnode.com
SOURCIFY_URL=https://sourcify.dev/server
LLM_PROVIDER=openai
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o
OPENAI_BASE_URL=
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=claude-sonnet-4-6
SWARM_MODE=dev
SWARM_BEE_URL=http://localhost:1633
SWARM_CREATE_DEV_STAMP=1
SWARM_DEV_FEED_FALLBACK=memoryNotes:
- Restart
@analyzer/sdk-backendafter changing backend.envvalues. - Rebuild and reload the browser extension after changing extension build-time values.
- Never commit
.env.
Common commands:
yarn typecheck
yarn test
yarn buildFocused checks:
yarn workspace @analyzer/core test
yarn workspace @analyzer/sdk test
yarn workspace @analyzer/sdk-backend test
yarn workspace @analyzer/extension build:chrome
yarn workspace @analyzer/metamask-snap testSolidity scenarios:
cd apps/contracts
forge testThe Solidity scenario suite covers malicious and benign patterns such as reentrancy, honeypots, hidden admin drains, upgrade abuse, fake airdrop approvals, permit phishing, rug pulls, selfdestruct via delegatecall, governance token false positives, and multicall false positives.
SignGuard is released under the MIT License.