WalletBrief checks any Monad address and returns a live snapshot: MON and WMON balances, transaction count, latest block, and current ERC-20 approvals discovered through HyperSync.
If the connected browser wallet owns an active approval, WalletBrief simulates an exact approve(spender, 0) revoke before requesting its signature. It never asks a server to sign for the user.
The public search-and-revoke app is live. The repository also includes a stricter EIP-7702 batch-executor proof, deployed and source-verified on Monad mainnet. A real WMON approval was detected, revoked through that executor, and reduced to a verified no-op.
| Proof | Link |
|---|---|
| Hosted app | WalletBrief on Railway |
| Public repository | github.com/gabchess/walletbrief-monad |
Verified BatchExecutor |
MonadVision · exact-match source record |
| Harmless WMON approval seed | MonadVision transaction |
| Successful revoke transaction | MonadVision transaction |
- Open the hosted app and check the timestamp, wallet link, block link, balances, and change since the previous run.
- Confirm the indexed approval scan resolves to the wallet's current active approvals or a clear no-active-approvals state.
- Open the approval seed and successful revoke transactions above. The revoke emits
Approval(owner, spender, 0). - Read the measured deployment, allowance, delegation, no-op, and restart evidence in docs/mainnet-proof.md.
- Refresh the app. Persistent cursors keep the result fast, and no second transaction is proposed.
Address search
-> four parallel read-only Monad calls
-> live MON + WMON balances, transaction count, latest block
-> HyperSync indexes Approval events for the owner
-> Multicall verifies each current on-chain allowance
-> connected owner selects an active approval
-> wallet simulates approve(spender, 0)
-> owner signs and receives explorer evidence
WalletBrief keeps separate cursors for balance activity and approval signals. A wallet without a cursor starts from SCAN_START_BLOCK when configured, or from a bounded 25,000-block lookback. Successful checks persist a new valued snapshot, so the next run reports the change since that check rather than pretending to calculate lifetime profit and loss.
Price reads use CoinGecko first and DefiLlama as a fallback. One wallet failure is isolated from the rest of a multi-wallet run.
The public app permits one narrow action: the connected owner can set a discovered ERC-20 allowance to zero. The wallet must match the indexed approval's owner, and the exact write is simulated before signature.
The separate EIP-7702 proof path has two additional boundaries:
- The client sends only a configured wallet address. The server rereads live state and rebuilds the action, digest, implementation address, and calldata.
BatchExecutoraccepts calls only from the delegated wallet itself. Every target must contain code, every payload must be exactly ERC-20approve(address,uint256), and the amount must be zero. Used digests cannot be replayed.
Hosted execution is disabled. The proof transaction was signed locally from macOS Keychain, so Railway never received a wallet private key. The executor has no payable entry point and no fund-custody logic.
Requirements: Node.js 20+, Foundry, and Socket CLI for dependency installation.
socket npm install
cp .env.example .env
npm run devOpen http://localhost:3000. Keep EXECUTE_ENABLED=false for a read-only local brief.
The production container uses Next.js standalone output and one Node process:
docker build -t walletbrief .
docker run --rm -p 3000:3000 \
-e BRIEF_WALLETS=0x35160A4238CB5F3166046399c397B6E0c12FD872 \
walletbriefGET /api/health returns {"ok":true,"chainId":143} without making an RPC call or exposing configuration.
| Variable | Default | Purpose |
|---|---|---|
MONAD_RPC_URL |
https://rpc.monad.xyz |
Read-only Monad mainnet RPC |
BRIEF_WALLETS |
Dedicated demo wallet | Comma-separated wallets to brief |
SCAN_START_BLOCK |
Unset | Explicit first block for a wallet with no cursor |
SCAN_LOOKBACK_BLOCKS |
25000 |
Bounded first-run lookback when no start block is set |
CURSOR_STORE_PATH |
.state/cursors.json |
Balance-activity scan cursors |
ANOMALY_CURSOR_STORE_PATH |
.state/anomaly-cursors.json |
Approval-signal scan cursors |
SNAPSHOT_STORE_PATH |
.state/snapshots.json |
Last successful valued state |
APPROVAL_STATE_STORE_PATH |
.state/approvals.json |
Tracked approval state |
BATCH_EXECUTOR_ADDRESS |
Zero address | Verified executor implementation |
EXECUTE_ENABLED |
false |
Explicit hosted execution gate |
EXECUTE_RPC_URL |
MONAD_RPC_URL |
HTTPS RPC used for an approved revoke |
DEMO_EXECUTION_WALLET |
Dedicated demo wallet | Exact wallet allowed to execute |
DEMO_WALLET_PRIVATE_KEY |
Unset | Runtime secret for the dedicated demo wallet |
For a hosted service, mount persistent storage at /data, point every state path there, and run exactly one replica. WalletBrief serializes state changes within one process; it does not claim distributed locking across replicas.
npm test
npm run typecheck
npm run web:build
cd contracts
forge fmt --check
forge test
forge buildThe default JavaScript suite keeps the Anvil integration test skipped. Run it explicitly with npm run test:integration when Foundry and a Monad RPC are available.
The contract suite covers self-only access, exact revoke validation, replay protection, partial action failure, reentrancy resistance, and zero custody. The application suite covers bounded scans, persisted state, per-wallet failure isolation, server-side action recomputation, disabled-by-default execution, explorer links, and the health endpoint.
- Approval discovery covers standard ERC-20
Approvalevents indexed by owner. Nonstandard tokens and permissions outside ERC-20 allowances are out of scope; this is not a full wallet security scanner. - "Stale" means a live nonzero tracked approval with no observed drawdown in WalletBrief's available history. It is a rule-based signal, not proof of malicious intent.
- USD values depend on external price APIs and are informational.
- Snapshot change is the delta since WalletBrief's previous successful check, not tax accounting or lifetime P&L.
- Stateful file storage requires one process and persistent disk.
- The demo executor is revoke-only. It cannot transfer tokens, set a positive allowance, or run arbitrary calldata.
Built for the Spark Hackathon on Monad.