Documentation Index Fetch the complete documentation index at: https://mintlify.com/snapshot-labs/sx-monorepo/llms.txt
Use this file to discover all available pages before exploring further.
The Governor Bravo client enables interaction with governance systems built on Compound’s Governor Bravo protocol. It supports both gasless voting through signatures and direct transaction-based voting.
Installation
npm install @snapshot-labs/sx
Overview
Governor Bravo is a widely-used on-chain governance protocol originally developed by Compound. Many DAOs use Governor Bravo or its variants for on-chain governance.
The Governor Bravo client currently supports voting only . Proposal creation and execution must be done through direct contract interaction or other tools.
Client Types
The Governor Bravo client comes in two implementations:
GovernorBravoEthereumSig : Signature-based voting (gasless)
GovernorBravoEthereumTx : Transaction-based voting (direct)
GovernorBravoEthereumSig (Signature-based)
The signature-based client allows users to vote using EIP-712 signatures, which can be submitted by relayers for gasless voting.
Initialization
import { clients } from '@snapshot-labs/sx' ;
const client = new clients . GovernorBravoEthereumSig ({
chainId: 1 // Ethereum mainnet
});
Configuration
Chain ID for the network (1 for Ethereum mainnet, 11155111 for Sepolia)
Methods
vote()
Create a signed vote message that can be submitted to the Governor Bravo contract.
Vote For
Vote Against
Vote Abstain
Vote with Reason
import { Wallet } from '@ethersproject/wallet' ;
const signer = new Wallet ( privateKey );
const envelope = await client . vote ({
signer ,
authenticatorType: 'GovernorBravoAuthenticatorSignature' ,
data: {
spaceId: '0x...' , // Governor contract address
proposalId: 42 , // Proposal ID
choice: 1 // 1 = For
}
});
// The envelope contains signature data that can be submitted
// to the Governor contract's castVoteBySig function
console . log ( 'Signature:' , envelope . signatureData . signature );
signer
Signer & TypedDataSigner
required
Ethers.js signer with EIP-712 signing capabilities
authenticatorType
'GovernorBravoAuthenticatorSignature'
required
Must be set to ‘GovernorBravoAuthenticatorSignature’
Vote data object Governor Bravo contract address
Vote choice:
0 = Against
1 = For
2 = Abstain
Optional reason for the vote (max ~1000 characters recommended)
Returns an envelope containing the signature data and vote data EIP-712 signature that can be submitted to castVoteBySig
EIP-712 domain with governor name and chain ID
Signed message containing proposalId and support
Submitting Signed Votes
After creating a signed vote, it must be submitted to the Governor Bravo contract:
Submit via castVoteBySig
Submit with Reason
import { Contract } from '@ethersproject/contracts' ;
const governorAbi = [
'function castVoteBySig(uint256 proposalId, uint8 support, uint8 v, bytes32 r, bytes32 s)'
];
const governor = new Contract (
envelope . data . spaceId ,
governorAbi ,
provider
);
// Extract signature components
const sig = envelope . signatureData . signature ;
const r = sig . slice ( 0 , 66 );
const s = '0x' + sig . slice ( 66 , 130 );
const v = parseInt ( sig . slice ( 130 , 132 ), 16 );
// Submit the vote
const tx = await governor . castVoteBySig (
envelope . data . proposalId ,
envelope . data . choice ,
v ,
r ,
s
);
await tx . wait ();
console . log ( 'Vote submitted:' , tx . hash );
GovernorBravoEthereumTx (Transaction-based)
The transaction-based client allows direct voting through contract transactions.
Initialization
import { clients } from '@snapshot-labs/sx' ;
import { JsonRpcProvider } from '@ethersproject/providers' ;
const provider = new JsonRpcProvider ( 'https://eth.llamarpc.com' );
const client = new clients . GovernorBravoEthereumTx ({
provider
});
Methods
vote()
Submit a vote transaction directly to the Governor Bravo contract.
Vote Transaction
Vote with Reason
import { Wallet } from '@ethersproject/wallet' ;
const signer = new Wallet ( privateKey , provider );
const tx = await client . vote ({
signer ,
data: {
spaceId: '0x...' , // Governor contract address
proposalId: 42 ,
choice: 1 // 1 = For
}
});
await tx . wait ();
console . log ( 'Vote cast:' , tx . hash );
Ethers.js signer connected to a provider
Vote data object (same structure as signature-based client)
Returns an ethers.js transaction response that can be awaited
Type Definitions
Vote
type Vote = {
spaceId : string ; // Governor Bravo contract address
proposalId : number ; // Proposal ID
choice : 0 | 1 | 2 ; // 0=Against, 1=For, 2=Abstain
reason ?: string ; // Optional vote reason
};
EIP712Ballot
type EIP712Ballot = {
proposalId : number ;
support : number ; // Same as choice
};
type EIP712BallotWithReason = {
proposalId : number ;
support : number ;
reason : string ;
};
SignatureData
type SignatureData = {
authenticatorType : 'GovernorBravoAuthenticatorSignature' ;
address : string ;
signature : string ;
domain : TypedDataDomain ;
types : Record < string , TypedDataField []>;
message : Record < string , any >;
};
Governor Contract Compatibility
The client automatically detects the governor contract name for EIP-712 signing:
// The client queries the governor contract's name() function
const name = await governorContract . name ();
// e.g., "Compound Governor Bravo"
// Used in EIP-712 domain:
const domain = {
name: name ,
chainId: 1 ,
verifyingContract: '0x...'
};
For contracts without a name() function, custom names can be configured in the client source code.
Complete Example
Here’s a full example of voting on a Governor Bravo proposal:
import { clients } from '@snapshot-labs/sx' ;
import { Wallet } from '@ethersproject/wallet' ;
import { JsonRpcProvider } from '@ethersproject/providers' ;
import { Contract } from '@ethersproject/contracts' ;
// 1. Initialize client
const client = new clients . GovernorBravoEthereumSig ({
chainId: 1
});
// 2. Create signer
const provider = new JsonRpcProvider ( 'https://eth.llamarpc.com' );
const signer = new Wallet ( process . env . PRIVATE_KEY , provider );
// 3. Generate signed vote
const envelope = await client . vote ({
signer ,
authenticatorType: 'GovernorBravoAuthenticatorSignature' ,
data: {
spaceId: '0x...' , // Governor address
proposalId: 42 ,
choice: 1 ,
reason: 'Fully support this initiative'
}
});
// 4. Submit vote to Governor contract
const governorAbi = [
'function castVoteWithReasonBySig(uint256 proposalId, uint8 support, string reason, uint8 v, bytes32 r, bytes32 s)'
];
const governor = new Contract (
envelope . data . spaceId ,
governorAbi ,
provider
);
const sig = envelope . signatureData . signature ;
const r = sig . slice ( 0 , 66 );
const s = '0x' + sig . slice ( 66 , 130 );
const v = parseInt ( sig . slice ( 130 , 132 ), 16 );
const tx = await governor . castVoteWithReasonBySig (
envelope . data . proposalId ,
envelope . data . choice ,
envelope . data . reason || '' ,
v ,
r ,
s
);
await tx . wait ();
console . log ( 'Vote successfully cast:' , tx . hash );
Source Code
View the complete implementation: