Skip to main content
Spaces are the core organizational unit in Snapshot X, representing governance DAOs with their own voting configurations and execution strategies. Each space defines how proposals are created, how voting power is calculated, and how approved proposals are executed.

What are Spaces?

A space is a governance DAO that manages proposals, votes, and executions. Every space has:
  • Controller: The address that owns and manages the space
  • Authenticators: Methods for verifying user actions (signatures or transactions)
  • Voting strategies: Rules for calculating voting power
  • Execution strategies: How passed proposals are executed onchain
  • Timing parameters: Voting delay, minimum and maximum voting duration
  • Metadata: Space name, description, and other settings

Types of Spaces

Snapshot X supports different types of governance spaces:

Onchain Spaces

Onchain spaces are deployed as smart contracts and indexed by the Snapshot X API. There are three protocols:

Snapshot X

Native Snapshot X spaces with full flexibility for strategies and executors

Compound Governor

Spaces using Compound’s Governor Bravo protocol

OpenZeppelin Governor

Spaces using OpenZeppelin’s Governor contracts

Offchain Spaces

Offchain spaces use Snapshot’s gasless voting system. These spaces:
  • Store votes and proposals in snapshot-hub
  • Accept signed messages via snapshot-sequencer
  • Don’t require gas fees for voting
  • Can optionally execute proposals onchain after voting

Space Configuration

When deploying a Snapshot X space, you configure these parameters:
type SpaceParams = {
  controller: string;                          // Space owner address
  votingDelay: number;                         // Delay before voting starts (seconds)
  minVotingDuration: number;                   // Minimum voting period
  maxVotingDuration: number;                   // Maximum voting period
  proposalValidationStrategy: AddressConfig;   // Who can create proposals
  proposalValidationStrategyMetadataUri: string;
  daoUri: string;                              // DAO metadata URI
  metadataUri: string;                         // Space metadata URI
  authenticators: string[];                    // Enabled authenticators
  votingStrategies: AddressConfig[];          // Voting power strategies
  votingStrategiesMetadata: string[];         // Strategy metadata URIs
};
The AddressConfig type contains both an address and encoded parameters:
type AddressConfig = {
  addr: string;    // Contract address
  params: string;  // ABI-encoded parameters
};

Creating a Space

Spaces are deployed using the EthereumTx client from sx.js:
import { clients } from '@snapshot-labs/sx';

const client = new clients.evm.EthereumTx({
  networkConfig,
  provider,
  whitelistServerUrl
});

const { address, txId } = await client.deploySpace({
  signer,
  params: {
    controller: '0x...',
    votingDelay: 0,
    minVotingDuration: 86400,      // 1 day
    maxVotingDuration: 604800,     // 7 days
    proposalValidationStrategy: {
      addr: '0x...',
      params: '0x00'
    },
    proposalValidationStrategyMetadataUri: '',
    daoUri: 'ipfs://...',
    metadataUri: 'ipfs://...',
    authenticators: [
      '0x...'  // ethSig authenticator
    ],
    votingStrategies: [
      {
        addr: '0x...',  // Token voting strategy
        params: tokenAddress
      }
    ],
    votingStrategiesMetadata: ['']
  },
  saltNonce: '0x...'
});
The space address is deterministic based on the saltNonce, allowing you to predict the address before deployment:
const predictedAddress = await client.predictSpaceAddress({
  signer,
  saltNonce
});

Managing Spaces

Space controllers can update settings after deployment:

Update Settings

await client.updateSettings({
  signer,
  space: '0x...',
  settings: {
    minVotingDuration: 172800,  // 2 days
    maxVotingDuration: 1209600, // 14 days
    votingDelay: 3600,          // 1 hour
    metadataUri: 'ipfs://...',
    daoUri: 'ipfs://...',
    authenticatorsToAdd: ['0x...'],
    authenticatorsToRemove: ['0x...'],
    votingStrategiesToAdd: [{
      addr: '0x...',
      params: '0x...'
    }],
    votingStrategiesToRemove: [0],  // Remove strategy at index 0
    votingStrategyMetadataUrisToAdd: ['']
  }
});

Transfer Ownership

await client.transferOwnership({
  signer,
  space: '0x...',
  owner: '0x...'  // New controller address
});

Space Lifecycle

The typical flow for a governance space:
1

Deploy Space

Deploy the space contract with initial configuration
2

Create Proposals

Users create proposals using configured authenticators and validation strategies
3

Vote on Proposals

Users vote using their voting power calculated by voting strategies
4

Execute Proposals

Passed proposals are executed according to the execution strategy
5

Update Configuration

Space controller can modify settings as needed

Network Configuration

Each network has a configuration defining available strategies, authenticators, and factory contracts:
type NetworkConfig = {
  eip712ChainId: string;
  spaceFactory: string;
  masterSpace: string;
  starknetCommit: string;
  starknetCore: string;
  herodotusAccumulatesChainId: number;
  authenticators: {
    [address: string]: AuthenticatorConfig;
  };
  strategies: {
    [address: string]: StrategyConfig;
  };
};
For EVM networks, additional configuration includes:
type EvmNetworkConfig = {
  eip712ChainId: number;
  blockTime: number;
  proxyFactory: string;
  executionStrategiesImplementations: {
    SimpleQuorumVanilla?: string;
    SimpleQuorumAvatar?: string;
    SimpleQuorumTimelock?: string;
    EthRelayer?: string;
    Axiom?: string;
    Isokratia?: string;
  };
};

Data Flow

Spaces interact with multiple components:

Authenticators

Learn how users authenticate their actions

Strategies

Understand voting power calculation

Executors

Explore execution patterns

Creating Proposals

Start creating proposals

Build docs developers (and LLMs) love