Voting strategies determine how voting power is calculated for proposals. The SDK provides built-in strategies for token-based voting, whitelists, cross-chain proofs, and custom validation logic.
Overview
Strategies are organized by network type:
EVM strategies : For Ethereum and EVM-compatible chains
Starknet strategies : For Starknet L2
Offchain strategies : For gasless, offchain governance
Getting Strategies
Strategies are retrieved based on network configuration:
import { getEvmStrategy , getStarknetStrategy , getOffchainStrategy } from '@snapshot-labs/sx' ;
// EVM strategy
const evmStrategy = getEvmStrategy (
strategyAddress ,
networkConfig
);
// Starknet strategy
const starknetStrategy = getStarknetStrategy (
strategyAddress ,
networkConfig
);
// Offchain strategy
const offchainStrategy = getOffchainStrategy (
strategyName
);
EVM Strategies
Vanilla Strategy
Simple strategy that returns a fixed voting power:
import { createVanillaStrategy } from '@snapshot-labs/sx/strategies/evm' ;
const strategy = createVanillaStrategy ();
Use case : Testing or simple one-person-one-vote scenarios.
OpenZeppelin Votes (OZ Votes)
Voting power based on ERC20Votes or ERC721Votes tokens:
import { createOzVotesStrategy } from '@snapshot-labs/sx/strategies/evm' ;
const strategy = createOzVotesStrategy ();
const params = await strategy . getParams (
'vote' ,
strategyConfig ,
signerAddress ,
metadata ,
voteData ,
config
);
Use case : DAOs using OpenZeppelin’s governance tokens with built-in voting power tracking.
This strategy reads voting power from tokens implementing the IVotes interface with getPastVotes() or getPastTotalSupply().
Compound Strategy
Voting power based on Compound-style governance tokens:
import { createCompStrategy } from '@snapshot-labs/sx/strategies/evm' ;
const strategy = createCompStrategy ();
Use case : DAOs using Compound’s governance token standard with delegation.
Merkle Whitelist
Voting power based on a pre-defined whitelist stored in a merkle tree:
import { createMerkleWhitelist } from '@snapshot-labs/sx/strategies/evm' ;
const strategy = createMerkleWhitelist ();
Use case : Governance restricted to specific addresses with predetermined voting power.
ApeGas Strategy
Specialized strategy for ApeCoin DAO with delegation support:
import { createApeGasStrategy } from '@snapshot-labs/sx/strategies/evm' ;
const strategy = createApeGasStrategy ();
Use case : ApeCoin DAO governance with delegate.cash integration.
Starknet Strategies
Vanilla Strategy
Basic Starknet strategy:
import { createVanillaStrategy } from '@snapshot-labs/sx/strategies/starknet' ;
const strategy = createVanillaStrategy ();
ERC20 Votes
Starknet ERC20 token voting:
import { createErc20VotesStrategy } from '@snapshot-labs/sx/strategies/starknet' ;
const strategy = createErc20VotesStrategy ();
Use case : Voting power based on Starknet ERC20 token balances.
Merkle Whitelist
Whitelist-based voting on Starknet:
import { createMerkleWhitelistStrategy } from '@snapshot-labs/sx/strategies/starknet' ;
const strategy = createMerkleWhitelistStrategy ();
OZ Votes Storage Proof
Cross-chain voting using Ethereum storage proofs verified on Starknet:
import { createOzVotesStorageProofStrategy } from '@snapshot-labs/sx/strategies/starknet' ;
const strategy = createOzVotesStorageProofStrategy ( params );
Use case : L1 token holders voting on L2 proposals without bridging tokens.
This strategy uses Herodotus storage proofs to verify Ethereum state on Starknet, enabling secure cross-chain governance.
EVM Slot Value
Read arbitrary EVM storage slot values on Starknet:
import { createEvmSlotValueStrategy } from '@snapshot-labs/sx/strategies/starknet' ;
const strategy = createEvmSlotValueStrategy ();
Use case : Custom voting power calculations based on any Ethereum storage value.
Offchain Strategies
Only Members
Restrict proposals/votes to space members:
import { createOnlyMembersStrategy } from '@snapshot-labs/sx/strategies/offchain' ;
const strategy = createOnlyMembersStrategy ();
Remote VP (Voting Power)
Calculate voting power using remote APIs:
import { createRemoteVpStrategy } from '@snapshot-labs/sx/strategies/offchain' ;
const strategy = createRemoteVpStrategy ();
Use case : Complex voting power calculations using Snapshot’s voting power engine.
Remote Validate
Validate voters using predefined validation schemes:
import { createRemoteValidateStrategy } from '@snapshot-labs/sx/strategies/offchain' ;
const strategy = createRemoteValidateStrategy ( 'basic' );
// or
const passportStrategy = createRemoteValidateStrategy ( 'passport-gated' );
const arbitrumStrategy = createRemoteValidateStrategy ( 'arbitrum' );
const karmaStrategy = createRemoteValidateStrategy ( 'karma-eas-attestation' );
Supported validators :
any: Allow anyone
basic: Basic validation
passport-gated: Gitcoin Passport gating
arbitrum: Arbitrum-specific validation
karma-eas-attestation: Karma EAS attestation validation
Strategy Parameters
Strategies can accept configuration parameters:
interface StrategyConfig {
address : string ; // Strategy contract address
index : number ; // Strategy index in the space
params ?: string []; // Strategy-specific parameters
metadata ?: any ; // Additional metadata
}
Getting Strategy Parameters
import { getStrategiesWithParams } from '@snapshot-labs/sx/strategies/evm' ;
const strategiesWithParams = await getStrategiesWithParams (
'vote' , // 'propose' or 'vote'
strategiesConfigs ,
signerAddress ,
voteData ,
clientConfig
);
Strategy Interface
All strategies implement a common interface:
interface Strategy {
getParams (
call : 'propose' | 'vote' ,
strategyConfig : StrategyConfig ,
signerAddress : string ,
metadata : any ,
data : Propose | Vote ,
config : ClientConfig
) : Promise < string []>;
}
Multi-Strategy Voting
Spaces can combine multiple strategies:
const strategies = [
{
address: '0xOzVotesStrategy...' ,
index: 0 ,
params: [ '0xTokenAddress...' , '0' ]
},
{
address: '0xWhitelistStrategy...' ,
index: 1 ,
params: [ merkleRoot ]
}
];
const totalVotingPower = strategies . reduce (
( sum , strategy ) => sum + strategyVotingPower ( strategy ),
0 n
);
When using multiple strategies, ensure they don’t conflict (e.g., different token balances counting towards the same vote).
Custom Strategies
Create custom strategies by implementing the strategy interface:
function createCustomStrategy () : Strategy {
return {
async getParams ( call , strategyConfig , signerAddress , metadata , data , config ) {
// Custom logic to calculate and return strategy parameters
const votingPower = await calculateVotingPower ( signerAddress );
return [ votingPower . toString ()];
}
};
}
Storage Proofs
Some strategies use storage proofs for cross-chain verification:
import { storageProofs } from '@snapshot-labs/sx' ;
// Generate storage proof for L1 token balance
const proof = await storageProofs . generateProof (
tokenAddress ,
userAddress ,
blockNumber
);
Common Patterns
Token-Based Voting
// 1. Configure token strategy
const strategyConfig = {
address: ozVotesStrategyAddress ,
index: 0 ,
params: [ tokenAddress , '0' ] // token address and slot index
};
// 2. Get voting parameters
const params = await strategy . getParams (
'vote' ,
strategyConfig ,
voterAddress ,
null ,
voteData ,
config
);
// 3. Submit vote with parameters
Whitelist Voting
import { merkle } from '@snapshot-labs/sx' ;
// 1. Generate merkle tree
const entries = [
'0xAddress1:1000' ,
'0xAddress2:2000'
];
const tree = await merkle . generateMerkleTree ( entries );
const root = tree [ 0 ];
// 2. Deploy or update strategy with root
const strategyConfig = {
address: whitelistStrategyAddress ,
index: 0 ,
params: [ root ]
};
// 3. Generate proof for voter
const proof = merkle . generateMerkleProof ( tree , voterIndex );
Best Practices
Choose Appropriate Strategy Select strategies that match your governance model and token standard
Test Parameters Validate strategy parameters before deployment
Consider Gas Costs Some strategies (storage proofs) have higher gas costs
Snapshot Timing Ensure voting power snapshots are taken at the right block
Utils Merkle tree and storage proof utilities
Authenticators Authentication methods
Executors Execution strategies