# Coding logic of the contract upgrading renders upgrading contracts impractical

ProtocolDAO.upgradeExistingContract registers new contract before unregistering old, so same-name upgrades zero out the registry entry, breaking cross-referenced contracts.

- Payout: Contest reward
- Severity: medium
- Program: GoGoPool
- Credited: gz627
- Disclosed: 2023-03-21
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-gogopool-findings/issues/742
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-gogopool%3AM-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:medium tech:solidity technique:regression technique:source-review vuln:accounting-error vuln:misconfiguration

**Target:** ProtocolDAO contract registry (Solidity)
**Root cause:** upgradeExistingContract calls registerContract(newAddr,newName) then unregisterContract(existingAddr); if newName equals the existing name, unregister overwrites the shared Storage key with address(0).
**Steps:**
1. Register existing contract: `dao.registerContract(existingAddr, "existingName")`
2. Call `dao.upgradeExistingContract(addr, "existingName", existingAddr)` as guardian
3. Observe `store.getAddress(keccak256("contract.address","existingName"))` returns address(0)
4. Alternatively rename to ClaimNodeOpV2: `staking.increaseGGPRewards` reverts with InvalidOrOutdatedContract because modifier hardcodes "ClaimNodeOp"
**How found:** Code reading of upgradeExistingContract ordering plus tracing how Storage keys are derived from contract name; confirmed via Foundry tests.
**Escalation:** Renaming forces cascading upgrades of all cross-referenced contracts since names are hardcoded in modifiers, making upgrades impractical.
**Insight:** When a registry keys state by name, check register/unregister ordering for same-key collisions; also check whether hardcoded name references in modifiers break rename-based upgrades.
