[RFC] Reclaim Stranded Funds Across Legacy & Incidental Contracts into the DAO Treasury

1. Summary:

Following the V1→V2 governance migration, ETH and tokens have been left behind in deprecated and incidental protocol contracts. A confirmed example is ~0.9537 ETH sitting idle in the Governor V1 on Base. This RFC proposes a crowdsourced audit and recovery of stranded balances across legacy governance/staking contracts and incidental dust, sweeping them into the V2 DAO treasury (the Timelock) executed as a series of minimal, individually reviewed SIPs.


2. Context & Motivation:

The migration from Governance V1 to V2 left several contracts deprecated but still holding value. Migrations of this kind routinely strand assets: ETH sent to governor contracts, residual balances in superseded staking/reward modules, early-unstake penalty tokens that accrue to the DAO, and unclaimed/expired rewards.

A concrete balance is already identified:
Governor V1 (0xBE5A4DD68c3526F32B454fE28C9909cA0601e9Fa) holds ~0.9537 ETH. OpenZeppelin Governors expose relay(address,uint256,bytes) precisely so governance can recover assets sent to them as long as V1 still holds its role on the shared Timelock.


3. Proposal:

Goal: Identify and recover stranded balances across the contracts below, sending recovered assets to the V2 DAO treasury (Timelock).

Step 1: Onchain audit (first deliverable). Lets crowdsource and have a look at relevant contracts, in search for any stranded assets.

Step 2: Recovery mechanism by type:

  • Governor contracts: relay(target, value, data). For V2 this is a simple self-call submitted on the live governor. For V1 it must be a V1-native proposal (propose → queue → execute on V1), because relay is onlyGovernance and the authorizing _governanceCall queue is filled only inside the governor’s own execute().
  • Staking / rewards contracts: depends on whether they expose a governance-callable sweep, withdraw, or claim-to-DAO. Requires ABI review per contract.
  • Satellite chains: routed from Base via LayerZero, consistent with the protocol’s hub-and-satellite governance model.

Step 3: Execute as individual SIPs.** Each recovery should be promoted to its own minimal, single-purpose SIP (one action, fully decoded calldata published), not bundled.

This is deliberate: April’s SIP5.31 attack hid a malicious role grant inside a multi-call “V1 cleanup” package, so any V1-touching proposal must be trivially auditable and pre-reviewed by Guardians.


4. Open Questions:

  • Materiality threshold: What minimum balance justifies a recovery, given coordination + gas (e.g. skip sub-threshold dust.)
  • Satellite dust: Is cross-chain recovery worth the complexity, or should small satellite balances be accepted as stranded?

5. Next Steps:

  • Gather feedback and interest in contributions (@Recognized_Delegates).
  • Confirm V1’s Timelock role and quorum feasibility (determines whether the V1 ETH recovery is still possible).
  • Promote each viable recovery to a minimal child SIP.
  • Iterate and, where material, request Guardian pre-review for each V1-touching SIP.

6. Informal Support Indicator:

  • Support a coordinated stranded-funds recovery
  • Support, but only for the confirmed V1 ETH (skip the broader sweep)
  • Do not pursue
0 voters

Confirmed reference addresses (Base):

  • Governor V1 → 0xBE5A4DD68c3526F32B454fE28C9909cA0601e9Fa
  • Governor V2 → 0x4cEeE1b6289624d381383C1Bb42B118d5f2c3274
  • Timelock/treasury → 0x447BF9d1485ABDc4C1778025DfdfbE8b894C3796
  • SUMR → 0x194f360D130F2393a5E9F3117A6a1B78aBEa1624
  • stSUMR → 0x7cC488F2681cFC2A5E8A00184bfA94ea6d520D1c
  • & any other timelock controlled contracts.
1 Like

Anything worth $100+ makes sense to me, at a minimum, it will cover gas costs.

I think we can decide on cross-chain recovery once we know the actual balances after the onchain audit.

1 Like

Update: the V1 ETH recovery path looks closed PROPOSER_ROLE is already revoked

Following up on Next Step #2 (confirm V1’s Timelock role and quorum feasibility). I ran the check, and it rules out the V1 ETH recovery as originally scoped.

Finding. On the shared Timelock (0x447BF9d1485ABDc4C1778025DfdfbE8b894C3796), hasRole(PROPOSER_ROLE, GovernorV1) returns false. Anyone can reproduce it from the Timelock’s Read ContracthasRole, or via eth_call:

  • role = 0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1 (keccak256("PROPOSER_ROLE"))
  • account = 0xBE5A4DD68c3526F32B454fE28C9909cA0601e9Fa (Governor V1)

So, it seems like V1 has already been disconnected from the Timelock as part of the migration cleanup. (Worth a second pair of @Recognized_Delegates eyes to independently confirm.)

Potential option:

  1. Re-grant, recover, revoke. A V2 proposal grants V1 PROPOSER_ROLE (+EXECUTOR_ROLE), we run the V1 recovery, then a follow-up V2 proposal revokes it. Mechanically valid, but it temporarily reopens the exact surface behind the April SIP5.31 attempt (a live plain-SUMR governor at a 10k threshold), and it still needs V1 to reach 15% quorum.

  2. Accept it as stranded. “Leave it” is a potential legitimate outcome given that (1) might be the only alternative, and therefore it could introduce further attack vector.

Thanks for putting this RFC together, @Jensei! We support proceeding with the onchain audit and @Sixty’s proposed ($100) threshold, but we strongly agree that the ~0.95 V1 ETH should be accepted as stranded to avoid the security risk of reopening a known vulnerability.

1 Like