Governance Freeze PostMortem
Glow Team / July 4, 2025

Governance Freeze PostMortem
An incorrect constructor argument in the Veto Council deployment during the initial Glow V1 guarded-launch caused Governance to reference the wrong contract. When the first proposal to modify council membership executed, the call reverted, blocking and freezing the entire Governance pipeline.
This means that for the rest of Glow V1 there can no longer be on chain GCA Elections, Veto Council Elections, or Grants. Grants will proceed off-chain with support from the ICRG Foundation until the Glow V2 relaunch unfreezes execution and no funds in the protocol are affected. The bug does not affect solar farms, rewards, USDG Redemptions, or any other critical on-chain process.
Code Dive
In Glow V1, the happy path for governance follows a five step process, outlined below:
1. Proposal Creation
• Users call one of the create*Proposal
entry points (createGrantsProposal
, createGCACouncilElectionOrSlashProposal
, etc.).
• Each function:
- Calculates the nomination cost (
costForNewProposalAndUpdateLastExpiredProposalId
). - Burns the caller's nominations via
_spendNominations
. - Stores a
Proposal
struct in_proposals
and, if its vote count tops the leaderboard, records it inmostPopularProposalOfWeek
.
2. Collecting Votes
• Additional nominations can later be attached with useNominationsOnProposal
.
• Once the popularity week ends, long-staked GLW holders record ratify/reject votes through ratifyOrReject
.
• Votes accumulate in _proposalLongStakerVotes
.
3. Eligibility Window
A proposal becomes executable when:
• Its popularity week has finished and
• The four-week ratify/reject & veto window (_NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL
) has elapsed.
4. Execution Engine (syncProposals
)
Anyone can invoke syncProposals()
to process the backlog sequentially—oldest first.
function syncProposals() public {
...
for (_nextWeekToExecute; _nextWeekToExecute < currentWeek; ++_nextWeekToExecute) {
uint256 proposalId = mostPopularProposalOfWeek[_nextWeekToExecute];
...
handleProposalExecution(_nextWeekToExecute, proposalId, proposalType, proposal.data);
}
}
If any execution reverts, the loop aborts and lastExecutedWeek
remains unchanged, blocking every subsequent proposal.
5. Type-specific Dispatch (handleProposalExecution
)
handleProposalExecution
decodes the payload and forwards the action to the correct subsystem:
if (proposalType == IGovernance.ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH) {
(address oldMember, address newMember, bool slashOldMember) = abi.decode(data,(address,address,bool));
success = IVetoCouncil(VETO_COUNCIL).addAndRemoveCouncilMember(oldMember, newMember, slashOldMember);
}
Other branches cover Grants payouts, GCA requirement changes, RFC logging, etc.
Success or failure is stamped via _setProposalStatus
, and an event is emitted.
Where It Broke
During week 76, the queued proposal was a VETO_COUNCIL_ELECTION_OR_SLASH
.
When syncProposals()
hit the dispatch above, the call to VetoCouncil.addAndRemoveCouncilMember()
reverted with CallerNotGovernance
because the Veto Council contract's immutable governance
field had been mis-wired to the GLW token address during deployment:
// DeployGuardedLaunch.s.sol
vetoCouncilContract = new VetoCouncil(address(glow), address(glow), startingVetoCouncilAgents);
// ^^^^^^^^^^^^^^^^^^^^^ (should be Governance)
The revert bubbled up, terminated the for
loop, and left lastExecutedWeek
stuck.
Because syncProposals()
insists on synchronous, chronological execution (week == lastExecutedWeek + 1
), the entire Governance pipeline froze—no subsequent proposals (including grant payouts) can progress until a redeploy wires the Veto Council to the correct Governance address.
Impact
- Governance execution frozen. No on-chain grants, parameter changes, or council elections can complete.
- Grants moved off-chain. The Foundation will aid in an off-chain grant process manually until V2 is operational.
- No funds at risk. Contract balances and state remain intact; the issue is a logic lock, not a security breach.
Preventing These Issues
Ultimately, the value of any post-mortem lies in the concrete safeguards it inspires. The four mitigations below - type-safe constructors, AI-assisted static analysis, end-to-end deploy-script tests, and dual-review canary deployments - turn the lessons of this incident into hard guardrails baked into our tooling and release flow. Together they make a repeat of the mis-wiring error mechanically unlikely and surface any similar faults long before they can reach mainnet.
- Strongly-typed constructors in new code. All new contracts receive explicit interface parameters; misuse fails at compile time.
- Deployment scripts pass interface-typed objects instead of plain addresses, eliminating class-mismatch errors.
- AI-assisted static analysis. New codebases run an LLM ruleset that flags duplicated or suspicious constructor arguments before merge.
- Comprehensive deploy-script tests. Each script forks mainnet, executes the deployment end-to-end, and asserts post-deploy invariants, blocking any transaction that does not wire contracts correctly.
- Mandatory multi-party review and canary execution. Every mainnet deploy requires dual-signature review of calldata and a post-deploy smoke test on a fork, preventing mis-configured contracts from reaching production.
Related articles

David Vorick / July 4, 2024
5 min readWhat is Glow?
An overview of the Glow protocol and its mission to revolutionize the solar energy landscape.

Simon Boccara / April 10, 2024
5 min readExploring the GCA Protocol Binary Bug
We go through the GCA Binary bug that caused weeks [0-8] to be aggregated into a single week. We explore how this affected the rewards for farms and the carbon credits submitted on-chain.

David Vorick / March 29, 2024
7 min readThe First Major Refactor of the Glow Audit Standard
Discloses the first cheating incident on the Glow protocol, and explains how the audit standard was refactored to be more effective.

David Vorick / January 31, 2024
10 min readThe Glow Impact Platform
Rebuilding climate strategy from first principles.

David Vorick / January 9, 2024
3 min readGuarded Launch: Protecting Glow Users Against Hacks
Code audits are both expensive and insufficient; using a guarded launch can improve safety while reducing costs and time-to-market.

David Vorick / December 19, 2023
5 min readWhy Glow Excites Me
How I found my way to Glow, and why Glow is the path to effective climate action.

Simon Boccara / September 10, 2024
5 min readWeek 40 Bucket Submission Post-Mortem
An analysis of the incident during week 40's bucket submission, its impact, and the steps taken to resolve and prevent future occurrences.

Simon Boccara / June 25, 2025
5 min readAdding USDG Redemptions to the Glow V1 Guard
Glow's core contracts went live on Ethereum mainnet on December 18, 2023 under an intentionally conservative guarded launch framework. This post explains how Glow added USDG redemptions to the Glow V1 guard.