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

Setting Up a Snapshot Strategy for Off-Chain Voting

A technical tutorial for deploying a Snapshot space, writing custom voting strategies in JavaScript, and integrating with forums and on-chain execution.
Chainscore © 2026
introduction
DEVELOPER GUIDE

Setting Up a Snapshot Strategy for Off-Chain Voting

A technical walkthrough for creating and deploying a custom voting strategy on the Snapshot platform, enabling complex off-chain governance logic.

A Snapshot strategy is a smart contract or JavaScript function that determines a user's voting power for a proposal. While Snapshot provides basic strategies like erc20-balance-of, custom strategies are essential for implementing governance models based on delegated voting, time-weighted balances, NFT ownership, or cross-chain assets. Strategies are executed off-chain by Snapshot's indexer, which reads on-chain data to calculate scores without gas fees. The core concept is that each strategy returns a numerical score for each voter address, which is then used to tally votes.

To create a custom strategy, you must write a function that adheres to Snapshot's strategy interface. For an on-chain Ethereum strategy, this is typically a Solidity view function. For a simpler, multi-chain compatible approach, you can write a JavaScript function using the Strategy Template. The function receives parameters like the proposal creation block, voter address, and strategy-specific options, and must return a score. For example, a basic ERC-20 strategy checks the token balance at a specific block: return token.balanceOf(voter). More complex logic can involve querying staking contracts or verifying Merkle proofs for airdrops.

Here is a simplified example of a JavaScript strategy that calculates voting power based on a user's balance of two different ERC-20 tokens, with the second token's holdings weighted double.

javascript
export async function strategy(space, network, provider, addresses, options, snapshot) {
  const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
  // Fetch balances for first token
  const scores1 = await getScores(...);
  // Fetch balances for second token with multiplier
  const scores2 = await getScores(...);
  // Combine scores
  return Object.fromEntries(
    addresses.map((address) => [
      address,
      (scores1[address] || 0) + (scores2[address] || 0) * 2
    ])
  );
}

This function uses Snapshot's helper libraries to fetch on-chain data efficiently.

After developing your strategy, you must deploy and verify it. For Solidity contracts, deploy to a network like Ethereum Mainnet or a testnet and verify the source code on a block explorer. For JavaScript strategies, you publish the code to a public GitHub repository or a decentralized storage service like IPFS. The final step is to register the strategy in your Snapshot space's settings. You provide the network (e.g., 1 for Ethereum), the contract address (or GitHub/IPFS link for JS), and any required parameters. Once added, proposal creators can select your custom strategy to define voting power for their specific governance question.

Testing is critical. Use Snapshot's Playground to simulate your strategy against real addresses and block numbers before going live. Common pitfalls include incorrect block number handling, which can lead to snapshot manipulation, and inefficient data fetching that may cause timeouts. Always consider the security implications: strategies are read-only but if they rely on external oracles or manipulable data sources, they can affect vote integrity. For production use, strategies should be audited and their logic clearly documented for your community to ensure transparent governance.

prerequisites
GETTING STARTED

Prerequisites and Initial Setup

Before deploying a Snapshot strategy, you need a configured development environment and a clear understanding of the voting data you'll query.

To develop a custom Snapshot strategy, you'll need a Node.js environment (v16 or later) and a package manager like npm or yarn. The core dependency is the @snapshot-labs/snapshot.js library, which provides the necessary utilities for interacting with the Snapshot Hub API and Ethereum networks. Install it using npm install @snapshot-labs/snapshot.js. You'll also need access to a JSON-RPC provider for the blockchain your strategy will query; public providers from services like Infura or Alchemy are suitable for development.

A Snapshot strategy is fundamentally a function that fetches and scores voter addresses based on on-chain data. Your development setup should include a clear plan for the data you need: common examples include ERC-20 token balances, NFT holdings, or delegated voting power from contracts like Compound's Governor Bravo or OpenZeppelin's ERC20Votes. You must identify the exact smart contract addresses and the specific function calls (e.g., balanceOf, getVotes) required to calculate scores.

Finally, set up a testing structure. You can test your strategy logic locally by mocking the network, addresses, and snapshot block number parameters. Use the snapshot.js helper multicall function to batch RPC calls for efficiency. Ensure you understand the required return format: an object mapping voter addresses to their score (as a string). A basic strategy skeleton returns { [voterAddress]: '100' } where the score is often a token balance. Thorough local testing prevents failed proposals due to RPC errors or incorrect scoring logic on the Snapshot Hub.

space-creation
FOUNDATION

Step 1: Creating and Configuring Your Snapshot Space

Your Snapshot Space is the central hub for your DAO's off-chain governance. This guide walks through the initial setup and configuration.

A Snapshot Space is a dedicated page for your DAO's proposals and votes. It is not a smart contract but a front-end interface that reads voting power from a strategy—a set of rules defining who can vote and how much their vote counts. To begin, navigate to snapshot.org, connect your wallet (typically the one that will become the Space's controller), and click "Create a space". You'll be prompted to enter a unique name (e.g., my-dao.eth), which will become your Space's URL.

The core configuration happens in the Settings tab. Key fields include:

  • Avatar & Cover: Upload images for branding.
  • Admins: Add wallet addresses (multisig recommended) with full control over the Space settings.
  • Moderators: Add addresses that can hide or delete proposals.
  • Terms: Link to your governance constitution or rules.
  • Voting Delay & Period: Set a delay before voting starts and the duration votes are open (e.g., 24-hour delay, 5-day period).
  • Proposal Threshold: Optional minimum token balance required to submit a proposal.

The most critical setting is the Voting Strategy. This defines how member voting power is calculated. Snapshot provides pre-built strategies like erc20-balance-of (for standard ERC-20 tokens), erc721 (for NFT-based voting), and contract-call for custom logic. For a basic token-weighted DAO, select erc20-balance-of and enter your governance token's contract address and the snapshot block number (often the latest block when the proposal is created). The strategy will calculate balances at that historical block, preventing manipulation.

For advanced use cases, you can compose multiple strategies using the multichain or weighted strategy types. For example, you could combine an erc20-balance-of strategy on Ethereum with a delegation strategy on Polygon to calculate cross-chain voting power. Always test your strategy configuration using the "Check" button in the Snapshot interface, which will simulate voting power for a sample address.

Finally, configure your Voting System. The default is single-choice voting (e.g., "For," "Against," "Abstain"). For more complex decisions, you can enable approval voting (vote for multiple options) or quadratic voting (where cost scales quadratically with vote weight). Each system has different implications for sybil resistance and preference expression. Once settings are saved, your Space is live and ready for its first proposal.

voting-strategies
CORE CONCEPTS

Step 2: Understanding and Selecting Voting Strategies

A voting strategy defines the rules for determining who can vote and how voting power is calculated. This step is critical for ensuring your governance system reflects your community's structure.

In Snapshot, a voting strategy is a smart contract or an off-chain function that calculates a user's voting power for a specific proposal. It answers the fundamental question: "How many votes does this address get?" Strategies are not one-size-fits-all; they are modular components you select to align with your DAO's tokenomics and governance model. Common strategies include token-weighted voting (1 token = 1 vote), delegation-based voting (like Compound/Uniswap), or multi-token strategies that combine several assets.

You can use single strategies or multiple strategies in combination. For example, a DAO might use a primary erc20-balance-of strategy for its governance token, plus a secondary erc721-balance-of strategy to grant additional voting power to NFT holders. Snapshot aggregates the results. Strategies are specified in the proposal creation form using their unique identifier, such as erc20-balance-of or delegation. The strategy's parameters, like the contract address of the token and the snapshot block number, are defined in a JSON format.

Here is a basic example of a strategy configuration for a simple ERC-20 token vote, as it would be defined in the Snapshot interface:

json
{
  "symbol": "GOV",
  "address": "0x1234...",
  "decimals": 18,
  "strategy": {
    "name": "erc20-balance-of",
    "params": {
      "address": "0x1234...",
      "symbol": "GOV",
      "decimals": 18
    }
  }
}

This configuration tells Snapshot to calculate voting power based on the GOV token balance of each address at the specified snapshot block.

Selecting the right strategy requires analyzing your goals. Use erc20-balance-of for straightforward token governance. For delegated systems like those used by Uniswap or Compound, use the delegation strategy. To require a minimum holding, combine erc20-balance-of with a whitelist strategy. For more complex logic—like quadratic voting, time-locked weights, or cross-chain balances—you may need a custom strategy. You can browse and fork existing strategies on the Snapshot Strategy Registry.

The snapshot block number is a crucial parameter for most strategies. This is the Ethereum block height (or block number on the relevant chain) at which voter balances are recorded. It prevents users from buying tokens after a proposal is created to manipulate the vote. Always set this to a block number from before the proposal is published. You can use a block explorer or a tool like the Snapshot Block Finder to get a recent block number.

After understanding strategies, the next step is to create a space and configure its settings, including setting a default voting strategy and proposal validation criteria. A well-chosen strategy ensures your governance process is secure, fair, and resistant to manipulation from token swapping or sybil attacks.

custom-strategy-development
SNAPSHOT INTEGRATION

Step 3: Developing a Custom Voting Strategy

Learn how to write and deploy a custom strategy contract to enable complex, off-chain voting logic for your DAO's Snapshot space.

A Snapshot strategy is a smart contract that defines how voting power is calculated for a proposal. Instead of a simple 1-token-1-vote model, strategies allow you to implement custom logic like quadratic voting, time-weighted balances, or multi-token governance. The strategy contract's getVotingPower function is called by Snapshot's off-chain indexer to determine each voter's power at a specific block number. You can write strategies in Solidity or Vyper and deploy them to any EVM-compatible network, though Ethereum mainnet is most common for verification.

To develop a strategy, you must implement the interface defined by Snapshot. The core function is getVotingPower(address voter, uint256 blockNumber, bytes calldata params). This function returns a uint256 representing the voter's power. The params field allows for flexible configuration per proposal. For example, a strategy could calculate power based on a user's balance of a specific ERC-20 token, their NFT holdings, or their reputation in a different system. You can review existing strategies on the Snapshot Strategy Registry for inspiration.

Here is a basic example of a strategy that calculates voting power based on an ERC-20 token balance:

solidity
pragma solidity ^0.8.0;
interface IERC20 {
    function balanceOf(address account) external view returns (uint256);
}
contract ERC20BalanceStrategy {
    function getVotingPower(
        address voter,
        uint256 blockNumber,
        bytes calldata params
    ) external view returns (uint256) {
        address token = abi.decode(params, (address));
        // Note: Using `blockNumber` for historical lookups requires archive node access.
        return IERC20(token).balanceOf(voter);
    }
}

After deployment, you must verify the contract source code on a block explorer like Etherscan. This allows Snapshot to publicly read and trust your contract's logic.

Once deployed, you add the strategy to your Snapshot space. Navigate to your space's settings, select "Strategies," and click "Add Strategy." You will need to provide:

  • Name: A unique identifier (e.g., "erc20-balance").
  • Network: The chain where the contract is deployed (e.g., "1" for Ethereum Mainnet).
  • Contract Address: The address of your verified strategy contract.
  • Parameters: Default params to be passed to getVotingPower, encoded as a string (e.g., the token address). You can assign multiple strategies to a space; Snapshot will sum the voting power from each. Always test your strategy thoroughly on a testnet and use Snapshot's Playground to simulate votes before going live.

Common advanced strategies include multi-token voting (power from several assets), delegation (power from other voters), and time-lock based voting (power based on how long tokens have been held). Remember that strategies are read-only and executed off-chain; they do not handle vote casting or execution. Their sole purpose is to provide a cryptographically verifiable snapshot of voting power. For on-chain execution of proposal results, you would pair Snapshot with an execution layer like SafeSnap or a custom Zodiac module.

STRATEGY TYPES

Comparison of Common Snapshot Voting Strategies

Key characteristics and trade-offs of the most widely used voting strategies for Snapshot proposals.

Strategy / MetricSingle-Choice VotingQuadratic VotingRanked-Choice VotingWeighted Voting

Core Mechanism

One token, one vote per choice

Voting power = sqrt(tokens)

Rank candidates by preference

Vote weight based on custom formula

Best For

Simple yes/no or single-option proposals

Reducing whale dominance, community sentiment

Elections with multiple candidates

Complex governance (e.g., time-locked tokens)

Gas Efficiency

High

Medium

Medium

Low (depends on strategy)

Resistance to Sybil Attacks

Low

High (with proof-of-personhood)

Medium

Varies by weight source

Implementation Complexity

Low

Medium

Medium

High

Typical Use Case

Protocol parameter changes

Grant funding allocations

DAO committee elections

Vesting-based governance

Vote Counting

Sum of votes per choice

Sum of sqrt(votes) per choice

Instant-runoff elimination

Custom calculation per voter

proposal-workflow
SETTING UP A SNAPSHOT STRATEGY

Step 4: Creating Proposals and Managing the Voting Workflow

Learn how to configure a custom voting strategy on Snapshot to define who can vote and how voting power is calculated for your DAO's off-chain governance.

A Snapshot strategy is a JavaScript function that determines a voter's eligibility and voting power at a specific block number. It fetches on-chain data—like token balances, NFT ownership, or delegated votes—to create the voter list for a proposal. You don't write proposals in Snapshot; you create them. The core governance logic is defined by the strategy you select or build. Popular pre-built strategies include erc20-balance-of (for token-weighted voting) and erc721 (for NFT-based voting), but custom strategies are common for complex DAOs.

To set up a custom strategy, you must write and deploy a JSON file containing your strategy's metadata and logic to a public URL, typically via IPFS. The key components are a name, author, version, and the strategy function itself. The function receives parameters like the voter's address, the proposal's snapshot block number, and your DAO's contract addresses. It must return an object with a score property representing the voter's power. Here is a basic template for a custom ERC-20 strategy:

js
export async function strategy(space, network, provider, addresses, options, snapshot) {
  const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
  // Fetch token balances using a library like ethers.js
  const scores = await getScores(...);
  return Object.fromEntries(
    addresses.map((address) => [address, scores[address] || 0])
  );
}

After deploying your strategy JSON to IPFS, you add its content hash (like Qm...) to your Snapshot space settings under Strategies. You can combine multiple strategies (e.g., token balance + delegation) by setting their weights.

Once your strategy is active, creating a proposal is straightforward. In your Snapshot space, click New Proposal. You'll define the title, description, choices (e.g., "For," "Against," "Abstain"), and voting period. The critical step is setting the Snapshot block number. This is the block at which voter eligibility is calculated using your strategy. Choose a recent, finalized block before the proposal is published to prevent manipulation. The voting workflow then proceeds off-chain, with signatures validating votes.

Managing the workflow involves monitoring proposal states: Pending, Active, Closed. After voting closes, results are tallied based on your strategy's scoring. While Snapshot votes are not directly on-chain, many DAOs use bridging tools like Snapshot's Relayer or custom governor contracts (e.g., OpenZeppelin's) to execute passed proposals. This often involves a multi-sig or a specialized contract checking the Snapshot outcome and submitting the transaction on-chain.

Best practices for strategy design include using a single, verified block number for all voters, caching data to reduce RPC calls, and thoroughly testing with a testnet space first. Security is paramount: a flawed strategy can disenfranchise voters or allow sybil attacks. Always audit custom logic and consider using established, audited strategies from the Snapshot strategy library when possible.

on-chain-execution
SNAPSHOT STRATEGY

Step 5: Linking Off-Chain Votes to On-Chain Execution

This guide explains how to create a Snapshot strategy to validate and link off-chain voting results to on-chain execution, a critical component for secure DAO governance.

A Snapshot strategy is a custom validation script that determines a user's voting power for a specific proposal. It acts as the bridge between the off-chain vote on Snapshot and the on-chain execution via a Safe transaction. When a proposal is created, you define which strategy to use, such as checking token holdings, delegation status, or membership in a specific NFT collection. The strategy's logic is executed when a user casts a vote, calculating their power based on on-chain data at a specific block snapshot. This ensures the vote is weighted according to the DAO's chosen governance model.

To create a strategy, you write a JavaScript function that returns a Promise resolving to an object containing the voter's address and their voting power. The function receives parameters like the voter's address, the proposal's snapshot block number, and any custom parameters defined in the proposal. For example, a basic ERC-20 token strategy fetches the user's token balance at the snapshot block using the multicall method from the ethers.js library. You must publish your strategy's code to a public repository like GitHub, as Snapshot will fetch and execute it from there.

Here is a simplified example of an ERC-20 token holding strategy:

javascript
async function strategy(space, network, provider, addresses, options, snapshot) {
  const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
  const contract = new ethers.Contract(
    options.address, // Token contract address
    ['function balanceOf(address) view returns (uint256)'],
    provider
  );
  const balances = await Promise.all(
    addresses.map((address) => contract.balanceOf(address, { blockTag }))
  );
  return Object.fromEntries(
    addresses.map((address, i) => [address, parseFloat(ethers.utils.formatUnits(balances[i], options.decimals))])
  );
}

This function queries the token contract for each voter's balance at the snapshot block and returns the results formatted as plain numbers.

After deploying your strategy, you must register it on the Snapshot hub. This involves submitting a pull request to the snapshot-strategies GitHub repository. Your PR should include your strategy file and an entry in the src/strategies.json file, which defines the strategy's key, version, and schema for its parameters. Once merged, the strategy becomes available for any space to use. You can test it locally using Snapshot's strategy tester or on a testnet proposal before relying on it for mainnet governance.

The final link to on-chain execution is the Safe transaction hash. After a Snapshot proposal passes, the DAO's designated executor (often a Safe multisig or a specialized module) creates a transaction in the Safe interface. The executor must provide the proposal's unique identifier, typically the IPFS hash from Snapshot, as part of the transaction's metadata. This creates an immutable, verifiable link proving that the on-chain action is the direct result of a specific, validated off-chain vote. This audit trail is essential for transparency and security in decentralized governance.

SNAPSHOT STRATEGIES

Frequently Asked Questions (FAQ)

Common questions and troubleshooting for developers building custom voting strategies on Snapshot, the off-chain governance platform.

A Snapshot strategy is a JavaScript function that determines a user's voting power for a proposal. It fetches data from on-chain or off-chain sources (like token balances, NFT ownership, or delegated votes) at a specific block number. The strategy executes within Snapshot's serverless infrastructure, returning a score object where keys are voter addresses and values are their voting power.

Key components:

  • strategy.name: A unique identifier.
  • strategy.network: The blockchain network (e.g., 1 for Ethereum Mainnet).
  • strategy.params: Configuration parameters for the strategy.
  • The core function: strategy(space, network, provider, addresses, options, snapshot).

Strategies are the foundational logic that moves governance from simple token-weighted voting to complex, permission-based systems.

conclusion
IMPLEMENTATION SUMMARY

Conclusion and Next Steps

You have now configured a complete off-chain voting strategy using Snapshot, from proposal creation to result execution.

Your Snapshot strategy is now operational. The core components you have deployed include a voting strategy (e.g., ERC-20 token-weighted), a proposal validation strategy to set creation rules, and a space controller for administrative permissions. The strategy's logic is executed off-chain via the Snapshot Hub, which aggregates wallet signatures to determine vote outcomes without gas fees. Remember that the final, on-chain execution of a proposal's actions is a separate step, typically managed by a multisig or a custom executor contract that validates the Snapshot vote result.

For production use, rigorous testing is essential. Deploy your strategy contracts to a testnet like Sepolia or Goerli. Use the Snapshot test suite to simulate voting scenarios and verify vote power calculations. Test edge cases: zero balances, delegated voting, and the interaction between your validation and voting strategies. Monitor gas costs for the getVotingPower function, as high gas can lead to indexing failures on the Hub.

Consider advanced strategy features to enhance governance. Implement quadratic voting to reduce whale dominance, or a time-weighted strategy based on token age (vesting). For cross-chain DAOs, explore strategies using LayerZero or Axelar for omnichain vote aggregation. All strategies must be publicly verified on block explorers like Etherscan, and their addresses must be whitelisted in your Snapshot space settings to be usable.

The next step is integration and monitoring. Add your strategy to a UI like the Snapshot front-end or a custom dApp using the Snapshot.js library. Set up alerts for new proposals and vote conclusions. For on-chain execution, ensure your executor (e.g., a Safe multisig with the Zodiac module) is configured to read from the correct Snapshot space and proposal ID.

Stay updated with Snapshot's evolution. Follow the Snapshot GitHub for core protocol updates and new strategy templates. The ecosystem is moving towards EIP-712 structured data signing and ERC-1271 for smart contract signatures, which will enable more complex delegation patterns. Your strategy should be reviewed periodically to incorporate security patches and leverage new features for a more resilient governance process.

How to Set Up a Snapshot Strategy for Off-Chain Voting | ChainScore Guides