Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
Free 30-min Web3 Consultation
Book Now
Smart Contract Security Audits
Learn More
Custom DeFi Protocol Development
Explore
Full-Stack Web3 dApp Development
View Services
LABS
Guides

How to Use Signatures for Governance

A developer guide to implementing cryptographic signatures for secure, gas-efficient on-chain governance. Covers EIP-712, Solana Ed25519, and signature verification patterns.
Chainscore © 2026
introduction
TUTORIAL

Introduction to Signatures in Governance

A technical guide to using cryptographic signatures for on-chain voting, delegation, and proposal execution in DAOs and governance protocols.

In blockchain governance, a signature is a cryptographic proof of consent, generated when a user signs a message with their private key. This mechanism moves governance actions off-chain, enabling gasless voting, secure delegation, and batched transactions. Unlike a direct on-chain transaction, a signature is simply data that can be submitted by any relayer, separating the cost of approval from the cost of execution. This is foundational for systems like OpenZeppelin Governor, Compound's governance, and Snapshot for off-chain voting.

The core component is the EIP-712 standard for typed structured data hashing and signing. EIP-712 allows users to sign human-readable, structured data instead of opaque hexadecimal strings. A governance signature typically includes critical fields like the proposalId, the support value (for/against/abstain), and a nonce to prevent replay attacks. By signing this structured data, a voter authorizes a specific action on a specific proposal, creating a verifiable and secure intent that can be stored or relayed.

Here is a basic example of signing a governance vote using ethers.js and EIP-712:

javascript
const domain = {
  name: 'GovernorContract',
  version: '1',
  chainId: 1,
  verifyingContract: governorAddress
};
const types = {
  Vote: [
    { name: 'proposalId', type: 'uint256' },
    { name: 'support', type: 'uint8' },
    { name: 'nonce', type: 'uint256' }
  ]
};
const value = {
  proposalId: proposalId,
  support: 1, // 1=For, 0=Against, 2=Abstain
  nonce: userNonce
};
const signature = await signer._signTypedData(domain, types, value);

This signature can then be submitted to the governance contract's castVoteBySig function by any party.

Signatures enable gasless voting meta-transactions, where a user signs their vote and a third-party relayer pays the gas to submit it on-chain. They also power vote delegation, where a token holder signs a message authorizing another address to vote on their behalf, as seen in the delegateBySig function. Furthermore, signatures allow for batching multiple governance actions into a single transaction, improving efficiency and reducing costs for multi-step treasury operations or parameter changes.

Security is paramount. Always verify the signer's address on-chain using ecrecover. Contracts must validate the signature against the expected signer and check the nonce to prevent signature replay across chains or proposals. Users must guard their private keys, as a leaked key compromises governance power. For off-chain systems like Snapshot, ensure the signing message and platform are legitimate to avoid phishing attacks that could trick users into signing malicious proposals.

prerequisites
GOVERNANCE SIGNATURES

Prerequisites

Before implementing on-chain governance with signatures, you need to understand the core cryptographic and smart contract concepts involved.

Using signatures for governance requires a foundational understanding of cryptographic primitives. The most common standard is EIP-712, which defines a structured data hashing and signing format. This standard allows users to sign typed, human-readable messages (like a governance proposal) off-chain, which can then be verified and executed on-chain by a smart contract. You should be familiar with the ecrecover function, which is used to retrieve the signer's address from a signature and a message hash. Understanding the separation between the signer, the message, and the verifying contract is critical for secure implementation.

Your development environment must be properly configured. You will need a tool for generating and managing signatures, such as ethers.js v6+ or viem. For testing, frameworks like Hardhat or Foundry are essential. A basic setup includes a local blockchain node (e.g., Hardhat Network) and wallet accounts with test ETH. You'll write smart contracts in Solidity 0.8.x that implement signature verification logic, often inheriting from or referencing OpenZeppelin's EIP712 and ECDSA libraries, which provide battle-tested, secure implementations of these standards.

The core workflow involves three steps: structuring the message, signing it, and verifying it on-chain. First, define your governance action as a Solidity struct, such as ProposalVote. This struct must be hashed according to EIP-712, which includes the contract's domain separator to prevent replay attacks across different chains or contracts. Second, a user signs this hash with their private key using their wallet. Finally, a smart contract function receives the raw proposal data and the signature, recomputes the hash, and uses ecrecover to validate that the signature came from an authorized address (e.g., a token holder).

key-concepts-text
KEY CRYPTOGRAPHIC CONCEPTS

How to Use Signatures for Governance

Digital signatures are the cryptographic foundation for on-chain governance, enabling secure and verifiable voting, proposal submission, and delegation.

In blockchain governance, a digital signature proves that a specific private key holder authorized a transaction or message. For a governance action—like casting a vote on a Snapshot proposal or executing a transaction from a DAO treasury—the user signs a structured message with their private key. This creates a unique cryptographic proof that is publicly verifiable using the signer's corresponding public address. This mechanism ensures non-repudiation; a user cannot later deny they authorized the action, and integrity; the signed data cannot be altered after the fact.

The typical workflow involves signing an EIP-712 typed structured message. Unlike signing a raw transaction, EIP-712 provides human-readable context, reducing phishing risks. A governance proposal's core data—such as proposalId, choice (e.g., "For"), and a timestamp—are hashed into a digest. Signing this digest with a wallet like MetaMask generates the signature. The signature, the original signer's address, and the proposal data are then submitted to the governance platform's backend or smart contract for verification using the ecrecover function.

Here is a simplified JavaScript example using ethers.js to sign a vote:

javascript
const { ethers } = require('ethers');
const domain = {
  name: 'GovernanceDAO',
  version: '1',
  chainId: 1,
  verifyingContract: '0x...'
};
const types = {
  Vote: [
    { name: 'proposalId', type: 'uint256' },
    { name: 'support', type: 'bool' },
  ]
};
const value = { proposalId: 42, support: true };
const signature = await signer._signTypedData(domain, types, value);
// Submit signature, signer address, and `value` to governance contract

For delegation in systems like Compound or Uniswap, signatures enable gas-less delegation of voting power. A token holder signs a message delegating their votes to another address. The delegate can then submit this signature on-chain, claiming the voting power without the original holder needing to send a transaction. This pattern separates the act of delegation from the act of voting, improving user experience and reducing gas costs for passive participants.

Security considerations are critical. Users must verify the domain separator and message structure in their wallet before signing to avoid malicious data. Governance contracts must correctly implement signature verification, checking for replay attacks across chains or forks using the chainId, and ensuring signatures are not reused. Best practice is to use audited, standard libraries like OpenZeppelin's EIP712 contract for on-chain verification logic.

use-cases
PRACTICAL IMPLEMENTATIONS

Governance Signature Use Cases

Signatures are the cryptographic foundation for on-chain governance, enabling secure, gasless, and flexible voting mechanisms. This guide covers the primary technical applications.

GOVERNANCE USE CASES

Signature Standards Comparison

A comparison of common signature standards used for on-chain governance proposals, voting, and delegation.

Feature / MetricEIP-712EIP-1271EIP-191

Primary Use Case

Structured Data Signing

Contract Signature Validation

Simple Message Signing

Human-Readable Format

Off-Chain Verification

On-Chain Verification

Supports Smart Contract Signers

Typed Data Schema

Typical Gas Cost for Verify

~45k gas

~100k+ gas

~30k gas

Common Governance Applications

Vote Delegation, Proposal Submission

DAO Treasury Actions, Multi-sig Proposals

Simple Polls, Snapshot Voting

implementation-ethereum
GUIDE

Implementation: Ethereum & EIP-712

This guide explains how to implement secure, user-friendly off-chain governance voting using EIP-712 typed structured data signatures on Ethereum.

EIP-712 introduces a standard for typed structured data signing, a significant upgrade over raw message hashing (eth_sign). Instead of signing an opaque hexadecimal string, users sign a human-readable JSON structure that clearly defines the vote's intent—proposal ID, choice (e.g., FOR, AGAINST), and a nonce. This improves security and user experience, as wallets like MetaMask display the structured data for verification before signing, reducing the risk of signature phishing attacks.

The core of EIP-712 is defining a type hash and a domain separator. The domain separator (EIP712Domain) includes chain-specific data like the chain ID, verifying contract address, and a name/version, ensuring a signature is only valid for a single contract on a specific network. The vote structure itself is defined in a Vote type, which includes fields like proposalId (uint256), support (uint8), and nonce (uint256). The contract pre-computes the typeHash (the keccak256 hash of the type string) and domainSeparator during construction.

On the client side, you use a library like ethers.js or viem to generate the signature. The process involves creating the data to sign, which includes the domain, the Vote message data, and the types definition. The wallet presents this structured data to the user. The signed digest is the keccak256 hash of \x19\x01 concatenated with the domainSeparator and the hash of the encoded vote data (the structHash). This creates a unique, replay-protected signature.

In the Solidity contract, verification involves reconstructing the structHash from the submitted vote data and the signer's address. The contract uses ecrecover on the final EIP-712 digest to retrieve the signer. It must then check that the recovered signer has voting power, validate the proposal state, and mark the nonce as used to prevent replay attacks. A critical step is verifying the chainId in the domain separator matches the contract's chain to prevent cross-chain replay.

A complete implementation includes tracking used nonces per signer and often batches votes for gas efficiency. For example, a contract might have a castVoteBySig function that accepts the voter's address, proposal ID, support value, nonce, deadline, and the v, r, s signature components. This pattern is used by major protocols like Compound and Uniswap for their governance systems, enabling gas-less voting where a relayer can submit signed votes on behalf of users.

implementation-solana
GOVERNANCE SIGNATURES

Implementation: Solana & Ed25519

A technical guide to implementing on-chain governance using Solana's native Ed25519 signature scheme for proposal signing and voting.

On Solana, governance actions like creating proposals, casting votes, or executing instructions are authorized via cryptographic signatures. The network's foundation is the Ed25519 signature algorithm, a high-performance elliptic curve system. Every transaction must be signed by the fee-paying payer and all accounts that are being written to, making signatures the gatekeeper for state changes. For governance, this means a user's vote is only valid if it is cryptographically signed by the private key corresponding to their governance token holding address, ensuring non-repudiation and integrity.

To implement a basic vote, you construct a transaction containing an instruction to a governance program. The critical step is signing this transaction with the voter's keypair. Using the @solana/web3.js library, this involves creating a Transaction object, adding the vote instruction, and then signing it with the signer's keypair before sending it to the network. The program will then verify the Ed25519 signature against the public key in the instruction data to confirm the voter's identity and authority.

For more complex governance, such as a multisig controlled by a council, you use Solana's Program Derived Address (PDA) system alongside signatures. A multisig account can be created where a transaction requires M-of-N signatures from a set of predefined public keys. The governance program's logic checks that the required number of valid Ed25519 signatures are present in the transaction's signature array before the proposal can pass or treasury funds can be moved. This is how decentralized autonomous organizations (DAOs) like Realms implement secure, collective decision-making.

Security best practices are paramount. Always verify signatures on-chain within the program's instruction handler. Use Pubkey.createProgramAddressSync to derive PDAs for secure, signer-less accounts. For off-chain tooling, never expose private keys; use wallet adapters for signing. Remember that while Ed25519 signatures are fast and secure, the governance logic—such as vote weighting, timelocks, and execution paths—must be meticulously audited, as bugs here are a common attack vector.

Testing your implementation is crucial. Use the solana-program-test framework to simulate the blockchain environment. Write tests that verify: a vote with a correct signature succeeds, a vote with an invalid signature fails, and a multisig proposal executes only with the required threshold of signatures. Incorporating Signature verification and governance logic tests ensures your on-chain system behaves as intended before deploying to mainnet.

GOVERNANCE SIGNATURES

Common Implementation Mistakes

Using cryptographic signatures for on-chain governance is powerful but introduces subtle pitfalls. This guide addresses frequent developer errors in signature-based voting, delegation, and execution.

Signature verification failures are often caused by mismatched message digests. The most common mistake is signing a raw proposal ID or address instead of an EIP-712 typed structured hash. The on-chain verifier must reconstruct the exact same hash that was signed.

Key checks:

  • Ensure you are using encodePacked or encode consistently.
  • Verify the domainSeparator (chainId, verifyingContract) is identical.
  • Confirm the user's signing message matches the contract's getMessageHash output.
  • Test with a known library like @openzeppelin/ether's EIP-712 utilities first.
SIGNATURE-BASED GOVERNANCE

Frequently Asked Questions

Common technical questions and troubleshooting for developers implementing on-chain governance using cryptographic signatures.

Signature-based governance uses cryptographic signatures to authorize on-chain actions, rather than directly voting with tokens in a smart contract. A user signs a structured message (like an EIP-712 typed data payload) off-chain, approving a specific proposal. This signature is then submitted to a contract by any relayer. The contract verifies the signer's address and checks their voting power via a snapshot (e.g., using OpenZeppelin's Votes interface) taken at a past block. This pattern separates the voting action from the transaction execution, enabling:

  • Gasless voting for signers.
  • Delegated execution where a dedicated party submits batches of signatures.
  • Reduced on-chain congestion compared to live token transfers for each vote.
conclusion
IMPLEMENTATION GUIDE

Conclusion and Next Steps

This guide has covered the core concepts of using cryptographic signatures for on-chain governance. The next steps involve practical implementation and exploring advanced patterns.

You should now understand the fundamental role of off-chain signature verification in modern governance. By moving vote collection and aggregation off-chain, protocols like OpenZeppelin's Governor can execute complex, gas-efficient proposals with a single on-chain transaction. This pattern is used by major DAOs including Compound and Uniswap. The key components are the EIP-712 typed data standard for structuring signable messages and the ECDSA.recover function to verify signer addresses on-chain.

To implement this, start by defining your proposal's data structure using EIP-712Domain and custom types. Your off-chain service (like a backend API or a frontend with ethers.js or viem) will generate signatures from authorized voters. The core on-chain contract must then verify these signatures, typically in a proposeBySig or castVoteBySig function, ensuring the recovered address has the requisite voting power. Always include a nonce in the signed data to prevent replay attacks across different proposals or chains.

For production systems, consider these next steps. First, explore signature aggregation with libraries like BLS or tools such as the Safe Snapshot Protocol, which bundle multiple signatures into a single proof to minimize gas costs further. Second, implement deadline enforcement by including a timestamp in the signed message that your contract validates. Third, audit your signature verification logic for common pitfalls like signature malleability or improper EIP-712 domain separator calculation, which must be unique to your contract and chain.

Further resources are essential for robust development. Study the OpenZeppelin Governor contract source code for reference implementations. Use the EIP-712 specification as your canonical guide for typed data. For testing, leverage foundry's vm.sign cheat code or Hardhat's wallet utilities to simulate signature generation within your test suite, ensuring your logic handles edge cases correctly.