Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Rotates the shared SC-owned Pauser wallet (the emergency-pause EOA that trips EmergencyPauseFacet) by redeploying the facet with the new pauser baked into its constructor and cutting it into every diamond — because pauserWallet is immutable and has no setter, a rotation is a redeploy, not a config write. Use when the user says "rotate the pauser wallet", "repoint the emergency pauser", or "replace the pause EOA". NOT for the deployer wallet (safeOwners[0] + Timelock CANCELLER — that is `rotate-d
.claude/skills/lifinance-rotate-pauser-wallet/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 106% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 47% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 106% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 73% | 0% |
Rotates the shared Pauser EOA — the wallet allowed to call pause() on EmergencyPauseFacet to halt a diamond in an incident. The pauser is SC-owned, so it is rotatable (custody guard below).
Why this is a redeploy, not a setter call: EmergencyPauseFacet stores the pauser as an immutable set in its constructor — there is no on-chain function to repoint it. So "rotate the pauser" means deploy a fresh EmergencyPauseFacet carrying the new pauser and diamondCut it into every diamond, replacing the old facet's selectors. The repoint is delegated to deploy-contract (staging / testnets) and multisig-rollout (production Safe proposals); the old pauser's residual gas is swept to the new one via sweep-wallet-funds.
Kept-simple by design: the coverage gap during a per-chain cut is sub-second (the old facet still pauses until its selectors are replaced), so this skill does not atomically flip every chain at once — it repoints chain-by-chain, then rotates the CI secret and re-verifies the pause flow.
| Situation | Skill | |---|---| | Rotate the emergency-pause EOA (pauserWallet) | this skill | | Rotate the deployer (safeOwners[0] + Timelock CANCELLER) | rotate-deployer-wallet | | Rotate the staging diamond owner (Dev wallet) | rotate-dev-wallet | | Full SC-dev offboarding across all three roles | offboard-sc-dev (it calls this skill) |
NOT for changing what EmergencyPauseFacet does (that is a facet-logic change, deployed via deploy-contract on its own) — this skill only changes who the pauser is.
--new-address 0xNEW — the new pauser EOA (securely generated by a human; see Guardrails). Required unless the orchestrator passes it.--check — dry-run: run Phase 5's verification read-only against the current state and report what a rotation would change, without deploying, cutting, or moving anything.config/global.json — read the pauser currently baked into the live EmergencyPauseFacet (its constructor arg / the address the facet reports), because global.json can be mid-rotation-inconsistent.multisig-rollout → script/deploy/safe/confirm-safe-tx.ts; this skill hands off and WAITS — it never runs the signer.SEND_PROPOSALS_DIRECTLY_TO_DIAMOND=true.global.json.verifyEmergencyPauseReadiness.yml live partly outside contracts — coordinate the rotation, don't fake rotating a secret you can't see.0 success; 1 real error (report stderr, stop, no retry/fallback); 2 recoverable misconfig (name the missing env/credential).bunx tsx) or Bash only, never Python. Foundry/bun may need export PATH="$HOME/.foundry/bin:$HOME/.bun/bin:$PATH".Ordering is deliberate: repoint → sweep → CI funding check → CI secret + pause-flow re-verify → config. Repoint first so the new pauser is live before we sweep gas out of the old one and retire it.
Run from the repo root. Report (don't fix silently):
.env present; PRODUCTION matches the intended environment; SEND_PROPOSALS_DIRECTLY_TO_DIAMOND not true.forge --version); gh auth status OK; VPN up for MongoDB (needed by multisig-rollout / check-rotation-status).grep -m1 "@custom:version" src/Facets/EmergencyPauseFacet.sol — the redeploy must ship a new pauser, so bump/confirm the version per repo convention before deploying.The new pauser is a constructor argument of EmergencyPauseFacet, so it is set at deploy time (CREATE3). Confirm the deploy script wires the new pauser into the constructor — the address baked in must be the new one, verified before cutting.
/deploy-contract EmergencyPauseFacet <network...> — deploys, explorer-verifies, and diamondCuts the new facet directly./multisig-rollout EmergencyPauseFacet — discovers every chain where EmergencyPauseFacet is live, deploys via deploy-contract, creates one timelock-wrapped diamondCut proposal per chain, drafts the deployment-log PR, hands off Ledger signing, verifies signatureCount >= 2, and posts #dev-sc-multisig-proposals. Include Tron — its diamond also hosts the facet and must be cut too.Do not reimplement the deploy/cut/propose plumbing; deploy-contract and multisig-rollout own it. Carry forward the per-network new facet addresses for the config update and verification.
Once the new pauser is live on every chain, drain residual native gas from the old pauser EOA into the new one so nothing is stranded on the retired key:
text/sweep-wallet-funds --new-address <NEW_PAUSER> --old-key-env PRIVATE_KEY_PRODUCTION --production
sweep-wallet-funds previews balances first (dry-run), moves native across all active EVM chains (native swept last), and reports per-network moved/skipped. Tron native has no multi-chain script — it flags a single manual troncast send.
Confirm the new pauser is funded on the chains CI expects (the emergency-pause funding gate). This is the funding slice of the rotation status check:
text/check-rotation-status --old-address <OLD_PAUSER> --new-address <NEW_PAUSER> --role pauser --production
Read-only. If a chain shows the new pauser underfunded, top it up (/manage-wallet-funds send for a single chain, or /request-dev-funds for a PR-based top-up) before treating the rotation as complete.
The pauser's key is also held as a CI secret that drives the automated pause path, and its readiness is asserted by verifyEmergencyPauseReadiness.yml. Both live partly outside contracts:
verifyEmergencyPauseReadiness.yml is green against the new pauser so the automated pause flow actually works end-to-end.If either is outside your reach in this session, surface it explicitly as a human/operational follow-up rather than marking it done.
Land the pauser role change in the repo:
text/update-wallet-config --role pauser --new-address <NEW_PAUSER> --production
update-wallet-config updates the EVM field and the matching tronWallets.pauser (deriving the Tron base58 from the new EVM address and cross-checking the reverse), honors config-structure rule 004, and ends by calling /create-pr. The Notion wallet-registry update is a follow-up it flags (needs auth) — don't fake it.
Gate the rotation complete only when all hold:
EmergencyPauseFacet selectors to the newly deployed facet, and that facet reports the new pauser (read it back — do not infer from the proposal).signatureCount >= 2 and posted for the remaining signer(s) (multisig-rollout's gate) — timelock ops execute after the delay via the scheduled pipeline.check-rotation-status shows the new pauser funded on every CI-expected chain.verifyEmergencyPauseReadiness.yml is green (or the coordination follow-up is explicitly logged).update-wallet-config PR (EVM + tronWallets.pauser) is open; Notion registry follow-up noted.--check runs this section read-only and reports the delta without changing anything.
| Step | Calls | |---|---| | Repoint (staging / testnets) | /deploy-contract EmergencyPauseFacet <network...> | | Repoint (production Safe proposals, incl. Tron) | /multisig-rollout EmergencyPauseFacet | | Fund the new pauser from the old | /sweep-wallet-funds --new-address <NEW> --old-key-env PRIVATE_KEY_PRODUCTION --production | | Single-chain top-up / PR top-up | /manage-wallet-funds send / /request-dev-funds | | Funding + role verification gate | /check-rotation-status --old-address <OLD> --new-address <NEW> --role pauser --production | | Land the config change | /update-wallet-config --role pauser --new-address <NEW> --production | | Facet version marker | grep -m1 "@custom:version" src/Facets/EmergencyPauseFacet.sol |
CI secret rotation and verifyEmergencyPauseReadiness.yml live partly outside this repo — coordinated, not owned here.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 17,684 | 8,374 | -53% | 1 | 1 | 0% | 3,120 | 3,168 | +2% | 0 | 0 | — |
case-07 | fail→pass | 10,079 | 4,413 | -56% | 1 | 1 | 0% | 1,624 | 3,344 | +106% | 0 | 0 | — |
case-02 | fail→fail | 16,343 | 7,320 | -55% | 1 | 1 | 0% | 3,200 | 3,053 | -5% | 0 | 0 | — |
case-03 | fail→pass | 16,839 | 8,244 | -51% | 1 | 1 | 0% | 2,948 | 4,347 | +47% | 0 | 0 | — |
case-04 | fail→pass | 11,133 | 6,471 | -42% | 1 | 1 | 0% | 1,861 | 3,861 | +107% | 0 | 0 | — |
case-05 | fail→fail | 7,690 | 6,356 | -17% | 1 | 1 | 0% | 1,303 | 3,917 | +201% | 0 | 0 | — |
case-06 | fail→pass | 9,145 | 3,097 | -66% | 1 | 1 | 0% | 1,486 | 3,067 | +106% | 0 | 0 | — |
case-08 | fail→pass | 11,600 | 3,305 | -72% | 1 | 1 | 0% | 1,784 | 3,079 | +73% | 0 | 0 | — |
case-09 | fail→pass | 11,635 | 3,997 | -66% | 1 | 1 | 0% | 2,255 | 3,294 | +46% | 0 | 0 | — |
case-10 | fail→pass | 8,542 | 5,707 | -33% | 1 | 1 | 0% | 1,398 | 3,589 | +157% | 0 | 0 | — |
case-11 | fail→pass | 12,724 | 16,832 | +32% | 1 | 1 | 0% | 2,020 | 3,357 | +66% | 0 | 0 | — |
case-21 | fail→pass | 7,834 | 3,653 | -53% | 1 | 1 | 0% | 1,225 | 3,124 | +155% | 0 | 0 | — |
case-12 | pass→pass | 10,524 | 7,297 | -31% | 1 | 1 | 0% | 1,843 | 3,895 | +111% | 0 | 0 | — |
case-13 | fail→pass | 12,634 | 2,935 | -77% | 1 | 1 | 0% | 2,124 | 2,961 | +39% | 0 | 0 | — |
case-14 | fail→pass | 8,220 | 2,723 | -67% | 1 | 1 | 0% | 1,500 | 2,972 | +98% | 0 | 0 | — |
case-15 | fail→pass | 11,528 | 3,977 | -66% | 1 | 1 | 0% | 2,020 | 3,167 | +57% | 0 | 0 | — |
case-22 | fail→pass | 15,558 | 5,136 | -67% | 1 | 1 | 0% | 2,388 | 3,330 | +39% | 0 | 0 | — |
case-16 | pass→pass | 7,000 | 2,107 | -70% | 1 | 1 | 0% | 1,267 | 2,898 | +129% | 0 | 0 | — |
case-17 | fail→pass | 18,138 | 5,125 | -72% | 1 | 1 | 0% | 3,723 | 3,567 | -4% | 0 | 0 | — |
case-18 | pass→pass | 12,620 | 4,410 | -65% | 1 | 1 | 0% | 2,200 | 3,201 | +46% | 0 | 0 | — |
case-19 | fail→pass | 18,588 | 5,844 | -69% | 1 | 1 | 0% | 3,244 | 3,570 | +10% | 0 | 0 | — |
case-20 | fail→pass | 6,844 | 2,634 | -62% | 1 | 1 | 0% | 1,062 | 2,999 | +182% | 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 20 counted toward the lift figure. The other 2 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 +73 percentage points is the difference between those two pass rates over the 20 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.