Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Rotates the shared SC-owned **Deployer** wallet — `safeOwners[0]` + the Timelock `CANCELLER_ROLE` (and prod timelock executor) — end-to-end: bootstraps the new deployer's gas, swaps the Safe owner and moves the canceller role via Safe proposals, handles Tron, updates config, decommissions the old key, and gates on a completeness check. Thin orchestrator: it CALLS the L1 skills (`sweep-wallet-funds`, `move-tron-delegation`, `update-wallet-config`, `check-rotation-status`) and existing skills (`/m
.claude/skills/lifinance-rotate-deployer-wallet/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 127% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 88% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 127% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 95% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 136% | 0% |
Rotate the shared Deployer wallet, which carries the protocol's heaviest privileges:
safeOwners[0] — a signer on every production Safe.CANCELLER_ROLE (and the production timelock executor).Because it is SC-owned it is rotatable, but every privilege it holds is governed by Safe + Timelock — so the on-chain swaps run as Safe proposals through multisig-rollout, never as owner shortcuts. This skill is a thin orchestrator: it sequences the L1 and existing skills, enforces the guardrails, and gates on the final check. It reimplements none of their logic.
Use when the user says:
Do NOT use for:
rotate-dev-wallet.rotate-pauser-wallet.offboard-sc-dev (the orchestrator that calls this skill).Required:
0x…). If not supplied, ask once; never generate it inside the skill (see Guardrails).Optional:
check-rotation-status, changes nothing) and stop. Use to preview state before rotating or to re-verify after.The old deployer address is derived from PRIVATE_KEY_PRODUCTION in .env (the sweep in Phase 1 does this), never from config/global.json.deployerWallet — the key and the config can diverge, and the wrong address makes a funded wallet look empty (or a rotation look incomplete).
multisig-rollout's hand-off (script/deploy/safe/confirm-safe-tx.ts); this orchestrator hands off and WAITS — it never runs the signer.multisig-rollout. The Tron ownership transfer (Phase 3, transfer-ownership-to-timelock.ts) is the one different mechanism but still governed — its confirm step is itself a Safe/Timelock proposal, not an owner shortcut.config/global.json.--check/--dryRun and confirm the plan before any broadcast or proposal is minted.Foundry/bun may need export PATH="$HOME/.foundry/bin:$HOME/.bun/bin:$PATH". VPN is required for the MongoDB signature verification inside multisig-rollout.
--new-address is present, checksum-valid, and NOT any current SC/CTO wallet in config/global.json.multisig-rollout, after which the user returns to the chat and the skill resumes with the remaining phases (3–7).sweep-wallet-funds) — FIRSTSweep native gas from the old deployer to the new one across all active EVM chains so the new deployer can broadcast. This runs before any governance change so the new wallet is fundable and usable when the Safe adds it.
text/sweep-wallet-funds --new-address <NEW> --old-key-env PRIVATE_KEY_PRODUCTION --production
sweep-wallet-funds previews balances first, sweeps native LAST (stranding guard), and owns the human-confirmed pre-send report + secrets hygiene. Do not reimplement moveNativeFundsToNewWallet.ts here.
> Leave enough in the OLD deployer to sign the Safe/timelock txs it still needs to send in Phase 2 if any are broadcast by the old key — sweep-wallet-funds's balance preview (read-only; the mover script has no dry-run flag) lets you judge this per network before committing.
> HyperEVM big blocks (manual, per-address). The new deployer cannot broadcast contract deploys on hyperevm until big blocks are enabled for it — an L1 setting that does not carry over on rotation (register the address as a HyperCore Core user, then toggle big blocks ON). Follow the runbook: docs/HyperEVMBigBlocks.md.
> Sophon deployer allow-list (manual, per-address). sophon gates contract deployment behind a per-EOA allow-list, so the new deployer is rejected on every Sophon deploy (contract deployer address … is not in the allow list) until the Sophon team adds it — funding the wallet is not enough, and the allow-listing does not carry over on rotation. It's an off-repo, async request, so start it now during bootstrap rather than discovering it at the next Sophon rollout: ask in the Sophon partner channel to allow-list the new deployer EOA. It doesn't block the other phases. (Other zkEVM chains like abstract and zksync have no such restriction.)
multisig-rollout)The governed changes — replace safeOwners[0] (old → new) on every production Safe and move the Timelock CANCELLER_ROLE (old removed, new granted) — run as timelock-wrapped Safe proposals via the production rollout skill:
text/multisig-rollout <owner-swap + canceller-role change>
multisig-rollout captures the proposals, drafts the PR, and then pauses to hand Ledger signing to the human (confirm-safe-tx.ts) — it verifies signatureCount >= 2 in MongoDB and posts #dev-sc-multisig-proposals. This orchestrator does NOT sign and does NOT post; it waits for multisig-rollout to complete its lifecycle (the human signs, the team recruits the remaining signer). Never self-sign, never bypass the Safe.
On Tron the diamond ownership is held by the Timelock; move it via the existing script (env-derived network: production → tron, NOT a flag):
bashbunx tsx script/deploy/tron/transfer-ownership-to-timelock.ts --dryRun # preview bunx tsx script/deploy/tron/transfer-ownership-to-timelock.ts --step 1 # then --step 2
Then re-point the Tron staked-resource delegation from the old deployer Tron address to the new one:
text/move-tron-delegation --old-address <old deployer 0x…> --new-address <NEW> --role deployer
move-tron-delegation derives both base58 addresses, drafts the undelegate→re-delegate request (delegator-controlled, executed off-repo), and verifies on Tronscan afterward. Any Ledger signing the Tron ownership step needs is a human step.
update-wallet-config)Open the PR that rotates the deployerWallet role in config.
text/update-wallet-config --role deployer --new-address <NEW> --production
update-wallet-config updates the EVM deployerWallet field AND tronWallets.deployerWallet (Tron base58 derived + reverse-checked), honors config-structure rule 004, and ends by calling /create-pr. Notion registry update is a flagged follow-up.
Once Phases 2–4 have landed and check-rotation-status (Phase 6) confirms the old address holds no Safe-owner / canceller / owner privileges anywhere, the old private key can be retired: remove it from .env / secret stores and rotate any CI secret that carried it. This is a human/operational step — surface the exact checklist; do not attempt to touch secret stores from the skill.
check-rotation-status)Run the read-only completeness gate scoped to the deployer rotation:
text/check-rotation-status --old-address <old deployer 0x…> --new-address <NEW> --role deployer --production
For the deployer role the relevant checks are: Safe-owner membership (old removed / new added) on every production Safe, Timelock CANCELLER_ROLE (old removed / new granted), the Tron ownership/delegation state, and the CI wallet-funding check. Only declare complete when every network passes.
Summarize: swept networks (moved/skipped), the multisig-rollout outcome (proposal nonces, PR URL, Slack thread, remaining team signatures), Tron ownership + delegation state, config PR URL, old-key decommission status, and the check-rotation-status result. Call out anything still pending (unsigned proposals, unverified networks) and the human follow-ups.
Complete only when check-rotation-status (Phase 6) passes for every network: new deployer is safeOwners[0] and holds CANCELLER_ROLE, the old deployer holds neither anywhere, Tron reflects the new address, and funding passes. Because the Safe swaps go through timelock, the on-chain state flips only after the proposals are signed to threshold and the timelock delay elapses — the check may legitimately still show "old" until then; report that as pending, not as failure. Re-run /rotate-deployer-wallet --check to re-confirm.
| Step | Delegates to | Owns | |---|---|---| | Bootstrap gas | sweep-wallet-funds | native sweep across EVM chains, pre-send report, secrets hygiene | | Safe owner swap + canceller move | multisig-rollout | proposals → PR → Ledger hand-off → Mongo sig verify → Slack | | Tron ownership → Timelock | script/deploy/tron/transfer-ownership-to-timelock.ts | env-derived Tron handover (production → tron) | | Tron delegation | move-tron-delegation | undelegate→re-delegate request + Tronscan verify | | Config PR | update-wallet-config | global.json deployerWallet + tronWallets.deployerWallet, /create-pr | | Completeness gate | check-rotation-status | read-only cross-network verification |
This skill adds only sequencing (sweep-first bootstrap ordering), the custody/self-sign/no-bypass guardrails, and the confirm gate — no funds-moving, signing, address-deriving, or config-editing logic of its own.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-03 | fail→fail | 24,481 | 9,997 | -59% | 1 | 1 | 0% | 2,242 | 3,888 | +73% | 0 | 0 | — |
case-01 | fail→fail | 25,688 | 4,640 | -82% | 1 | 1 | 0% | 5,368 | 3,486 | -35% | 0 | 0 | — |
case-02 | fail→fail | 9,916 | 7,168 | -28% | 1 | 1 | 0% | 1,918 | 3,317 | +73% | 0 | 0 | — |
case-04 | fail→pass | 7,601 | 2,964 | -61% | 1 | 1 | 0% | 1,525 | 3,458 | +127% | 0 | 0 | — |
case-05 | fail→pass | 10,516 | 3,782 | -64% | 1 | 1 | 0% | 1,878 | 3,540 | +88% | 0 | 0 | — |
case-06 | fail→pass | 7,087 | 2,425 | -66% | 1 | 1 | 0% | 1,438 | 3,258 | +127% | 0 | 0 | — |
case-07 | fail→fail | 9,849 | 3,119 | -68% | 1 | 1 | 0% | 1,777 | 3,326 | +87% | 0 | 0 | — |
case-12 | fail→pass | 9,979 | 1,693 | -83% | 1 | 1 | 0% | 1,611 | 3,145 | +95% | 0 | 0 | — |
case-08 | fail→pass | 18,356 | 3,761 | -80% | 1 | 1 | 0% | 1,458 | 3,439 | +136% | 0 | 0 | — |
case-09 | pass→pass | 11,087 | 3,366 | -70% | 1 | 1 | 0% | 1,777 | 3,475 | +96% | 0 | 0 | — |
case-10 | fail→pass | 23,061 | 2,265 | -90% | 1 | 1 | 0% | 1,866 | 3,292 | +76% | 0 | 0 | — |
case-11 | fail→pass | 17,463 | 6,158 | -65% | 1 | 1 | 0% | 3,222 | 4,090 | +27% | 0 | 0 | — |
case-13 | fail→pass | 13,239 | 6,237 | -53% | 1 | 1 | 0% | 2,440 | 4,057 | +66% | 0 | 0 | — |
case-14 | fail→pass | 9,396 | 2,710 | -71% | 1 | 1 | 0% | 1,808 | 3,426 | +89% | 0 | 0 | — |
case-15 | fail→pass | 15,147 | 8,552 | -44% | 1 | 1 | 0% | 2,496 | 4,194 | +68% | 0 | 0 | — |
case-16 | fail→pass | 20,137 | 2,556 | -87% | 1 | 1 | 0% | 1,343 | 3,493 | +160% | 0 | 0 | — |
case-25 | fail→pass | 12,333 | 2,109 | -83% | 1 | 1 | 0% | 1,899 | 3,157 | +66% | 0 | 0 | — |
case-17 | fail→pass | 11,162 | 4,161 | -63% | 1 | 1 | 0% | 1,992 | 3,590 | +80% | 0 | 0 | — |
case-18 | pass→pass | 11,981 | 2,935 | -76% | 1 | 1 | 0% | 1,843 | 3,261 | +77% | 0 | 0 | — |
case-19 | fail→pass | 10,832 | 5,264 | -51% | 1 | 1 | 0% | 1,707 | 3,584 | +110% | 0 | 0 | — |
case-20 | pass→pass | 10,575 | 2,785 | -74% | 1 | 1 | 0% | 1,667 | 3,244 | +95% | 0 | 0 | — |
case-21 | fail→pass | 5,776 | 3,527 | -39% | 1 | 1 | 0% | 947 | 3,397 | +259% | 0 | 0 | — |
case-22 | pass→pass | 7,601 | 3,555 | -53% | 1 | 1 | 0% | 1,295 | 3,461 | +167% | 0 | 0 | — |
case-23 | fail→pass | 9,343 | 2,549 | -73% | 1 | 1 | 0% | 1,389 | 3,269 | +135% | 0 | 0 | — |
case-24 | pass→pass | 7,498 | 2,038 | -73% | 1 | 1 | 0% | 1,374 | 3,165 | +130% | 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. 25 cases were attempted, and 22 counted toward the lift figure. The other 3 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 +64 percentage points is the difference between those two pass rates over the 22 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.