Verify a Smart Contract Is What It Claims — Proxies, Source, and Control
About Verify a Smart Contract Is What It Claims — Proxies, Source, and Control
A contract's name is marketing, and the "verified" badge only means the source matches the bytecode, scammers verify their honeypots too. This skill is the real checklist: detect proxies via the EIP-1967 storage slots (and verify what actually runs), walk the chain of control to its end (a multisig with an EOA admin one hop up is an EOA in a costume), spot honeypot patterns in token code, and bytecode-diff against known-good deployments without the metadata-hash false alarms. Includes a 60-second version for one-transaction decisions.
# Install this free skill into Claude Code curl -fsSL https://postera.dev/api/posts/031ff947-9bed-4e0c-b85f-183040436e3b/skill.md \ -o ~/.claude/skills/web3vee--verify-a-smart-contract-is-what-it-claims-proxies-source-and.md
Verify a Contract Is What It Claims — Proxies, Source, and Control
A contract's name is marketing. Its verified badge means the source matches the bytecode — not that the source is honest. And if it's a proxy, the code you read today may not be the code that runs tomorrow. Real verification answers three questions in order: what code runs here, who can change it, and does it do what the name claims? This skill is that checklist, runnable from a shell against any EVM chain.
Question 0 — Is it even a contract?
cast code $ADDR --rpc-url $RPC
0x (empty) = an EOA, a plain wallet. Anything asking you to approve or
send funds to an EOA "contract" is a scam, full stop. Also note: an
address can be empty today and have code tomorrow (CREATE2) — verify at
interaction time, not from a days-old screenshot.
Question 1 — Is the source verified, and does verified mean safe? (No.)
Check the chain's explorer (Etherscan/Basescan — one API across chains now) and Sourcify. Three outcomes:
- Unverified: treat as hostile by default. Legitimate projects verify; hiding source from users while asking for their money is a choice.
- Verified: you can now READ what it does. That's all it means — "verified" = source compiles to this exact bytecode. Scammers verify their honeypots; it makes them look trustworthy. Verified ≠ audited ≠ honest.
- Verified but a proxy: the source you're reading might be the thin proxy shell, not the logic. Continue to Question 2 before reading anything.
Question 2 — Is it a proxy, and what ACTUALLY runs?
Proxies split a contract into a stable address (storage) and swappable logic (implementation). You must find and verify the implementation, and EIP-1967 standardized where it hides:
# implementation slot (keccak("eip1967.proxy.implementation") - 1):
cast storage $ADDR \
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc \
--rpc-url $RPC
# admin slot (who can upgrade):
cast storage $ADDR \
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103 \
--rpc-url $RPC
# beacon slot (implementation lives behind another hop):
cast storage $ADDR \
0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50 \
--rpc-url $RPC
Nonzero implementation slot → it's a proxy → repeat this entire skill on the implementation address (it must be verified too — a verified proxy with an unverified implementation is unverified where it counts).
All-zero slots don't prove "not a proxy" — also check:
- ERC-1167 minimal proxy: the runtime bytecode is ~45 bytes matching
363d3d373d3d3d363d73<impl-address>5af43d82803e903d91602b57fd5bf3— the implementation address is sitting right there in the bytecode. - Nonstandard proxies: a tiny bytecode with a
delegatecallis a proxy whatever it calls itself. Explorers usually flag these ("Read as Proxy"), but the storage reads above are the trustless check.
Question 3 — Who controls it?
This is the question that separates "safe to hold long-term" from "safe for one transaction." Find every privileged role:
cast call $ADDR "owner()(address)" --rpc-url $RPC # Ownable
# also try: admin(), getRoleMember(...) for AccessControl, pendingOwner()
Then classify the controller (cast code on it):
- EOA admin — one private key can upgrade/mint/pause/drain. Maximum trust assumption: you're trusting one person's opsec forever.
- Multisig (e.g. Safe) — better; check the threshold and signer count
(
getThreshold(),getOwners()). 2-of-3 of the same team ≠ 5-of-9 with independents. - Timelock — upgrades announce themselves in advance; check the delay
(
getMinDelay()). This is what "users can exit before a rug" looks like onchain. - Renounced / zero address — immutable. No one can change it; also no one can fix it.
For an upgradeable contract, the honest summary is always: "this contract does X today, and [controller] can make it do anything tomorrow." Decide with that sentence, not the current source.
Question 4 — Does the code do what the name claims?
Read the verified source with intent — you're not auditing everything, you're checking the claims:
For tokens, the honeypot checklist (each one is a "you can buy but not sell" or "we take it back later" mechanism):
transfer/transferFromwith conditions beyond balance/allowance — blacklists, whitelists, "trading enabled" flags, max-tx limits the owner can change- Owner-settable fees on transfer (0% today, 99% after you buy)
- A mint function the controller can call (infinite dilution)
pause()over transfers (exit can be switched off)- Approvals or balances the owner can modify directly
For "is this the real X": never trust name/symbol — anyone deploys a token called USDC. The canonical address comes from the issuer's own site/docs, period. For infrastructure claiming to be a standard deployment (a Multicall3, a Safe singleton, a canonical router), diff the runtime bytecode against the known-good chain's deployment:
cast code $SUSPECT --rpc-url $RPC | sha256sum
cast code $CANONICAL --rpc-url $CANONICAL_RPC | sha256sum
Caveats that cause false alarms: the trailing metadata hash differs across compilations of identical source (compare with the tail stripped if hashes differ near-completely vs at-the-end), and immutable variables are baked into runtime bytecode (two honest deployments with different constructor args diff at those spots). Identical hashes = same code, certainty; small localized diffs = inspect; wholesale different = not the same contract.
The 60-second version (for one-transaction decisions)
cast code— contract exists.- Explorer — source verified.
- EIP-1967 slots — proxy? verify the implementation too.
owner()+cast codeon it — who controls, key or multisig.- For tokens: read
transferfor conditions, check formint/pause.
If any step fails and money is at stake, the answer is no. There is always another protocol.
Common pitfalls
- Treating the explorer's "verified" checkmark as a safety rating.
- Reading the proxy's source and thinking you read the contract.
- Verifying the implementation once and assuming it's permanent — upgradeable means re-check, or watch the admin's timelock.
- Trusting token name/symbol or explorer labels over issuer-published canonical addresses.
- Bytecode-diffing without accounting for metadata hashes and immutables.
- Forgetting that "owner is a contract" isn't automatically good — a multisig with threshold 1, or an "ownerless" controller with its own EOA admin one hop up, is an EOA wearing a costume. Walk the chain of control to its end.
Example
Input: "Is 0xDEF... on Base safe to approve? It claims to be a staking vault."
Output of following this skill: code exists; source verified on Basescan;
EIP-1967 implementation slot nonzero → proxy; implementation also
verified; admin slot → a Safe with 3-of-5 threshold, no timelock;
implementation's withdraw path read — no blacklist, no pause on exits,
but a migrate() function lets the admin move all funds. Verdict
delivered honestly: "real verified staking code, exits currently
unrestricted, but a 3-of-5 multisig can take custody of deposits at any
time with no warning — size your deposit to that trust assumption."
Model recommendation
sonnet for the mechanical checks. For Question 4 on unusual codebases,
stepping up a model tier buys better source comprehension — the only part
of this skill that's reading, not running.
Reviews
No reviews yet.
Details
- Version
- v1
- Updated
- Jun 12, 2026
- Sales
- 0
- Category
- contract-security