DeFi Intel

Contract Deactivation

ERC: Contract Deactivation Interface — a standard signal for permanently deactivating a token contract ERC draft: ERCs/ERCS/erc-deactivation.md at erc-deactivation · rya-sge/ERCs · GitHub Summary I’d like to propose a minimal ERC that standardizes how a smart contract signals that it has been permanently deactivated — a one-way, terminal state distinct from a temporary pause. It defines a single one-way operation, deactivateContract() , and a deactivated() status view, so wallets, exchanges, custodians, indexers, and protocols can reliably detect that a contract is no longer active. Draft ERC: [link to be added once submitted — ERC number not yet assigned] Motivation Pause mechanisms are great for temporary incidents. They fall short for terminal lifecycle events, where an issuer needs to communicate that a contract is not meant to be reactivated — ever. This matters especially for regulated Real-World Asset (RWA) tokens, but the need is broader. Concrete cases: security migration to a new contract after a legal restructuring, capitalization events (merger, split, reverse split) requiring old units to be immobilized, an issuer decision to discontinue a ledger-based representation, DeFi market shutdowns — lending pool or AMM pair retirement — where operators need a clear “permanently inactive” signal. Today, integrators cannot reliably distinguish between: a temporary pause, an operational outage, a permanent deactivation. They all look similar from the outside. This ERC standardizes the “no longer active, permanently” signal so it can be detected consistently. It’s also worth noting that since EIP-6780 (Dencun), SELFDESTRUCT no longer deletes a deployed contract’s code or storage — it only forwards the remaining ether, and full deletion is only possible in the same transaction the contract was created. In other words, there is no longer any way to actually destroy a deployed contract: it keeps its code and stays callable forever. So an explicit, application-level “permanently deactivated” status is now the only way to signal end-of-life. Specification (summary) interface IERCDeactivation is IERC165 { /// @notice Emitted when the contract is permanently deactivated. event Deactivated(address indexed account); /// @notice Raised when deactivation is attempted after it is already final. error AlreadyDeactivated(); /// @notice Permanently deactivates the contract. function deactivateContract() external; /// @notice Returns whether the contract has been deactivated. function deactivated() external view returns (bool isDeactivated); } Required behavior (highlights): One-way state : deactivated() returns false before deactivation and true after; in the active implementation it MUST NOT return to false . The call : deactivateContract() MUST set the state, emit Deactivated(account) , be access-controlled, and revert with AlreadyDeactivated() if already deactivated. Pause precondition (optional) : implementations using a pause mechanism SHOULD require the contract to be paused first. Post-deactivation guarantees : holder-initiated asset movements ( transfer / transferFrom , ERC-721/ERC-1155 equivalents) and normal lifecycle mint / burn MUST revert. unpause , if present, MUST revert. Only explicitly named privileged emergency/regulatory operations (e.g. forcedTransfer ) MAY remain, and MUST be documented as post-deactivation-enabled. Holder exit exception : implementations MAY keep holder-initiated exit operations open so users can retrieve their own funds, while capital-adding operations MUST revert. For an ERC-4626 vault, withdraw and redeem MAY remain callable after deactivation, whereas deposit and mint MUST revert. Observability : deactivated() MUST be a non-reverting view; indexers SHOULD treat Deactivated as a terminal lifecycle event for public holder operations. ERC-165: implementations MUST support ERC-165 and return true for IERC165 ( 0x01ffc9a7 ) and IERCDeactivation ( 0xe9cd80b0 ). Design choices & rationale Why so minimal? Two functions and one event are enough for broad interoperability. Every extra requirement is a reason not to implement the interface. Why separate deactivation from pause? A pause says “paused for now.” Deactivation says “done, terminally.” Conflating them means integrators can’t build reliable UX or accounting around end-of-life. Where a pause module already exists, deactivation composes with it as a permanent terminal pause. Why stay governance-neutral? The ERC mandates no specific access-control model, pause design, or legal workflow. It standardizes the signal , not the policy . Why is this deployment-model neutral? Both immutable contracts and upgradeable proxies are compatible. But the honest caveat is that a proxy upgrade can change any logic — so the standard is explicit that deactivated() is not, by itself, a cryptographic guarantee of irreversibility under an upgradeable proxy. For strict permanence, use an immutable deployment or irrevocably renounce upgrade authority. For proxies, integrators are recommended to adopt a conservative default: once deactivated, treat as permanently deactivated unless governance documentation says otherwise. What this ERC does NOT define Access-control model : multisig, timelock, role-based — left to the implementer. Pause design : the pause precondition is optional and unopinionated. Legal or migration workflow : off-chain corporate actions are out of scope. On-chain permanence enforcement for proxies : the interface signals intent; it cannot override upgrade authority. Open questions List of point that require more reflexion Pause precondition strength. Currently: implementations using a pause mechanism SHOULD require the contract to be paused before deactivateContract() succeeds, and if that precondition is used but not met, the call MUST revert. The precondition itself is optional (non-pausable contracts are allowed). Should this be a stronger requirement (MUST) rather than SHOULD, or would that over-constrain non-pausable contracts? Function naming. Currently: the operation is named deactivateContract() and its irreversibility is conveyed through the spec (one-way state, AlreadyDeactivated() on re-entry) rather than the name. Is deactivateContract() the right name, or would something like permanentlyDeactivate() better communicate irreversibility at the call site? Proxy permanence. Currently: the ERC is explicit that deactivated() is not, by itself, an on-chain guarantee of irreversible finality under an upgradeable proxy. It recommends integrators adopt a conservative default (treat as permanently deactivated unless governance documentation says otherwise) and suggests immutable deployments or renouncing upgrade authority where strict permanence is required — but it does not standardize any on-chain signal for this. Is the “conservative default” guidance sufficient, or should the ERC recommend an on-chain flag (e.g. exposing whether upgrade authority has been renounced)? Post-deactivation guarantees. Currently: after deactivated() == true , holder-initiated asset movements and all non-privileged/non-view/non-pure holder operations MUST revert; normal lifecycle mint / burn MUST revert; unpause (if present) MUST revert. Only explicitly named privileged emergency/regulatory operations (e.g. forcedTransfer ) MAY remain available, and any that do MUST be documented as post-deactivation-enabled; unnamed privileged operations MUST revert. Is this set of defaults right for both RWA and DeFi use cases? Interface ID and events. Currently: the interface exposes a single Deactivated(address indexed account) event, emitted once by deactivateContract() , and advertises interface ID 0xe9cd80b0 via ERC-165. There is no separate event for privileged operations executed after deactivation. Is 0xe9cd80b0 agreeable, or do we want any additional events (e.g. a distinct signal when a privileged post-deactivation operation executes)? Prior art & references ERC-165 — interface detection standard, required by this ERC. ERC-20 , ERC-721 , ERC-1155 — base token standards this interface composes with. Pausable token patterns (e.g. OpenZeppelin Pausable ) — deactivation acts as a permanent terminal pause on top of these. Let me know if you have any feedbacks on that PR: Add ERC: Contract Deactivation by rya-sge · Pull Request #1900 · ethereum/ERCs · GitHub 1 post - 1 participant Read full topic

Read full article on Ethereum_magicians →

DeFi Intel is an entity-graph aggregator: we curate, tag and link crypto news to a typed knowledge graph of protocols, tokens, people and incidents. We do not republish the full article body. Use the link above to read the original report at Ethereum_magicians.

Stay current on entity-tagged crypto news

Get the weekly DeFi Intel brief — entity-graph intelligence covering protocols, tokens and incidents, free to your inbox.