Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Deploys a facet/periphery contract (the version currently in the repo) to one or more networks and registers it in each network's LiFiDiamond — deploy, explorer-verify, diamondCut (facets) or diamondUpdatePeriphery (periphery), plus the diamond allowlist sync for diamond-called periphery. Use whenever the user wants to "deploy <Contract> to <networks>", "redeploy <Facet> on staging", "push <Periphery> to base/optimism", or otherwise get a contract on-chain and into the diamond WITHOUT the Safe-p
.claude/skills/lifinance-deploy-contract/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 153% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 380% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 45% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 73% | 0% |
Non-interactive deploy of a single contract to N networks via script/deploy/deployContractToNetworks.sh (scriptMaster use case 1, repeated). Per network it deploys (CREATE3), verifies on the explorer, and registers in the LiFiDiamond:
diamondCut (a Safe proposal in production, direct cut in staging)diamondUpdatePeripheryIt stops once the contract is deployed, verified, and registered (production: proposal created carrying the deployer's signature). In the standalone staging path it also lands the resulting deployment-log changes via a draft PR (Phase 4). It never drives hardware-wallet signing or posts to Slack — and in production it leaves the PR to multisig-rollout.
See also: rotate-pauser-wallet calls this skill to redeploy EmergencyPauseFacet with the new pauser when rotating the pauser wallet.
| Situation | Skill | |---|---| | Staging / testnet / non-governed deploy (terminal) | this skill | | Production rollout needing Safe proposals signed & shepherded | multisig-rollout (it calls this skill) |
Hard rail — don't strand production proposals. A standalone production deploy creates Safe proposals carrying a single signature and then stops; with no PR, no signing hand-off, and no Slack thread, those proposals sit forgotten below threshold. So: if this is a production deploy (--production) and you are not running it as a step inside multisig-rollout, stop and route the user to /multisig-rollout. Only proceed with --production here when multisig-rollout is driving the full lifecycle around you.
PR ownership. The staging path opens its own deployment-log PR (Phase 4). The production PR is not this skill's job — when multisig-rollout drives, skip Phase 4; it opens the single combined PR (logs + nonce table) after capturing proposals.
The target environment is a double opt-in enforced by the script: staging unless both --production is passed and PRODUCTION=true is in .env. Default standalone use is staging. Never edit .env to flip this — if --production and .env disagree, the script aborts; relay that to the user.
Tron gate — check first. If the target network list includes tron or tronshasta, split them out: this skill's pipeline (deployContractToNetworks.sh, Foundry, CREATE3) has no Tron support at all. Hand those networks to /deploy-contract-tron (a different repo checkout — contracts-tron — and a different toolchain) and continue here only with the remaining EVM networks, if any.
Run from the repo root. Check and report (don't fix silently):
.env exists; PRODUCTION matches the intended environment (true only for a production run); SEND_PROPOSALS_DIRECTLY_TO_DIAMOND not true for production (it bypasses the Safe — legitimate only when bootstrapping a new production network before ownership transfers to the Safe; abort otherwise); MAX_CONCURRENT_JOBS set.forge --version); gh auth status OK.deployments/<net>.json (and, for diamond-called periphery, config/whitelist.json), which the caller commits later.The target list comes from one of two sources:
/add-network + a full deploy). If a named network has no diamond, flag it and drop it.bashfor F in deployments/*.diamond.json; do NET=$(basename "$F" .diamond.json) V=$(jq -r --arg N "<Contract>" '(.LiFiDiamond.Facets // {}) | to_entries[] | select(.value.Name == $N) | .value.Version' "$F" 2>/dev/null | head -1) [ -n "$V" ] && echo "$NET $V" done
For periphery contracts check .LiFiDiamond.Periphery | has($N) instead. The glob matches only production logs (*.diamond.staging.json and *.diamond.immutable.json do not end in .diamond.json).
Repo version: grep -m1 "@custom:version" src/Facets/<Contract>.sol (or src/Periphery/...). Report old → new version per network (a new network shows no current version — expected). Networks already on the repo version are re-deployed only if the user asked — surface them and ask.
Diamond-called periphery needs a second proposal. A periphery contract the diamond invokes during swaps (e.g. GasZipPeriphery, FeeCollector, LiFiDEXAggregator) must be both registered in the diamond and added to the diamond's allowlist — registration alone (PeripheryRegistry) does not let the diamond call it. Detect deterministically:
bashjq -e --arg N "<Contract>" '.whitelistPeripheryFunctions | has($N)' config/global.json >/dev/null && echo "needs whitelist sync"
If it matches, Phase 3b runs an allowlist sync afterwards (a second production proposal). No manual whitelist.json editing: the sync derives the address + selectors from global.json.whitelistPeripheryFunctions automatically. Facets and non-diamond-called periphery skip Phase 3b.
Present: contract + version (old → new per network), the full network list, environment, and what will be created (per network: one registration; two for a diamond-called periphery — registration + allowlist; in production each is a timelock-wrapped Safe proposal). Wait for explicit go-ahead — deployments cost gas and, in production, mint Safe proposals on many chains.
Run in the background (long-running; deploys retry and verify inline), monitor output, report per-network results:
bash# staging (default) ./script/deploy/deployContractToNetworks.sh <Contract> <network...> # production (only inside multisig-rollout — see hard rail) ./script/deploy/deployContractToNetworks.sh <Contract> <network...> --production
Ends with a per-network summary and exits 1 if any network failed. Failures don't block survivors: continue with the succeeded networks, report the failed ones, and offer to retry them individually with the same command. In production each proposal is created already carrying one signature (signatureCount: 1).
Run only when Phase 1 flagged the contract as diamond-called. After the deploy registered it, sync the allowlist on the same networks:
bash# staging sends directly; production proposes (and re-syncs staging afterwards — expected) ./script/tasks/syncWhitelistToNetworks.sh <network...> [--production]
This re-derives whitelist.json from global.json.whitelistPeripheryFunctions (picking up the just-deployed address) and applies a batchSetContractSelectorWhitelist cut — the second proposal per network in production. Skip entirely for facets and non-diamond-called periphery.
The deploy framework attempts explorer verification inline, but it can fail, and the MongoDB verified flag is written separately from on-chain verification. Confirm every freshly deployed contract is verified by invoking the verify-contracts skill for each target network:
text/verify-contracts <network>
It verifies the deployment's addresses on the explorer and writes verified:true to MongoDB (both must hold).
Skip this phase entirely when multisig-rollout is driving (production): the orchestrator opens one combined PR after capturing proposals, because that body needs the per-network Safe nonce table that doesn't exist until then. In the standalone staging path the deploy's only leftover is the deployment-log diff, and landing it shouldn't be a manual afterthought.
git add -A:bash git status --porcelain -- deployments/ 'config/whitelist*.json'
The contract type need not be special-cased: a facet writes the diamond log's Facets section + address map, periphery writes the Periphery section, a diamond-called periphery also rewrites config/whitelist.json / config/whitelist.staging.json (Phase 3b) — staging whatever changed covers all of them. If the output is empty (idempotent re-deploy — same CREATE3 address, version already registered), there's nothing to land; skip.
to /create-pr, passing:
list, environment (staging), and the registration note for the type — diamondCut (facet) / diamondUpdatePeriphery (periphery) / + allowlist sync, whitelist.json updated (diamond-called periphery).
/create-pr stages only the named files and has a confirm gate, so a routine staging deploy isn't force-PR'd — you approve before it pushes. Don't reimplement branching/commit/PR plumbing here; /create-pr owns it.
Report a per-network result table the caller (or user) can act on:
| Field | Source | |---|---| | contract, version | Phase 1 (repo @custom:version) | | network, chainId | target list / config/networks.json | | address | deploy summary / deployments/<net>.json | | registration | diamondCut (facet) or diamondUpdatePeriphery (periphery); + allowlist if Phase 3b ran | | proposalCreated | production only — one per registration (sig 1); two for diamond-called periphery | | verified | Phase 3c result |
In production, note the files changed on disk (deployments/<net>.json, and config/whitelist.json / config/whitelist.staging.json if Phase 3b ran) so the caller commits them, and that proposals carry a single signature awaiting the signing lifecycle. When run inside multisig-rollout, hand this table back so it can capture proposal nonces, draft the PR, and run the signing tail.
--production / .env mismatch → script aborts with a clear message; do not edit .env, relay it./verify-contracts <network>; the MongoDB verified flag and on-chain verification must both hold.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-16 | pass→pass | 13,754 | 6,029 | -56% | 1 | 1 | 0% | 2,092 | 3,758 | +80% | 0 | 0 | — |
case-01 | fail→fail | 16,110 | 7,030 | -56% | 1 | 1 | 0% | 2,512 | 3,293 | +31% | 0 | 0 | — |
case-02 | fail→fail | 12,061 | 5,669 | -53% | 1 | 1 | 0% | 2,025 | 3,136 | +55% | 0 | 0 | — |
case-03 | fail→fail | 12,090 | 4,642 | -62% | 1 | 1 | 0% | 2,141 | 2,977 | +39% | 0 | 0 | — |
case-04 | fail→pass | 8,616 | 3,736 | -57% | 1 | 1 | 0% | 1,333 | 3,376 | +153% | 0 | 0 | — |
case-05 | pass→pass | 12,728 | 4,061 | -68% | 1 | 1 | 0% | 1,828 | 3,384 | +85% | 0 | 0 | — |
case-06 | fail→pass | 20,396 | 6,057 | -70% | 1 | 1 | 0% | 3,304 | 3,617 | +9% | 0 | 0 | — |
case-07 | pass→pass | 10,461 | 5,124 | -51% | 1 | 1 | 0% | 1,649 | 3,673 | +123% | 0 | 0 | — |
case-08 | fail→pass | 4,074 | 2,983 | -27% | 1 | 1 | 0% | 673 | 3,231 | +380% | 0 | 0 | — |
case-09 | fail→pass | 13,987 | 3,353 | -76% | 1 | 1 | 0% | 2,292 | 3,312 | +45% | 0 | 0 | — |
case-10 | fail→pass | 17,228 | 15,000 | -13% | 1 | 1 | 0% | 2,713 | 4,687 | +73% | 0 | 0 | — |
case-11 | fail→pass | 13,354 | 3,912 | -71% | 1 | 1 | 0% | 1,942 | 3,331 | +72% | 0 | 0 | — |
case-12 | fail→pass | 8,229 | 3,011 | -63% | 1 | 1 | 0% | 1,333 | 3,214 | +141% | 0 | 0 | — |
case-13 | fail→pass | 9,914 | 4,944 | -50% | 1 | 1 | 0% | 1,554 | 3,505 | +126% | 0 | 0 | — |
case-14 | fail→pass | 9,804 | 3,049 | -69% | 1 | 1 | 0% | 1,520 | 3,283 | +116% | 0 | 0 | — |
case-15 | pass→pass | 8,879 | 4,273 | -52% | 1 | 1 | 0% | 1,409 | 3,446 | +145% | 0 | 0 | — |
case-17 | fail→pass | 11,369 | 3,822 | -66% | 1 | 1 | 0% | 1,749 | 3,218 | +84% | 0 | 0 | — |
case-18 | fail→pass | 13,521 | 2,660 | -80% | 1 | 1 | 0% | 2,030 | 3,081 | +52% | 0 | 0 | — |
case-19 | fail→pass | 14,052 | 2,099 | -85% | 1 | 1 | 0% | 846 | 2,983 | +253% | 0 | 0 | — |
case-20 | fail→pass | 14,803 | 3,956 | -73% | 1 | 1 | 0% | 2,307 | 3,380 | +47% | 0 | 0 | — |
case-21 | pass→pass | 9,798 | 3,480 | -64% | 1 | 1 | 0% | 1,509 | 3,252 | +116% | 0 | 0 | — |
case-22 | fail→fail | 14,081 | 10,354 | -26% | 1 | 1 | 0% | 2,375 | 3,561 | +50% | 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 +59 percentage points is the difference between those two pass rates over the 18 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
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.