Freeze-and-Burn Finality
ClaimRush v1.0.0 reaches permanent runtime finality through one timelocked ceremony. The launch window is governed and patchable. The end state is public, delayed, and irreversible.
Finality is a two-part ceremony for the proxy-backed runtime quartet:
freezeConfig()locks the documented core wiring setters on the five freeze-gated contracts (ClaimToken freezes at wire time; the remaining four freeze in the ceremony)- burning the four runtime
ProxyAdminowners removes quartet upgrade authority forever
The quartet is:
MineCoreFurnaceMarketRouterShareholderRoyalties
The direct permanent roots remain:
ClaimTokenVeClaimNFT
What the ceremony does
ClaimToken freezes at wire time: ClaimToken.freezeConfig() and ClaimToken.renounceOwnership() execute at the end of Wire.s.sol, immediately after wiring. ClaimToken has no post-freeze owner knobs (no pause, no metadata, no guardian), so ownership is dead weight after freeze. By the time the ceremony runs, it is already frozen and ownerless.
The canonical finality batch is therefore 8 operations:
MineCore.freezeConfig()Furnace.freezeConfig()VeClaimNFT.freezeConfig()ShareholderRoyalties.freezeConfig()MineCore ProxyAdmin.renounceOwnership()Furnace ProxyAdmin.renounceOwnership()MarketRouter ProxyAdmin.renounceOwnership()ShareholderRoyalties ProxyAdmin.renounceOwnership()
This ordering is mandatory.
- Every freeze call runs before any proxy-admin burn
- If any freeze precondition fails, the whole batch reverts
- No runtime proxy admin is ever burned unless all four ceremony freezes succeed first
- The script asserts that ClaimToken is already frozen before scheduling
What finality means
After the batch executes successfully:
- All five freeze-gated contracts (
ClaimToken,MineCore,Furnace,VeClaimNFT,ShareholderRoyalties) reportconfigFrozen() == true(ClaimToken was already frozen at wire time) - the runtime quartet can no longer be upgraded
- the quartet proxy addresses remain the canonical live addresses
ClaimTokenandVeClaimNFTremain direct permanent roots
Finality means both layers are locked:
- wiring is locked by the five
freezeConfig()calls (ClaimToken freezes at wire time; the remaining four freeze in the ceremony) - runtime logic is locked by burning the four runtime
ProxyAdmins - the public governance window is over for the runtime itself
What stays mutable afterward
Finality is not full protocol owner renounce.
The timelock still owns the protocol owner() paths after the burn, so documented post-freeze operational knobs remain available, including:
MineCore.guardian(rotatable;MineCore.setGuardianhas no freeze gate)MineCore.entryTokenRegistry(MineCore.setEntryTokenRegistryhas no freeze gate)Furnace.entryTokenRegistry(Furnace.setEntryTokenRegistryhas no freeze gate)Furnace.delegationHub(Furnace.setDelegationHubhas no freeze gate, but is reciprocal-binding-gated againstMineCore.delegationHub). Note the freeze asymmetry:MineCore.setDelegationHubISwhenNotFrozen, so the MineCore-side hub is permanently locked at the ceremony. A real post-freeze hub rotation therefore requires the new hub to be live inMineCore.delegationHubbefore the canonical freeze; afterwards,Furnacecan only adopt that already-pinned address.Furnace.guardianis pinned toMineCore(atomically set insideFurnace.setMineCore, andFurnace.setGuardianonly allows re-asserting the currentmineCore).Furnace.setMineCoreISwhenNotFrozen, so post-freezeFurnace.guardianis fixed to the MineCore proxy address — the operational guardian is rotated viaMineCore.setGuardian, not on Furnace directly.- Furnace delayed emergency LP-vault recovery (
requestEmergencyVaultRewire/cancelEmergencyVaultRewire/executeEmergencyVaultRewireare owner-only with no freeze gate) MarketRouterpolicy knobs such as settlement keepers and bonus-target escrow paramsVeClaimNFTmetadata URIs (setBaseURI,setContractURI) — these are gated bywhenMetadataNotFrozen, notwhenNotFrozen, so the canonicalfreezeConfig()ceremony does not lock them. They can be permanently locked at any time via the separate one-wayfreezeMetadata()call (src/VeClaimNFT.sol).ShareholderRoyaltiescompounding keepers/floors
Those actions no longer happen instantly. They remain timelocked governance actions.
Contracts whose setter is whenNotFrozen (ClaimAllHelper, FurnaceQuoter, LpStakingVault7D) are permanently locked after the ceremony. Contracts whose setter has no freeze gate (entry-token registries, DelegationHub, DexAdapter) remain reconfigurable through the timelock — the Security page shows these as “Configurable” after finality. See the full before/after table at the end of this document.
Governance path
The production chain of authority is:
Safe -> TimelockController -> ProxyAdmin -> runtime proxySafe -> TimelockController -> protocol owner()
Defaults:
PROPOSER_ROLE = SafeCANCELLER_ROLE = SafeEXECUTOR_ROLE = Safe
The guardian remains separate and immediate for pause/unpause response.
Why the delay matters
The freeze-and-burn batch is intentionally timelocked before execution.
That delay is not just an operational buffer:
- it creates a public onchain countdown to finality
- the exact batch calldata is visible before execution
- the Safe can cancel if anything looks wrong
- users and integrators can see that permanent runtime immutability is approaching
- operators get one final review window before the protocol crosses into permanent runtime finality
On mainnet, that countdown is part of the protocol’s credibility story.
Operational sequence
- Finish deployment, wiring, and genesis
- Transfer ownership to the timelock
- Bootstrap the timelock roles and renounce deployer admin
- Complete verification while quartet upgrades are still available
- When ready for permanent finality, schedule the freeze-and-burn batch
- Wait the timelock delay
- Execute the batch
- Verify frozen state and burned proxy admins onchain
Required scripts
FinalizeOwnership.s.solFinalizeTimelockBootstrap.s.solTimelockAcceptOwnership.s.solTimelockRuntimeUpgrade.s.solFreezeAndBurn.s.sol
Emergency model before finality
Before the burn, critical runtime bugs are handled in the standard order:
- guardian pauses the affected surface immediately
- governance schedules the runtime upgrade through the timelock
- wait the delay
- execute and verify
- unpause only after the corrective change is confirmed live
Post-finality model
After the burn:
- runtime upgrades are impossible
- surviving owner knobs still require the timelock delay
- “post-freeze operational change” means
schedule -> wait -> execute, not “call the setter directly” - the timelock remains load-bearing governance, not a ceremonial leftover
Verification checklist
After execution, confirm:
- all five
configFrozen()values aretrue - each runtime
ProxyAdmin.owner()isaddress(0) python3 scripts/verify_deployment.py --network <network> --rpc-url "$RPC_URL" --require-frozenpasses- the deployment manifest still shows the same quartet proxy addresses
- the manifest
proxyAdminOwnervalues are updated to0x0000000000000000000000000000000000000000
Contract upgradeability before and after finality
The Security page reads configFrozen() and proxy-admin ownership (EIP-1967 admin slot) to detect each contract’s upgradeability status live. The table below is the definitive reference for all deployed contracts.
Proxy-backed runtime quartet (Yes → No):
| Contract | Before ceremony | After ceremony | Mechanism |
|---|---|---|---|
| MineCore | Yes | No | ProxyAdmin ownership renounced |
| Furnace | Yes | No | ProxyAdmin ownership renounced |
| MarketRouter | Yes | No | ProxyAdmin ownership renounced |
| ShareholderRoyalties | Yes | No | ProxyAdmin ownership renounced |
Direct permanent roots and non-proxy contracts (always No):
| Contract | Before ceremony | After ceremony | Mechanism |
|---|---|---|---|
| ClaimToken | No | No | Direct root, frozen at wire time |
| VeClaimNFT | No | No | Direct root, no proxy |
| TimelockController | No | No | Plain contract, no proxy |
| GenesisLPVault24M | No | No | Not redeployable |
Configurable peripherals (Redeploy → Configurable):
| Contract | Before ceremony | After ceremony | Mechanism |
|---|---|---|---|
| FurnaceEntryTokenRegistry | Redeploy | Configurable | setEntryTokenRegistry has no freeze gate |
| MineCoreEntryTokenRegistry | Redeploy | Configurable | setEntryTokenRegistry has no freeze gate |
| DelegationHub | Redeploy | Configurable | Furnace.setDelegationHub has no freeze gate (gated by requireCanonicalDelegationHub reciprocal-binding check); MineCore.setDelegationHub is whenNotFrozen, so a post-freeze replacement requires the new hub to be live in MineCore before the canonical freeze. |
| DexAdapter | Redeploy | Configurable | Swapped via registry, no freeze gate |
Before the ceremony, governance can replace these by deploying a new instance and re-pointing the protocol. After the ceremony, the pointer remains writeable (timelocked), so in-place configuration changes are still possible — the status changes to “Configurable” to reflect that the contract is modified in place rather than replaced wholesale.
Frozen redeploy contracts (Redeploy → No):
| Contract | Before ceremony | After ceremony | Mechanism |
|---|---|---|---|
| ClaimAllHelper | Redeploy | No | setClaimAllHelper is whenNotFrozen on both MineCore and ShareholderRoyalties |
| FurnaceQuoter | Redeploy | No | setFurnaceQuoter is whenNotFrozen on Furnace |
| LpStakingVault7D | Redeploy | No | setLpRewardsVault is whenNotFrozen on Furnace |
Standalone peripherals (Redeploy → Redeploy):
| Contract | Before ceremony | After ceremony | Mechanism |
|---|---|---|---|
| MaintenanceHub | Redeploy | Redeploy | Standalone, no onchain pointer from a frozen contract |
| MineCoreQuoter | Redeploy | Redeploy | Standalone, no onchain pointer |
| AgentLens | Redeploy | Redeploy | Standalone read-only lens |
Retired:
| Contract | Before ceremony | After ceremony | Mechanism |
|---|---|---|---|
| LaunchController | Retired | Retired | Genesis-only, no longer active post-launch |