---
name: lifinance/offboard-sc-dev
source: https://app.decimal.ai/s/lifinance-offboard-sc-dev@1/SKILL.md
source_sha256: 490ab3b4dcc2
---

# Offboard SC Dev (LI.FI Contracts)

Drives the smart-contract half of offboarding a departing SC team member: remove them as a Safe multisig signer, add their replacement, and rotate every **shared** wallet they had custody of to a freshly generated one. This is the orchestrator — it **calls** the per-role rotate-* skills and `multisig-rollout`; it does not reimplement any rotation.

**v1 scope — EXECUTE-ONLY.** This skill assumes the offboarding **Linear ticket tree already exists** (created by hand, modeled on EXSC-558) and its job is to *execute* that plan. It does **not** generate the ticket tree. Auto-creating the tickets is a deliberate **fast-follow** — call it out at the start so the user knows to have the tree ready, and don't silently skip a step because a ticket is missing.

Why an orchestrator and not one big script: each role has a different rotation mechanism (Safe owner swap, staging owner transfer, immutable-facet redeploy), and each is independently useful and independently tested. This skill sequences them by dependency and holds the custody guard across all of them.

## When to use / when NOT

| Situation | Skill |
|---|---|
| Full SC-dev offboarding (signer swap + all shared wallets) | **this skill** |
| Just the deployer wallet | `rotate-deployer-wallet` |
| Just the staging owner (Dev wallet) | `rotate-dev-wallet` |
| Just the emergency pauser | `rotate-pauser-wallet` |
| A single production rollout / signer swap on its own | `multisig-rollout` |

NOT for non-SC offboarding (HR/IT deprovisioning is out of scope) and NOT for rotating a CTO-owned wallet (refund / feeCollector / withdraw — see custody guard).

## Inputs

- `--person <name>` — the departing SC dev, resolved from the offboarding Linear tree (EXSC-558-style).
- `--removed-signer 0x` — the departing person's personal multisig signer seat to remove (human-supplied / ticket-sourced).
- `--new-signer 0x` — the replacement personal multisig signer to add (human-supplied / ticket-sourced).
- `--linear EXSC-XXX` — the parent offboarding ticket (the pre-existing tree this run executes). If absent, ask for it — do not invent a tree.
- New wallet addresses for **deployer, dev, pauser** — securely generated by a human (the blocking first step, below). Old addresses are **derived from keys / on-chain state, never from `config/global.json`** (it can be mid-rotation-inconsistent).

## Guardrails

- **Custody guard.** Rotate only the SC-owned shared wallets (**deployer, dev, pauser**) plus swap the departing person's **personal multisig signer** seat. NEVER rotate the CTO-owned refund / feeCollector / withdraw — if the ticket tree implies touching one, stop and escalate.
- **Never self-sign.** New-key generation is a human step. Every Safe proposal (signer swap, deployer's Safe-owner / CANCELLER moves, pauser diamond cuts) is human Ledger-signed via `multisig-rollout` → `script/deploy/safe/confirm-safe-tx.ts`; this skill and the ones it calls hand off and WAIT — none run the signer.
- **Never bypass Safe/timelock** (rule 002-architecture). All owner/role/pauser on-chain changes go through `multisig-rollout` — no direct cuts, no `SEND_PROPOSALS_DIRECTLY_TO_DIAMOND=true`.
- **Secrets hygiene.** Never print a private key or full RPC URL. Derive every old address from its key or on-chain state, never from `config/global.json`.
- **Exit-code convention** for sub-skills / scripts: `0` success; `1` real error (report, stop, no retry); `2` recoverable misconfig (name the missing env/credential). A failing network in one rotation must not silently abort the others — surface it and let the operator decide.
- Scripting is TypeScript (`bunx tsx`) or Bash only, never Python. Foundry/bun may need `export PATH="$HOME/.foundry/bin:$HOME/.bun/bin:$PATH"`.

## Workflow

Ordered by dependency. The new keys must exist and be funded before anything on-chain can move, so key generation is the **blocking first human step**; the signer swap and deployer rotation come next because they change who can sign; dev and pauser follow; secret rotation and the completeness gate close it out.

### Phase 0 — Preflight & scope confirmation

Run from the repo root. Confirm and report (don't fix silently):

- The Linear offboarding tree (`--linear`, EXSC-558-style) exists and is the plan being executed. State the EXECUTE-ONLY scope note: ticket-tree creation is a fast-follow, not done here.
- Departing person, their replacement signer, and which of the three shared wallets they held (all should be rotated regardless — the departing person loses access to all shared keys).
- `.env` present, `PRODUCTION` correct, `SEND_PROPOSALS_DIRECTLY_TO_DIAMOND` not `true`; Foundry, `gh auth status`, VPN (MongoDB), Slack MCP all available (Slack + VPN needed by `multisig-rollout`).
- Set the interaction model up front: this is **semi-automated** — it will pause for the human to (a) generate keys and (b) sign proposals on a Ledger, then resume. Tell the user the pauses are coming so they don't complete signing steps by hand.

### Phase 1 — Generate + fund the new wallets (BLOCKING human step)

Nothing on-chain can proceed until the replacement keys exist. The human securely generates the new **deployer, dev, and pauser** keys and their replacement personal signer, and provides the addresses (never the keys, never via `global.json`). Fund the new deployer/dev/pauser enough to broadcast where each rotation needs gas — the individual rotate-* skills sweep the bulk from the old wallets, but the new deployer needs bootstrap gas *before* it can broadcast. Wait for the addresses before continuing.

> **HyperEVM big blocks.** The new **deployer** and **dev** EOAs each need big blocks enabled on `hyperevm` before they can deploy there — an L1, per-address setting that does not carry over on rotation. `rotate-deployer-wallet` and `rotate-dev-wallet` each flag this in their funding phase; follow the runbook: `docs/HyperEVMBigBlocks.md`. (The **pauser** does not deploy, so it is exempt.)

### Phase 2 — Swap the multisig signer (remove departing, add replacement)

Change the Safe ownership set on every production chain: remove the departing person's personal signer, add the replacement. This is a Safe owner change, so it runs through the production rollout lifecycle:

```text
/multisig-rollout
```

driven for the owner-swap (add replacement + remove departing signer) across all chains — proposals → PR → **human Ledger signing (hand off, wait)** → verify `signatureCount >= 2` → post `#dev-sc-multisig-proposals`. Do not run `confirm-safe-tx.ts` yourself. Wait for the user to confirm signing before treating the swap as landed.

### Phase 3 — Rotate the deployer wallet

Heaviest governance role (`safeOwners[0]` + Timelock `CANCELLER_ROLE` + prod timelock executor), so it goes before the lighter roles:

```text
/rotate-deployer-wallet --new-address <NEW_DEPLOYER>
```

It sweeps old→new first (bootstrap gas), swaps the Safe owner + moves `CANCELLER_ROLE` via `multisig-rollout` (human signs), handles Tron ownership + delegation, updates config, and decommissions the old key. Let it own its own signing hand-offs; wait for it to report complete.

### Phase 4 — Rotate the dev wallet

Staging diamond owner — lowest-stakes, the reference rotation:

```text
/rotate-dev-wallet --new-address <NEW_DEV>
```

It funds the new dev by sweeping the old, transfers staging diamond ownership old→new, moves the Tron delegation, updates config, and self-verifies.

### Phase 5 — Rotate the pauser wallet

Immutable pauser → redeploy `EmergencyPauseFacet` with the new pauser and cut it into every diamond:

```text
/rotate-pauser-wallet --new-address <NEW_PAUSER>
```

It repoints (via `deploy-contract` / `multisig-rollout`, incl. Tron), sweeps the old pauser, runs the CI funding check, rotates the CI pauser secret + re-verifies `verifyEmergencyPauseReadiness.yml` (coordinated, partly outside this repo), and updates config.

### Phase 6 — Shared-secret rotation checklist

Beyond the on-chain wallets, the departing person had access to shared secrets that must be rotated so their leaving revokes access. Work the checklist modeled on **EXSC-567** (RPC keys, API tokens, CI secrets, any shared credential store). These live largely **outside** `contracts` — coordinate with the secret owners and record what was rotated. Do NOT mark a secret rotated that this session cannot actually reach; surface it as a human/operational follow-up.

### Phase 7 — Completeness gate

The single source of truth that the offboarding actually took effect everywhere, per rotated role:

```text
/check-rotation-status --old-address <OLD_ADDR> --new-address <NEW_ADDR> --role <deployer|dev|pauser> --removed-signer <DEPARTING_SIGNER> --production
```

Run it once per rotated role. Each invocation verifies only the checks that apply to that role: **deployer** — Safe-owner membership (departing removed / replacement added; old deployer removed / new added), Timelock `CANCELLER_ROLE` (old removed / new granted), whitelist role, and wallet funding; **dev** — staging-diamond `owner()` and wallet funding; **pauser** — wallet funding and CI pauser config. Read-only. The offboarding is **not** complete until every role passes on every network. Any red row → go back to the owning rotate-* skill for that role and network.

## Verification

Offboarding is complete only when ALL hold:

- **Signer swap:** departing personal signer removed and replacement added on every production Safe (`check-rotation-status` green; proposals signed and executed via the timelock pipeline).
- **Deployer:** `safeOwners[0]` is the new deployer, `CANCELLER_ROLE` moved, Tron ownership + delegation moved, old deployer key decommissioned.
- **Dev:** staging diamond `owner()` is the new dev on every chain (incl. Tron staging), delegation moved.
- **Pauser:** every diamond routes `EmergencyPauseFacet` to the facet carrying the new pauser; CI secret rotated + pause-flow re-verified (or logged as coordination follow-up).
- **Secrets:** EXSC-567-style checklist worked; anything outside reach logged as a follow-up, not faked.
- **Config:** the per-role `update-wallet-config` PRs are open (EVM + `tronWallets.*`); Notion registry follow-ups noted.
- **Fast-follow logged:** the ticket-tree auto-creation gap (v1 execute-only) recorded for a later version.

## Reuse map

| Step | Calls |
|---|---|
| Multisig signer swap (remove departing, add replacement) | `/multisig-rollout` |
| Rotate deployer (`safeOwners[0]` + CANCELLER) | `/rotate-deployer-wallet` |
| Rotate dev (staging owner) | `/rotate-dev-wallet` |
| Rotate pauser (immutable → redeploy `EmergencyPauseFacet`) | `/rotate-pauser-wallet` |
| Completeness gate (signer swap + all roles, all networks) | `/check-rotation-status --old-address <OLD> --new-address <NEW> --role <role> --removed-signer <DEPARTING_SIGNER> --production` |
| Config PRs per role (called *inside* each rotate-* skill) | `/update-wallet-config` |
| Fund sweeps per role (called *inside* each rotate-* skill) | `/sweep-wallet-funds` |

Shared-secret rotation (EXSC-567) and Linear ticket-tree creation live outside this skill — coordinated / fast-follow, not owned here.