ECIP 1112: Sovereignty Vault
| Author | Cody Burns, Chris Mercer |
|---|---|
| Discussions-To | https://github.com/orgs/ethereumclassic/discussions/530 |
| Status | Draft |
| Type | Standards Track |
| Category | Core |
| Created | 2025-07-04 |
| Requires | 1111 |
Simple Summary
Establishes the Sovereignty Vault: the permanent address at which Ethereum Classic’s base-fee revenue accumulates.
The network makes one address permanent. It is written into every client’s chain configuration by the hard fork that activates ECIP-1111, and a further fork is what changes it. A stock OpenZeppelin transparent proxy is deployed at that address, so the logic behind it can be repaired while the address stands.
One address holds one balance. “Sovereignty Vault” names that address and the revenue ECIP-1111 credits to it. This ECIP states what must be true of the account there before the network commits to the address, and what must be published so anyone can confirm it from chain state; it specifies no governance machinery.
Abstract
This ECIP defines the Sovereignty Vault: the address to which ECIP-1111 credits the base fee charged to every transaction. That ECIP states the consensus rule and the chain-configuration parameter holding the address; this one states what must be true of the account at it.
Three requirements, and nothing above them: the account is deployed, locked, and inspectable on-chain before the fork commits to the address; every implementation ever deployed there derives spendable value from the account’s balance; and enough is published that a third party can confirm both from chain state. Governance of the account and allocation of the balance are specified elsewhere. This ECIP introduces no consensus behavior.
Motivation
The base fee ECIP-1111 credits is capital the network raises from its own usage, with no foundation, sponsor, or donor in the path. The destination holding it answers to two requirements whose lifetimes differ.
The address is permanent. Execution clients carry it in chain configuration, so redirecting the network’s revenue costs a coordinated client release, and no on-chain party can do it at all.
The logic behind the address is repairable. The contract at the network’s revenue destination must be able to take a security patch, a response to a disclosed vulnerability, and a major-version migration of its own dependencies. A design that needs a hard fork for each of those makes a chain split the routine response to a routine defect.
An upgradeable proxy holds both at once, and the remainder of this ECIP specifies the conditions that keep the separation sound.
Specification
The Address
ECIP-1111 §”The Destination Address” states the consensus parameter: SOVEREIGNTY_VAULT holds one address per network in the chain specification each participating client ships. ECIP-1111 delegates publication of the value to this ECIP, and §Implementation is the list of what is published.
What Is Deployed There
The account at the address MUST be an upgradeable proxy with the three properties below, each of them readable from chain state:
- The implementation is replaceable and the address is not. The implementation address is held in the ERC-1967 implementation slot, and replacing it leaves the account’s address and its balance untouched.
- Upgrade authority is fixed at construction and cannot be repointed. The account names the holder of upgrade authority when it is constructed and exposes no path to change it afterwards, so no party acting through the account can move the authority to replace the implementation.
- Upgrade authority reaches nothing else through the account. A call from the holder of upgrade authority either replaces the implementation or reverts, and is never forwarded to the implementation.
OpenZeppelin’s TransparentUpgradeableProxy has all three, and is what the deployment uses, unmodified. It holds the implementation address in the ERC-1967 implementation slot; it deploys its own ProxyAdmin and stores that address in an immutable field, ProxyAdmin being Ownable with upgradeAndCall restricted onlyOwner; and a call from that contract which is not upgradeToAndCall reverts with ProxyDeniedAdminAccess(). OpenZeppelin warns that adding an external function to the proxy can shadow upgradeToAndCall through a selector clash and leave the account permanently unupgradeable, which is why it is deployed stock. The reference below reads it at release v5.3.0.
Which contracts sit beneath the implementation, which release each is deployed from, and where upgrade authority rests, are specified with that deployment and published under §Implementation.
GHSA-9rcw-c2f9-2j55 (CVE-2025-54070) does not reach this contract at any release. It affects >= 5.2.0, < 5.4.0, and the vulnerable code is lastIndexOf in utils/Bytes.sol, which is absent from the proxy’s transitive import closure at every release in that range and at every release since, through v5.7.0. That file enters the library at v5.2.0, the advisory’s own floor, so there is no earlier release at which the question arises. The same walk finds that file inside Governor’s closure at v5.4.0, so it distinguishes rather than reporting absence everywhere. The closure of the contracts deployed beneath the proxy is not specified by this ECIP, and MUST be checked on its own terms before Mainnet deployment.
One requirement binds every implementation deployed there, now and after any later replacement of its logic: §”Balance Is the Source of Truth”.
Balance Is the Source of Truth
Every implementation deployed at the Vault address MUST determine spendable value from the account’s own balance, and every upgrade MUST preserve that property.
ECIP-1111’s credit is a direct state write performed by the client during the transaction’s state transition. It executes no EVM code: no receive() body runs, no fallback is entered, no event fires, and no counter is incremented. An implementation that released funds against a total it maintained itself would release nothing, and the consensus-credited balance would be permanently unspendable.
An implementation satisfying this maintains no balance ledger and spends the account’s real balance when it acts. An upgrade proposal MUST be rejected if the implementation it installs introduces a deposit counter, a running total of received value, or any other state variable mirroring the balance.
Two shipped contracts carry the pattern this excludes. OpenZeppelin’s Escrow credits _deposits[payee] inside deposit(address payee) public payable, and Liquity’s ActivePool credits uint256 internal ETH inside receive() external payable. Each counter rises only in a call, and a consensus-layer credit makes none.
Deployment and Publication
The activation fork is the last step. It commits to an address whose contents are already deployed and inspectable.
Two orderings are the requirement, and each is checkable from chain state:
- The account is complete before the address is published. The published address MUST resolve to deployed code already in its final configuration, holding only the roles its own specification requires — at the moment of publication and at the activation block alike.
- The address is published before the activation block is scheduled, so that the network commits to an address the public has already had the opportunity to inspect.
The steps that produce that account, the roles granted between its contracts, and the invariants a deployer verifies against them are properties of those contracts and are specified with them. What this ECIP requires is that all of it be complete, and independently checkable, before the network commits to the address.
Rationale
The commitment is an address because an address is what a client can hold. Execution clients carry a destination address in their chain configuration; they cannot carry the logic behind it. Permanence therefore attaches to the thing clients actually carry, and extending it to the logic would add a constraint the consensus layer never asked for, at the cost of the ability to repair.
A proxy is a safe consensus-credit target because the credit executes no EVM code. ECIP-1111 requires a direct balance addition, so the proxy’s payable fallback never runs, no delegation to the implementation occurs, no gas is consumed, and the credit cannot revert. The upgradeable surface and the consensus rule therefore do not touch: no upgrade can introduce a revert path into the state transition, because the state transition never calls the account. What an upgrade can reach is accounting, which is why §”Balance Is the Source of Truth” binds every implementation rather than only the first.
Ethereum Classic’s governance model is what puts the destination in chain configuration. On the production networks ECIP-1111 §Rationale tabulates, the destination is a configuration value some authority already controls — a chain owner, a multisig, a proxy administrator, an allow-list admin — so immutability there buys nothing, that authority being able to change the configuration regardless. Ethereum Classic has no such authority, which inverts the trade: a destination an on-chain party could repoint would create one, able to redirect the network’s entire revenue without the fork that installed the address.
Backwards Compatibility
This ECIP introduces no changes to transaction formats, opcodes, or EVM semantics; all consensus-layer behavior is ECIP-1111’s, and its §”Backwards Compatibility” governs those. Existing transactions and contracts are unaffected. Tooling that displays or attributes fee flows needs updating for one change this ECIP makes visible: the base fee accrues to an account, and that account’s balance is where it is observed.
Test Cases
What a conforming deployment looks like from chain state, read at the published address before the activation block and re-established after every upgrade:
| Read | Expected |
|---|---|
| The implementation’s storage layout | no deposit counter, running total, or other state mirroring the balance (§”Balance Is the Source of Truth”) |
| The role table of the account | the roles its own specification requires, and no role that existed only to construct the deployment |
What a conforming client does with it, run against the deployed proxy and a client implementing ECIP-1111:
| Case | Expected |
|---|---|
| Consensus credit, and the code that credit executes | as ECIP-1111 §”Test Cases” specifies — the per-transaction credit amount, and the requirement that the credit execute no EVM code, carried there at its Vault credit, per transaction and EVM code executed by the credit rows — with the deployed proxy as the account under test |
| The account under test | the deployed proxy. An externally-owned account cannot distinguish a conforming direct state write from an implementation that calls the destination, so it does not discharge the row above |
| Spending consensus-credited value | an operation executed through the account moves value that arrived only by consensus credit |
| Cross-client | identical balance and identical state root at every post-activation block, on ETC Mainnet (chainId 61) and Mordor Testnet (chainId 63) |
| Published address | resolves to the same deployed code under every client implementation |
Security Considerations
The one case that cannot be repaired at this layer is capture of the account’s upgrade authority, since every remedy at this layer is itself an execution through the captured path. The remedy is a hard fork repointing the consensus address at a newly deployed account, after which base fees arrive at the replacement from the new activation block onward.
That remedy bounds the worst case, and the bound is the design’s central security claim. The loss is the balance held at the moment of compromise plus the revenue credited between then and the new activation block. The repair is coordination rather than invention: the replacement is deployed and published on the same terms §”Deployment and Publication” already requires, and the instrument that installs the new address is the one that installed the original.
§”Balance Is the Source of Truth” is what keeps that bound true, and it is the highest-severity requirement in this ECIP. The loss it guards against is the one the fork remedy above does not reach: funds at an address whose code cannot release them survive any repointing, because repointing moves later revenue and not the balance already held. It MUST be verified against every proposed implementation.
Publication is a requirement because a misconfigured role fails invisibly. A deployment whose roles are wrong produces a working system: value arrives, balances rise, and ordinary operations execute, so the defect surfaces only when someone acts through it. Publishing the role table is what lets a party who did not run the deployment check it against the specification that defines it.
Audit. The deployed code is OpenZeppelin at a published release, so the audit obligation is one of configuration rather than of novel code. Third-party review MUST confirm, prior to Mainnet deployment, that the published address is the proxy rather than the implementation behind it, and that every published item reproduces from chain state. Testnet deployment MUST confirm accumulation, spendability of consensus-credited value, and cross-client consistency.
Implementation
This ECIP requires no client behavior of its own. ECIP-1111 states the consensus rule and the chain-configuration parameter holding the address, and a client implementing that ECIP implements everything this one needs.
Prior to Mainnet activation the following MUST be published, so that §”Deployment and Publication” is checkable by a party who did not run the deployment:
- the address together with the network it is on — Mainnet’s and Mordor’s are independent values, so an address published without its chainId is ambiguous;
- the verified source and release tag of every contract at and beneath it;
- the implementation the address delegates to, read from the ERC-1967 implementation slot
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc, and where upgrade authority rests, read from the ERC-1967 admin slot0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103and then that contract’sowner()— both from chain state rather than from a deployment record, since that is what can change the logic behind a permanent address; - the full role table of the account, so that anyone can confirm which accounts may act through it and that no role which existed only to construct the deployment survives.
Each item MUST be reproducible from chain state.
Related ECIPs
| ECIP | Relationship to this ECIP |
|---|---|
| 1111 | The consensus rule that credits this address, the chain-configuration parameter holding it, and the source of the requirement that the credit execute no EVM code |
The requires: field expresses spec layering. The specification of how the account at this address is governed depends on this one, so that edge runs in the other direction and is recorded there.
References
Where a third-party repository is cited, the ref is a commit rather than a branch or tag: a commit cannot move, while a branch or tag resolves to different code over time and is therefore not a citation.
-
OpenZeppelin Contracts,
TransparentUpgradeableProxyandProxyAdmin, https://github.com/OpenZeppelin/openzeppelin-contracts @e4f70216d759d8e6a64144a9e1f7bbeed78e7079— release v5.3.0, the account §”What Is Deployed There” specifies.contracts/proxy/transparent/TransparentUpgradeableProxy.solline 67,address private immutable _admin; line 72,error ProxyDeniedAdminAccess(); line 80,_admin = address(new ProxyAdmin(initialOwner)), the constructor being the only place that address is set; and the WARNING preceding the contract, against adding an external function that could shadowupgradeToAndCallby selector clash.contracts/proxy/transparent/ProxyAdmin.solline 13,contract ProxyAdmin is Ownable, and line 42,upgradeAndCallrestrictedonlyOwner.contracts/proxy/ERC1967/ERC1967Utils.sollines 21 and 83, the two slot constants §Implementation names -
ERC-1967, “Proxy Storage Slots” (Final), https://eips.ethereum.org/EIPS/eip-1967 — the implementation and admin slots, each the keccak-256 hash of its label less one
-
GHSA-9rcw-c2f9-2j55 (CVE-2025-54070), https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories/GHSA-9rcw-c2f9-2j55 — affects
>= 5.2.0, < 5.4.0, first patched at 5.4.0. The vulnerable code islastIndexOfinutils/Bytes.sol, absent from the proxy’s transitive import closure at every release across that range and through v5.7.0; the same walk finds it insideGovernor’s closure at v5.4.0 -
OpenZeppelin Contracts,
Escrow, https://github.com/OpenZeppelin/openzeppelin-contracts @dc44c9f1a4c3b10af99492eed84f83ed244203f6—contracts/utils/escrow/Escrow.sol, wheredeposit(address payee) public payablecredits_deposits[payee]: the pattern §”Balance Is the Source of Truth” excludes. That commit is release v4.9.6, the last to carry the escrow family: every v5 release from932fddf69a699a9a80fd2396fd1a2ab91cdda123(v5.0.0) through v5.7.0 carries no escrow contract at all -
Liquity, https://github.com/liquity/dev @
3e64ee1b52c50d51587c64c1cf75e0ba82934979—packages/contracts/contracts/ActivePool.sol, wherereceive() external payablecreditsuint256 internal ETH: the same pattern, in thereceive()body that a consensus-layer credit never enters -
ECIP-1111 (2025), “Base Fee Market and Redirection” — the consensus rule, §”The Destination Address” for the chain-configuration parameter, and §”Test Cases” for the credit vectors this ECIP runs against the deployed proxy
Copyright
Copyright and related rights waived via CC0.