Governance and Proposal Process
Overview
This guide shows you how to participate in protocol governance as a sequencer. You'll learn how to signal support for protocol upgrades, create proposals, and vote on governance decisions that shape the Aztec network.
Prerequisites
Before proceeding, you should:
- Have a running sequencer node (see Sequencer Setup Guide)
- Have a basic understanding of Aztec's governance model and voting mechanisms
Understanding Governance Components
Payloads
Protocol upgrades consist of a series of commands that execute on protocol contracts or replace contract references. You define these steps in a contract called a payload that you deploy on Ethereum.
This guide assumes the payload already exists at a known address. You'll participate in the payload's journey through signaling, proposal creation, voting, and execution.
Before signaling support or voting, always:
- Verify the payload address on Etherscan or your preferred block explorer
- Review the
getActions()
function to understand what changes the payload will make - Check if the payload has been audited (if applicable)
- Discuss the proposal with the community on Aztec Discord
Never signal or vote for a payload you haven't personally verified.
Here's an example payload structure:
contract UpgradePayload is IPayload {
IRegistry public immutable REGISTRY;
address public NEW_ROLLUP = address(new FakeRollup());
constructor(IRegistry _registry) {
REGISTRY = _registry;
}
function getActions() external view override(IPayload) returns (IPayload.Action[] memory) {
IPayload.Action[] memory res = new IPayload.Action[](1);
res[0] = Action({
target: address(REGISTRY),
data: abi.encodeWithSelector(REGISTRY.addRollup.selector, NEW_ROLLUP)
});
return res;
}
function getURI() external pure override(IPayload) returns (string memory) {
return "UpgradePayload";
}
}
If this payload's proposal passes governance voting, the governance contract executes addRollup
on the Registry
contract.
Contract Addresses
Key contracts you'll use:
- Governance Proposer: Handles payload signaling and proposal creation
- Governance Staking Escrow (GSE): Manages stake delegation and voting
- Governance: Executes approved proposals
- Rollup: Your sequencer stakes here and defaults to delegating voting power here
Governance Lifecycle Overview
The governance process follows these stages:
- Signaling: Sequencers signal support for a payload when proposing blocks. A payload needs a quorum of support to be promoted to a proposal
- Proposal Creation: After reaching quorum, anyone can submit the payload as an official proposal.
- Voting Delay: A mandatory waiting period before voting opens (allows time for community review).
- Voting Period: Users who hold stake in the network vote on the proposal using their staked tokens.
- Execution Delay: After passing the vote, another mandatory delay before execution (allows time for node upgrades).
- Execution: Anyone can execute the proposal, which applies the changes.
Signaling Support for a Payload
As a sequencer, you initiate proposals through signaling. When you propose a block, you can automatically signal support for a specific payload. Once enough sequencers signal support within a round, the payload qualifies to become an official proposal.
How Signaling Works
- Only you can signal during slots when you're the block proposer
- Your sequencer node automatically calls
signal
on theGovernanceProposer
contract when proposing a block (if you've configured a payload address) - Rounds consist of 1000 slots each. At every 1000-block boundary, the system checks if any payload has received 750 or more signals (the quorum threshold, which is 75% of the round size)
- Payloads that reach quorum can be submitted as official proposals by anyone
Round size and quorum threshold will change between testnet and ignition. These values and any further references to these values are relevant for testnet only.
Configure Your Signaling Preference
Use the setConfig
method on your node's admin interface to specify which payload address you want to signal support for.
Call the JSON-RPC interface:
curl -X POST http://localhost:8880 \
-H 'Content-Type: application/json' \
-d '{
"jsonrpc":"2.0",
"method":"nodeAdmin_setConfig",
"params":[{"governanceProposerPayload":"0x1234567890abcdef1234567890abcdef12345678"}],
"id":1
}'
Replace 0x1234567890abcdef1234567890abcdef12345678
with your actual payload contract address.
Expected response:
{"jsonrpc":"2.0","result":true,"id":1}
Once configured, your sequencer automatically signals support for this payload each time you propose a block. Each signal counts toward the quorum requirement.
Creating a Proposal
Once a payload receives the required quorum (750 signals in a 1000-slot round), you or any user can call submitRoundWinner
on the GovernanceProposer
contract to officially create the proposal.
Submit the Payload
cast send [GOVERNANCE_PROPOSER_ADDRESS] \
"submitRoundWinner(uint256)" [ROUND_NUMBER] \
--rpc-url [YOUR_RPC_URL] \
--private-key [YOUR_PRIVATE_KEY]
To find the current round number:
# Get the current round from the GovernanceProposer contract
cast call [GOVERNANCE_PROPOSER_ADDRESS] \
"getCurrentRound()" \
--rpc-url [YOUR_RPC_URL]
Verify the Created Proposal
After creation, you can query the proposal in the governance contract:
# Get the total proposal count
cast call [GOVERNANCE_CONTRACT_ADDRESS] \
"proposalCount()" \
--rpc-url [YOUR_RPC_URL]
# Query the latest proposal (count - 1, since proposals are zero-indexed)
cast call [GOVERNANCE_CONTRACT_ADDRESS] \
"proposals(uint256)" $((PROPOSAL_COUNT - 1)) \
--rpc-url [YOUR_RPC_URL]
This returns the CompressedProposal
struct data, which includes:
- The payload address
- Creation timestamp
- Voting start and end times
- Current vote tallies
Voting on Proposals
Once a payload becomes a proposal, there's a mandatory waiting period before voting opens. You can vote in two ways: through default delegation to the rollup contract, or by delegating to an address you control for custom voting.
Default Voting Through the Rollup
By default, when you stake as a sequencer, you delegate your voting power to the rollup contract through the GSE (Governance Staking Escrow). The rollup automatically votes "yea" on proposals created through the GovernanceProposer
using all delegated stake from all sequencers in that rollup.
Key points:
- If you signaled for a payload, your stake votes "yea" automatically—no additional action needed
- If you didn't signal but other sequencers did, your stake still votes "yea" when the rollup votes
- To vote differently, you must change your delegation before voting opens (see Custom Voting below)
Anyone can trigger the rollup vote:
cast send [ROLLUP_ADDRESS] \
"vote(uint256)" [PROPOSAL_ID] \
--rpc-url [YOUR_RPC_URL] \
--private-key [YOUR_PRIVATE_KEY]
Custom Voting: Delegating to Your Own Address
If you want to vote differently on a proposal (for example, to vote "nay" or to split your voting power), you can delegate your stake to an address you control. This removes your stake's voting power from the rollup's control and gives it to your chosen address.
Voting power is timestamped at the moment a proposal becomes "active" (when the voting period opens). You must complete delegation before the voting period begins to use your voting power for that proposal.
Check the proposal's voting start time and delegate well in advance.
Step 1: Delegate Your Stake
Use the GSE contract to delegate to an address you control:
cast send [GSE_ADDRESS] \
"delegate(address,address,address)" \
[ROLLUP_ADDRESS] \
[YOUR_ATTESTER_ADDRESS] \
[YOUR_DELEGATEE_ADDRESS] \
--rpc-url [YOUR_RPC_URL] \
--private-key [YOUR_WITHDRAWER_PRIVATE_KEY]
[ROLLUP_ADDRESS]
: The rollup contract where you staked[YOUR_ATTESTER_ADDRESS]
: Your sequencer's attester address[YOUR_DELEGATEE_ADDRESS]
: The address that will vote (often the same as your attester address, or another address you control)- You must sign this transaction with your withdrawer private key (the withdrawer that you specified when you initially deposited to the rollup)
Step 2: Vote Through GSE
Once you've delegated to an address you control, that address can vote directly on proposals:
# Vote "yea" with your voting power
cast send [GSE_ADDRESS] \
"vote(uint256,uint256,bool)" \
[PROPOSAL_ID] \
[AMOUNT] \
true \
--rpc-url [YOUR_RPC_URL] \
--private-key [YOUR_DELEGATEE_PRIVATE_KEY]
[AMOUNT]
: The amount of voting power to use (can be your full stake or a partial amount)- You can vote multiple times with different amounts to split your voting power between "yea" and "nay" if desired
- To vote "nay" with your voting power, set the boolean in the code above to false
Step 3: Verify Your Vote
Check that your vote was recorded:
# Check vote counts for a proposal
cast call [GSE_ADDRESS] \
"getVotes(uint256)" [PROPOSAL_ID] \
--rpc-url [YOUR_RPC_URL]
This returns the current "yea" and "nay" vote tallies.
Executing Proposals
When a proposal receives sufficient support, it passes. After passing, there's another mandatory delay before the proposal becomes executable. Once executable, anyone can trigger execution.
Execute the Proposal
Once the proposal state is Executable, anyone can execute it:
cast send [GOVERNANCE_CONTRACT_ADDRESS] \
"execute(uint256)" [PROPOSAL_ID] \
--rpc-url [YOUR_RPC_URL] \
--private-key [YOUR_PRIVATE_KEY]
After execution, the governance contract performs all actions defined in the payload. The protocol changes become effective immediately.
Upgrade Your Node
Critical: Once a proposal executes, you must upgrade your node software to track the protocol changes.
Monitor proposals closely from the signaling stage through execution. When a vote passes, prepare to upgrade your node software during the execution delay period, so you're ready when the proposal becomes effective. In practice, this often means running multiple nodes, with one node being on the version upgraded from, and one being on the version being upgraded to.
Troubleshooting
My Signal Isn't Being Recorded
Symptoms: You configured a payload address, but the signal count isn't increasing.
Solutions:
- Verify you're actually proposing blocks in slots assigned to you
- Check your node logs for errors related to governance signaling
- Verify the payload address is correct and matches the format (0x...)
- Confirm the
GovernanceProposer
contract address is correct for your network
I Can't Delegate My Voting Power
Symptoms: Delegation transaction fails or reverts.
Solutions:
- Verify you're using your withdrawer private key, not your attester key
- Confirm you have stake deposited in the rollup
- Check that the addresses are correct (rollup, attester, delegatee)
- Ensure the rollup address matches where you actually staked
My Vote Transaction Fails
Symptoms: Vote transaction reverts or fails.
Solutions:
- Check the proposal is in the "Active" state (voting period is open)
- Verify you delegated before the voting period started (voting power is timestamped)
- Confirm you have sufficient voting power (check your stake amount)
- Ensure you're not trying to vote with more power than you have
- Check you're using the correct private key (delegatee key, not withdrawer)
How Do I Check When Voting Opens?
Query the proposal to see the voting timeline:
cast call [GOVERNANCE_CONTRACT_ADDRESS] \
"proposals(uint256)" [PROPOSAL_ID] \
--rpc-url [YOUR_RPC_URL]
The returned data includes timestamps for:
- Voting start time
- Voting end time
Summary
As a sequencer participating in governance:
- Signal support: Configure your node with a payload address. Your node automatically signals when proposing blocks.
- Vote: Your delegated stake automatically votes "yea" on proposals created through sequencer signaling. You don't need to take additional action if you support the proposal. To vote differently, delegate your stake to an address you control before voting opens, then vote directly through the GSE contract.
- Upgrade promptly: Monitor proposals and upgrade your node software after execution to stay in sync with protocol changes.
Next Steps
- Learn about sequencer management for operating your node
- Join the Aztec Discord to participate in governance discussions and stay informed about upcoming proposals