Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Verify a deployed network's smart contracts on its block explorer and flip the MongoDB `verified` flag for each. Use this skill whenever a user asks to "verify the contracts for <network>", "verify contracts in PR
.claude/skills/lifinance-verify-contracts/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 65% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 14% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 153% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 4% | 0% |
Goal: every contract in deployments/<network>.json shows verified on the block explorer AND carries verified:true in the MongoDB deployment log. Those two facts are independent — the skill is not done until both hold.
NETWORK — short network name as keyed in config/networks.json (e.g. base, arbitrum, mainnet).deployments/<network>.json: { "ContractName": "0x…", … }. The authoritative list of what to verify.ENVIRONMENT — production unless the deploy was a staging run.lib/ is empty, forge cannot compile and verification fails with the misleading Details: Fail - Unable to verify, preceded by many No such file or directory errors for lib/.... A fresh worktree does not inherit submodules. Always run git submodule update --init --recursive before the first verifyContract.verified flag. Calling verifyContract directly verifies the bytecode on the explorer but does not write verified:true to the MongoDB master log — only logContractDeploymentInfo() (→ update-deployment-logs.ts add) does that, and the direct loop bypasses it. So after the on-chain loop you must flip the Mongo flags explicitly (Step 5). Skip this and the contracts look unverified in every report that reads Mongo, even though the explorer shows them green.main): use deployments/<network>.json in the current checkout.gh pr view <N> --json headRefName -q .headRefName if you only have the PR number, then:bash PR_BRANCH=$(gh pr view <N> --json headRefName -q .headRefName) git worktree add ../contracts-wt-verify "$PR_BRANCH" ln -s "$(git rev-parse --show-toplevel)/.env" ../contracts-wt-verify/.env # symlink, never copy
The TS scripts (Steps 5–6) read MONGODB_URI from .env; the symlink reuses the main checkout's secrets. If you keep a personal contracts-wt-add.sh helper it does the same .env symlink for you, but it is not required.
bashgit submodule update --init --recursive # gotcha #1 — non-negotiable in a fresh worktree
The repo TS scripts (Step 5) also need deps: run bun install if node_modules is absent. The TS log scripts filter Mongo by --network as a plain string, so if a worktree lacks deps you can run Step 5 from the main checkout instead — only the on-chain loop (Step 4) needs this checkout's src/ + lib/.
The on-chain loop relies on three sources already being correct for NETWORK. Verify, don't assume:
foundry.toml — NETWORK present in both [rpc_endpoints] and [etherscan]. The [etherscan] entry carries the verifier url, chain, and verifier (blockscout | sourcify | custom/etherscan).config/networks.json — verificationType and explorerApiUrl for NETWORK.[profile.default] compiler settings (solc_version, evm_version, optimizer_runs) match what the contracts were deployed with. A mismatch is a silent source of "Unable to verify" on etherscan-type verifiers.verifyContract <network> <contract> <address> <constructorArgs> lives in script/helperFunctions.sh. Source .env then the helper, then loop over the address map.
Key fact: blockscout and sourcify match RUNTIME bytecode, so constructor args are NOT required — pass "". (etherscan-type verifiers can need them; the helper skips invalid/empty args safely either way.)
bashsource .env source script/helperFunctions.sh NETWORK=<network> ENVIRONMENT=production # set to "staging" for a staging deploy — Step 5 reuses this DEPLOYMENTS="deployments/${NETWORK}.json" while IFS=$'\t' read -r CONTRACT ADDRESS; do echo "Verifying ${CONTRACT} @ ${ADDRESS}" verifyContract "$NETWORK" "$CONTRACT" "$ADDRESS" "" done < <(jq -r 'to_entries[] | "\(.key)\t\(.value)"' "$DEPLOYMENTS")
Why the direct loop and not the menu: script/scriptMaster.sh option 8 (verifyAllUnverifiedContractsInLogFile) does both the on-chain verify and the Mongo write-back — but only for entries in the local deployments/_deployments_log_file.json cache, which for a freshly-deployed network is usually empty or stale. The direct loop over the deployment JSON is the reliable path; Step 5 covers the write-back it skips.
verified flag back to MongoDBThese TS scripts need node_modules (bun install) and MONGODB_URI in .env.
bash bunx tsx script/deploy/query-deployment-logs.ts list \ --env "$ENVIRONMENT" --network "$NETWORK" --limit 200 --no-use-cache --format json
verified, preserves all other fields):bash bunx tsx script/deploy/update-deployment-logs.ts update \ --env "$ENVIRONMENT" --network "$NETWORK" \ --contract <Name> --version <ver> --address <addr> --verified true
Match records by ADDRESS (case-insensitive) to the deployment map — a contract name can have multiple versions in Mongo (e.g. a superseded facet). Only flip the versions you actually verified on-chain; never blindly mark a superseded version true — its older bytecode won't match current src/ and the claim would be false.
Re-query with --no-use-cache and confirm the verified count matches the deployment map:
bashbunx tsx script/deploy/query-deployment-logs.ts list \ --env "$ENVIRONMENT" --network "$NETWORK" --limit 200 --no-use-cache --format json \ | jq '[.data[] | {contract: .contractName, version, verified}]'
Report any record still false and why (e.g. superseded version intentionally left, or a verifier that genuinely failed). Don't claim "all verified" unless both the explorer and this re-query agree.
| What fails | What to do | |---|---| | Details: Fail - Unable to verify with lib/...: No such file or directory above it | Submodules not initialized — git submodule update --init --recursive (gotcha #1). | | Unable to verify on an etherscan-type verifier, lib/ is fine | Compiler profile mismatch — re-check solc_version / evm_version / optimizer_runs in [profile.default] against the deploy (Step 3). | | No verifier URL found for network | NETWORK missing from the [etherscan] section of foundry.toml (Step 3). | | Explorer shows green but reports still say unverified | Mongo flag never written — run Step 5. This is gotcha #2. | | update-deployment-logs.ts can't find the record | Wrong --version or --address — list with --no-use-cache first and match by address. | | TS script errors on MONGODB_URI | Not set in .env; these scripts can be run from the main checkout where it is configured. |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 9,716 | 5,692 | -41% | 1 | 1 | 0% | 1,835 | 2,328 | +27% | 0 | 0 | — |
case-02 | fail→fail | 7,383 | 5,376 | -27% | 1 | 1 | 0% | 1,236 | 2,346 | +90% | 0 | 0 | — |
case-03 | fail→fail | 4,305 | 5,421 | +26% | 1 | 1 | 0% | 170 | 2,310 | +1259% | 0 | 0 | — |
case-04 | pass→pass | 5,035 | 2,142 | -57% | 1 | 1 | 0% | 770 | 2,347 | +205% | 0 | 0 | — |
case-05 | fail→pass | 8,621 | 2,052 | -76% | 1 | 1 | 0% | 1,395 | 2,305 | +65% | 0 | 0 | — |
case-06 | pass→pass | 8,960 | 5,563 | -38% | 1 | 1 | 0% | 1,345 | 2,978 | +121% | 0 | 0 | — |
case-07 | pass→pass | 11,379 | 3,029 | -73% | 1 | 1 | 0% | 1,846 | 2,507 | +36% | 0 | 0 | — |
case-08 | fail→pass | 12,681 | 5,830 | -54% | 1 | 1 | 0% | 1,970 | 3,081 | +56% | 0 | 0 | — |
case-09 | fail→pass | 13,241 | 3,487 | -74% | 1 | 1 | 0% | 2,255 | 2,581 | +14% | 0 | 0 | — |
case-10 | pass→pass | 10,481 | 4,862 | -54% | 1 | 1 | 0% | 1,579 | 2,751 | +74% | 0 | 0 | — |
case-11 | pass→pass | 9,703 | 2,735 | -72% | 1 | 1 | 0% | 1,566 | 2,480 | +58% | 0 | 0 | — |
case-12 | pass→pass | 14,279 | 2,631 | -82% | 1 | 1 | 0% | 2,268 | 2,451 | +8% | 0 | 0 | — |
case-13 | fail→pass | 5,841 | 2,096 | -64% | 1 | 1 | 0% | 907 | 2,295 | +153% | 0 | 0 | — |
case-14 | pass→pass | 11,549 | 2,213 | -81% | 1 | 1 | 0% | 1,684 | 2,315 | +37% | 0 | 0 | — |
case-15 | fail→pass | 15,261 | 2,294 | -85% | 1 | 1 | 0% | 2,177 | 2,260 | +4% | 0 | 0 | — |
case-20 | fail→pass | 21,114 | 13,156 | -38% | 1 | 1 | 0% | 966 | 3,621 | +275% | 0 | 0 | — |
case-16 | pass→pass | 10,637 | 4,483 | -58% | 1 | 1 | 0% | 1,802 | 2,838 | +57% | 0 | 0 | — |
case-17 | pass→pass | 6,467 | 1,604 | -75% | 1 | 1 | 0% | 868 | 2,192 | +153% | 0 | 0 | — |
case-18 | fail→pass | 12,553 | 3,073 | -76% | 1 | 1 | 0% | 1,894 | 2,466 | +30% | 0 | 0 | — |
case-19 | fail→pass | 6,239 | 7,005 | +12% | 1 | 1 | 0% | 888 | 3,057 | +244% | 0 | 0 | — |
case-21 | pass→pass | 14,972 | 7,924 | -47% | 1 | 1 | 0% | 2,833 | 3,428 | +21% | 0 | 0 | — |
case-22 | pass→pass | 18,260 | 11,767 | -36% | 1 | 1 | 0% | 3,342 | 4,061 | +22% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 18 counted toward the lift figure. The other 4 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +36 percentage points is the difference between those two pass rates over the 18 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.