ByAUJay
Summary: Sunsetting a DeFi protocol without breaking user funds, fragmenting liquidity, or triggering MEV exploits requires a surgical plan across governance, Solidity upgrades, cross-chain assets, and user migration. Below is our repeatable, metrics-driven playbook to deprecate contracts safely and on schedule.
Title: Deprecating a Smart Contract: How to Sunset a Protocol Gracefully
Target audience: DeFi teams (keywords: Gas optimization, MEV protection, cross-chain liquidity, governance timelock, UUPS/Transparent proxies)
Pain — the specific headache you’re likely feeling
- You need to retire an old set of contracts (e.g., v1 liquidity pools, vaults, or token wrappers) and migrate users to v2/v3 without freezing funds or nuking TVL.
- Your system mixes upgradeable and immutable components, has a few on-chain governance constraints, and straddles L2s where “canonical” tokens changed (USDC.e → USDC). The wrong deprecation order can strand assets or break routes. (docs.optimism.io)
- “We’ll just selfdestruct and redeploy” is no longer viable: EIP-6780 changed SELFDESTRUCT semantics, so you can’t rely on metamorphic patterns to swap logic at the same address. (eips.ethereum.org)
- The last-mile user journey is brittle: approvals linger (Permit2), MEV bots can sandwich migration swaps, and stale LP tokens may become illiquid on secondary markets. (docs.uniswap.org)
Agitation — the risk if you get this wrong
- Missed deadlines cascade: governance timelocks delay upgrades; if you pause in the wrong place, users cannot exit to safety in time. (docs.openzeppelin.com)
- Liquidity fragmentation: fail to map bridged vs native assets correctly (e.g., USDC.e vs USDC on OP/Arbitrum), and your new pools launch shallow while the old ones keep routing volume. Ops teams then spend months chasing “where did the TVL go?” (docs.optimism.io)
- Security regressions: rushed UUPS/Transparent upgrades that skip storage-layout validation brick proxies or open reentrancy windows. Formal tools catch these, but only if wired into CI before the freeze. (docs.openzeppelin.com)
- User losses and reputational damage: Permit2 signatures reused in phishing flows drain wallets during “approve then migrate” UX; public mempool submissions of bulk exits leak alpha to MEV. (decrypt.co)
Solution — 7Block Labs’ methodology to sunset safely (and measurably)
Phase 0 — Control plane hardening (week 0)
- Move upgrade rights to a TimelockController with 48–120h min delay; set proposer = DAO/multisig; executor = timelock or open; then renounce external admin. This ensures every maintenance action (including deprecation) is delayed and observable. (docs.openzeppelin.com)
- Bind on-chain governance to a Governor with ERC‑6372 clock-awareness so your voting windows are consistent across chains where block-time semantics differ. (docs.openzeppelin.com)
Phase 1 — Architecture-specific deprecation plan (week 1–2) We inventory your deployments and choose the precise deprecation mechanism per artifact:
- ERC‑1967 UUPS or Transparent proxies
- Strategy: one final upgrade to a “WithdrawOnly” implementation that:
- Disables state-mutating entrypoints except withdraw/unstake/claim.
- Sets fees to 0 and emits DeprecationNotice(version, newAddress, deadline).
- Optionally enforces a grace period via the timelock for transparency.
- Why: UUPS is now the recommended, gas-efficient pattern; both UUPS and Transparent share ERC‑1967 slots, so the cutover is predictable and observable. (docs.openzeppelin.com)
- Guardrails: use validateUpgrade and storage-gap checks in CI; never “unsafeSkipStorageCheck” unless a formal proof justifies it. (docs.openzeppelin.com)
- Beacon proxies
- Strategy: single beacon upgrade to the WithdrawOnly implementation to freeze a fleet of instances atomically. Ideal for factories with many children. (docs.openzeppelin.com)
- Diamonds (ERC‑2535/8109)
- Strategy: diamondCut to Remove or Replace state-changing selectors; keep read paths and exit functions; emit DiamondCut with a DeprecationFacet that routes users to vNext. (eips.ethereum.org)
- Immutable contracts (no proxy)
- Strategy: if Pausable or an “escape hatch” exists, switch to withdraw‑only; otherwise, deploy a Migrator with Merkle snapshots (or zk attestations if privacy needed) for claims to vNext. Note: SELFDESTRUCT deprecation is off the table post‑EIP‑6780. (blog.openzeppelin.com)
Illustrative Solidity: Withdraw‑Only final implementation (UUPS/Transparent)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24; import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import "@openzeppelin/contracts/security/Pausable.sol"; contract Vault_Deprecated is UUPSUpgradeable, ReentrancyGuard, Pausable { address public immutable NEW_ADDRESS; uint64 public immutable DEPRECATION_DEADLINE; // epoch seconds event DeprecationNotice(address indexed newAddress, uint64 deadline); event Exit(address indexed user, uint256 assets); // storage layout preserved; add vars only if gap permits (use OZ storage gaps) uint256[49] private __gap; constructor(address _new, uint64 _deadline) { NEW_ADDRESS = _new; DEPRECATION_DEADLINE = _deadline; } function initialize() external initializer { emit DeprecationNotice(NEW_ADDRESS, DEPRECATION_DEADLINE); _pause(); // start paused; unpause only for exit functions below } // UUPS auth — restrict to timelock/owner, but we expect no further upgrades function _authorizeUpgrade(address) internal view override { revert("Sunset: upgrades disabled"); } // Exit path — allow only withdraws/claims; everything else hard‑reverts function withdraw(uint256 assets) external nonReentrant whenPaused { // read-only calc; state changes only to settle user balance and transfer // ... emit Exit(msg.sender, assets); } // Block any unintended calls fallback() external payable { revert("Sunset"); } receive() external payable { revert("Sunset"); } }
Notes:
- UUPS is lighter for gas than Transparent (upgrade logic in implementation). Keep ERC‑1967 slot hygiene. Run validateUpgrade against the live proxy before scheduling. (docs.openzeppelin.com)
Phase 2 — Cross-chain token and LP migration (week 2–3)
- USDC.e → USDC: if you route on OP or Arbitrum, align with Circle’s native contract addresses and Optimism/Arbitrum guidance; surface warnings in UI, and auto-swap bridged to native via CCTP where feasible. (docs.optimism.io)
- LPs: provide a single-step router that burns v1 LP, retrieves assets, and mints v2 LP atomically. Always submit via private orderflow (Flashbots Protect) to avoid sandwiching and ensure “no revert, no fee.” (docs.flashbots.net)
- Bridges: if you previously wrapped canonical tokens, publish the deprecation window and maintain withdrawals on the old bridge but block new deposits post‑deadline.
Phase 3 — MEV-safe, approval-minimal user flows (week 3–4)
- MEV protection: default all “migrate” transactions to Flashbots Protect RPC; for whales, enable MEV‑Share configurations balancing hints vs privacy; only land non-reverting bundles. Document that 0 priority fee is rejected on Protect. (docs.flashbots.net)
- Approval hygiene:
- Prefer ERC‑2612 permit where tokens support it to reduce on-chain approvals during migration.
- If integrating Permit2, bound allowances (amount/duration) and display human-readable scopes; educate users on phishing risks and provide revoke flows. (docs.uniswap.org)
Phase 4 — Security engineering and CI (continuous through freeze)
- Upgrades safety: enforce OpenZeppelin Upgrades validate/validateUpgrade in CI; require storage-layout diffs clean, gaps respected, and no unsafe flags. (docs.openzeppelin.com)
- Static + fuzz + formal:
- Slither/Aderyn rules catch legacy selfdestruct usage and risky patterns pre‑EIP‑6780. (rya-sge.github.io)
- Echidna/Medusa invariants for “withdraw-only” paths and migrator idempotence; add action-replay tests for EIP‑712 signatures. (github.com)
- Certora rules for upgrade authorization and access invariants across timelock/owner paths. (docs.certora.com)
Phase 5 — Communications, timelines, and controlled pausing
- Emergency stops: Pausable is a tool, not a blanket. Keep “escape hatches” live while pausing new interactions; OWASP flags lack of emergency stop as a security weakness, but pausing must not lock exits. (blog.openzeppelin.com)
- Governance scheduling: publish deprecation transactions with timelock IDs and queue/execution timestamps so integrators (routers, analytics, market makers) can plan reindexing. (docs.openzeppelin.com)
Practical examples we’ve recently implemented
- Proxy fleet sunset via beacon
- Context: A derivative protocol with thousands of per-market proxies (beacon pattern).
- Action: Single beacon upgrade to WithdrawOnly implementation; exit-only period 21 days; fees zeroed; emitted DeprecationNotice events with vNext addresses.
- Why it worked: one transaction updated all proxies consistently; events made The Graph subgraphs trivial to migrate. (docs.openzeppelin.com)
- Immutable staking v1 → proxy v2 with Merkle snapshot
- Context: v1 was immutable; only emergencyWithdraw existed.
- Action: Snapshot balances; deploy Migrator with Merkle proofs; users claim v2 position with a one-click claim guarded by EIP‑712 signed terms; all claims routed via Protect RPC.
- Extra: Deployed a “nudge” hook in the v1 front-end to default to private RPC.
- USDC.e to USDC canonical shift on OP/Arbitrum
- Context: Existing pools held USDC.e; analytics and routers lagged native USDC adoption.
- Action: Enabled on-chain auto-detection of token type and fallback to CCTP mint for canonical USDC; published a 30‑day wind-down calendar and UI interstitials; prevented new deposits to USDC.e pools after T+7. (docs.optimism.io)
Emerging best practices to adopt in 2026 deprecations
- Don’t rely on SELFDESTRUCT for lifecycle control; post‑EIP‑6780 it only transfers ETH and won’t remove code except in same‑tx creations. Build life‑cycle switches explicitly. (eips.ethereum.org)
- Prefer UUPS over Transparent proxies for new deployments; keep admin separation via ProxyAdmin or timelock as appropriate; always emit Upgraded and AdminChanged per ERC‑1967. (docs.openzeppelin.com)
- Use ERC‑2535 (or ERC‑8109 simplified spec) for large modular systems; deprecate by removing selectors instead of hot-replacing risky facets. (eips.ethereum.org)
- MEV-aware migrations are the default; plan for private orderflow and refunds; document your Protect RPC parameters for power users. (docs.flashbots.net)
- Approval minimization with Permit2 must be bounded and transparent; teach users to revoke. Incorporate checks for stale Permit2 allowances in the app. (docs.uniswap.org)
Gas optimization you actually feel in ROI
- Minimize on-chain loops during claims; push iteration off-chain and prove membership via Merkle (or zk if privacy needed).
- UUPS upgrades reduce proxy overhead vs Transparent; fewer moving parts per upgrade lowers gas and operational risk. (docs.openzeppelin.com)
- Use EIP‑1167 Clones for temporary adapters/routers you’ll retire after migration; keep them immutable and cheap. (eips.ethereum.org)
What we deliver (and how Procurement measures it)
- Migration Risk Register + Gantt with on-chain proposal IDs, queue/ETA/execute windows, and recipients.
- Governance artifacts: Governor + TimelockController configs, quorum/thresholds aligned to ERC‑6372 clocks; owner transfers documented. (docs.openzeppelin.com)
- Engineering assets:
- Final “WithdrawOnly” implementations for all upgradeable components.
- Immutable Migrator with Merkle snapshot tooling and one-click user claim flow.
- Flashbots Protect integration guide, default RPCs, and mempool-avoidance policy. (docs.flashbots.net)
- CI gates: OpenZeppelin validateUpgrade; Slither/Aderyn checks for deprecated opcodes; Echidna invariants; Certora rules for access and upgrade safety. (docs.openzeppelin.com)
- Cross-chain plan: canonical token mapping and deadlines (USDC native vs bridged), router updates, and partner notifications. (docs.optimism.io)
GTM metrics we tie to compensation
- TVL Retention: ≥95% of v1 TVL migrated to vNext within 14 days of GA.
- Support Burndown: <1% of active users open migration tickets after Day 7.
- MEV Slippage: <10 bps median on migration swaps routed via Protect; 0 failed on-chain migration txs (by using private bundles). (docs.flashbots.net)
- Approval Hygiene: ≥80% of flows use permit/Permit2 with bounded scope and auto-revoke prompts; zero confirmed Permit2 phishing incidents across official UX. (docs.uniswap.org)
Implementation timeline (reference)
- Week 0: Control plane hardening (timelock/governor), role transfers; publish calendar and RFC.
- Week 1–2: Finalize deprecation implementations; CI proves storage/layout safety.
- Week 2–3: Cross-chain canonical mapping, routers and CCTP paths; partner notices (MMs, indexers).
- Week 3–4: Staged rollouts; Protect RPC defaults; exit-only windows; analytics dashboards for KPIs.
Where 7Block fits (and links)
- Full-stack delivery from migration design to shipping code and audits under one roof:
- Smart contracts and migrators: see our smart contract development solutions and custom blockchain development services.
- DeFi protocol upgrades, vaults/pools/routers: our DeFi development services.
- Security reviews and upgrade runbooks: our security audit services, with fuzz/formal integration.
- Cross-chain liquidity and bridge planning: our cross-chain solutions development and blockchain integration.
- dApp UX for migration flows, including MEV-safe paths and approval hygiene: our dApp development solutions.
Appendix — checklists you can copy into your runbook
Governance and scheduling
- TimelockController configured; proposer/executor roles set; deployer renounced; minDelay communicated. (docs.openzeppelin.com)
- Governor vote windows match token clock mode (ERC‑6372). (docs.openzeppelin.com)
Contract-level changes
- For proxies: validateUpgrade passes; Upgraded/AdminChanged events emitted; final implementation enforces withdraw‑only. (docs.openzeppelin.com)
- For diamonds: selectors removed/replaced; DiamondCut emitted. (eips.ethereum.org)
- For immutable: Pausable escape hatch or Merkle/zk migrator deployed; SELFDESTRUCT never relied upon. (docs.openzeppelin.com)
Cross-chain and assets
- Canonical addresses confirmed (e.g., USDC on OP/Arb); USDC.e labeled legacy; CCTP path documented. (docs.optimism.io)
- Bridges keep withdraws open; new deposits blocked per schedule.
User flows and MEV
- Migrations default to Flashbots Protect RPC; public mempool usage disabled in app; whales get extra privacy guidance. (docs.flashbots.net)
- Permit/Permit2 bounded approvals; explicit revoke UX; phishing warnings included. (docs.uniswap.org)
Security & CI
- Slither/Aderyn pass, including “selfdestruct deprecated” flags. (rya-sge.github.io)
- Echidna invariants: (1) exits idempotent, (2) no state‑increasing paths exist, (3) claims bounded by snapshot. (github.com)
- Certora rules: only timelock can schedule deprecations; no write after deadline except exits. (docs.certora.com)
If you want this executed with accountability, not hope, we’ll run the migration as a project with KPI guarantees and clear owner-of-record across governance, code, comms, and partners. Let’s make your next launch about shipping vNext, not firefighting vOld.
CTA: Book a DeFi Sunset Strategy Call
References
- EIP‑6780 SELFDESTRUCT changes; do not rely on metamorphic redeploy patterns. (eips.ethereum.org)
- ERC‑1967 storage slots; UUPS/Transparent proxy guidance (OpenZeppelin). (eips.ethereum.org)
- UUPS proxy pattern and benefits. (docs.openzeppelin.com)
- Diamond standard for modular systems (ERC‑2535, ERC‑8109 draft). (eips.ethereum.org)
- OpenZeppelin Governance with ERC‑6372 clocks; Timelock best practices. (docs.openzeppelin.com)
- Flashbots Protect/MEV‑Share docs; private orderflow and refunds. (docs.flashbots.net)
- Uniswap Permit2 (benefits and phishing risks). (docs.uniswap.org)
- USDC native on OP/Arbitrum and migration from USDC.e. (docs.optimism.io)
- Upgrades CI—storage layout validation and gaps. (docs.openzeppelin.com)
- Slither/Aderyn selfdestruct detectors; Echidna/Medusa fuzzing; Certora Prover rules. (rya-sge.github.io)
7Block Labs services (quick links)
- Blockchain development services: https://7blocklabs.com/services/blockchain-development-services
- Security audit services: https://7blocklabs.com/services/security-audit-services
- Cross-chain solutions development: https://7blocklabs.com/services/cross-chain-solutions-development
- DeFi development services: https://7blocklabs.com/solutions/defi-development-services
- Smart contract development: https://7blocklabs.com/solutions/smart-contract-development
- Blockchain integration: https://7blocklabs.com/services/blockchain-integration
Book a DeFi Sunset Strategy Call
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

