SPL Governance Documentation
Build and run decentralized autonomous organizations with modular smart contracts on Solana.
High Performance
Built on Solana's 400ms block time with ultra-low transaction costs averaging $0.00025.
Modular Architecture
Plug in custom voting mechanisms, proposal types, and governance logic without core modifications.
NFT Integration
Native support for NFT-based governance with customizable voting weight calculations.
Installation
npm install @solana/spl-governance
yarn add @solana/spl-governance
pnpm add @solana/spl-governance
Quick Start
Initialize the SDK
Set up the SPL Governance SDK in your project:
import { Connection, PublicKey } from '@solana/web3.js';
import { GovernanceSDK } from '@solana/spl-governance';
// Initialize connection to Solana
const connection = new Connection('https://api.mainnet-beta.solana.com');
// Initialize the governance SDK
const governance = new GovernanceSDK({
connection,
wallet: yourWallet, // Your Solana wallet adapter
});
console.log('SPL Governance SDK initialized!');
Create a Governance Realm
Set up your first DAO governance realm:
// Create a new governance realm
const realmConfig = {
name: "My DAO",
communityMintPk: new PublicKey("your-community-token-mint"),
councilMintPk: null, // Optional council token
communityMintMaxVoteWeightSource: {
type: 'SupplyFraction',
value: new BN(1000000), // 100% of supply
},
};
const realm = await governance.createRealm(realmConfig);
console.log('Realm created:', realm.publicKey.toString());
Create Your First Proposal
Submit a proposal for community voting:
// Create a proposal
const proposalConfig = {
governancePk: realm.governance.publicKey,
proposalOwnerRecord: ownerRecord.publicKey,
name: "Treasury Allocation Proposal",
descriptionLink: "https://your-dao.com/proposals/1",
governingTokenMint: realm.communityMint,
};
const proposal = await governance.createProposal(proposalConfig);
console.log('Proposal created:', proposal.publicKey.toString());
Core Concepts
Realm
The top-level governance entity that represents your DAO. Contains all governance configuration and manages token-based voting rights.
- Community token mint
- Optional council token mint
- Governance configuration
- Treasury accounts
Governance
Controls a specific treasury account and defines the rules for proposals and voting within that scope.
- Voting thresholds
- Time limits
- Proposal deposits
- Execution delays
Proposal
A specific action or change that the DAO can vote on. Can contain multiple instructions to execute if approved.
- Draft â Voting â Succeeded/Defeated
- Optional execution phase
- Automatic state transitions
Token Owner Record
Represents a member's voting power within the governance. Created when tokens are deposited.
- Voting weight calculation
- Proposal ownership
- Governance participation
Governance API
createRealm(config)
Parameters
Name | Type | Description |
---|---|---|
name |
string | The name of the governance realm |
communityMintPk |
PublicKey | The mint address for community governance tokens |
councilMintPk |
PublicKey | null | Optional mint address for council tokens |
Example
const realm = await governance.createRealm({
name: "DeFi Protocol DAO",
communityMintPk: new PublicKey("11111111111111111111111111111112"),
councilMintPk: null,
communityMintMaxVoteWeightSource: {
type: 'SupplyFraction',
value: new BN(1000000),
},
});
Proposal API
createProposal(config)
Parameters
Name | Type | Description |
---|---|---|
governancePk |
PublicKey | The governance account public key |
name |
string | The proposal name/title |
descriptionLink |
string | URL to the proposal description |
Example
const proposal = await governance.createProposal({
governancePk: governanceAccount.publicKey,
proposalOwnerRecord: ownerRecord.publicKey,
name: "Increase Treasury Allocation",
descriptionLink: "https://dao.example.com/proposals/1",
governingTokenMint: realm.communityMint,
});
Voting API
castVote(proposalPk, vote)
Parameters
Name | Type | Description |
---|---|---|
proposalPk |
PublicKey | The proposal account public key |
vote |
Vote | Vote.Yes, Vote.No, or Vote.Abstain |
voterTokenOwnerRecord |
PublicKey | Voter's token owner record |
Example
import { Vote } from '@solana/spl-governance';
// Cast a YES vote
await governance.castVote({
proposalPk: proposal.publicKey,
vote: Vote.Yes,
voterTokenOwnerRecord: voterRecord.publicKey,
payer: wallet.publicKey,
});
Treasury API
createTreasuryAccount(config)
Parameters
Name | Type | Description |
---|---|---|
governancePk |
PublicKey | The governance account that will control the treasury |
tokenMint |
PublicKey | The token mint for the treasury account |
Example
// Create SOL treasury
const solTreasury = await governance.createTreasuryAccount({
governancePk: governanceAccount.publicKey,
tokenMint: NATIVE_MINT, // SOL
});
// Create USDC treasury
const usdcTreasury = await governance.createTreasuryAccount({
governancePk: governanceAccount.publicKey,
tokenMint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
});
Creating a DAO
Step-by-step guide to creating your first DAO using SPL Governance.
Prepare Your Token Mint
Create or use an existing SPL token as your governance token:
import { createMint } from '@solana/spl-token';
// Create a new token mint for governance
const governanceTokenMint = await createMint(
connection,
payer,
mintAuthority.publicKey,
freezeAuthority.publicKey,
9 // decimals
);
Create the Realm
Establish your DAO's governance realm:
const realmConfig = {
name: "My First DAO",
communityMintPk: governanceTokenMint,
councilMintPk: null, // Optional: add council governance
communityMintMaxVoteWeightSource: {
type: 'SupplyFraction',
value: new BN(1000000), // 100% of token supply
},
};
const realm = await governance.createRealm(realmConfig);
Configure Governance Rules
Set up voting thresholds and timing:
const governanceConfig = {
voteThresholdPercentage: {
type: 'YesVote',
value: 60, // 60% yes votes required
},
minCommunityTokensToCreateProposal: new BN(1000000), // 1 token
minInstructionHoldUpTime: 0,
maxVotingTime: 3 * 24 * 60 * 60, // 3 days in seconds
};
Custom Plugins
Extend SPL Governance with custom voting mechanisms and proposal types.
Creating a Custom Voter Weight Plugin
import { VoterWeightPlugin } from '@solana/spl-governance';
// Custom plugin for quadratic voting
const quadraticVotingPlugin = new VoterWeightPlugin({
programId: QUADRATIC_VOTING_PROGRAM_ID,
config: {
// Plugin-specific configuration
votingPowerCurve: 'quadratic',
maxVoteWeight: 100,
}
});
// Register plugin with realm
await governance.setRealmConfig({
realmPk: realm.publicKey,
configArgs: {
voterWeightAddin: quadraticVotingPlugin.programId,
maxVoterWeightAddin: quadraticVotingPlugin.programId,
}
});
Treasury Management
Manage DAO treasuries and execute financial proposals.
Creating a Treasury Transfer Proposal
import { SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
// Create instruction to transfer SOL from treasury
const transferInstruction = SystemProgram.transfer({
fromPubkey: treasuryAccount.publicKey,
toPubkey: recipient.publicKey,
lamports: 5 * LAMPORTS_PER_SOL, // 5 SOL
});
// Create proposal with the transfer instruction
const proposal = await governance.createProposal({
governancePk: governanceAccount.publicKey,
proposalOwnerRecord: ownerRecord.publicKey,
name: "Treasury Transfer: 5 SOL for Development",
descriptionLink: "https://dao.example.com/proposals/treasury-1",
governingTokenMint: realm.communityMint,
instructions: [transferInstruction],
});
Basic DAO Setup
Complete example of setting up a basic DAO from scratch.
Complete DAO Setup
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
import { GovernanceSDK } from '@solana/spl-governance';
import { createMint, mintTo, createAssociatedTokenAccount } from '@solana/spl-token';
async function setupBasicDAO() {
// 1. Initialize connection and wallet
const connection = new Connection('https://api.devnet.solana.com');
const wallet = Keypair.generate();
const governance = new GovernanceSDK({ connection, wallet });
// 2. Create governance token
const tokenMint = await createMint(
connection,
wallet,
wallet.publicKey,
null,
9
);
// 3. Mint tokens to founder
const founderTokenAccount = await createAssociatedTokenAccount(
connection,
wallet,
tokenMint,
wallet.publicKey
);
await mintTo(
connection,
wallet,
tokenMint,
founderTokenAccount,
wallet.publicKey,
1000000 * 10**9 // 1M tokens
);
// 4. Create governance realm
const realm = await governance.createRealm({
name: "Basic DAO",
communityMintPk: tokenMint,
councilMintPk: null,
communityMintMaxVoteWeightSource: {
type: 'SupplyFraction',
value: new BN(1000000)
}
});
console.log('DAO created successfully!');
console.log('Realm:', realm.publicKey.toString());
return { realm, tokenMint, governance };
}
Voting Examples
Examples of different voting scenarios and implementations.
Token-Based Voting
// Vote with governance tokens
async function voteWithTokens(proposalPk: PublicKey) {
const vote = await governance.castVote({
proposalPk,
vote: Vote.Yes,
voterTokenOwnerRecord: voterRecord.publicKey,
payer: wallet.publicKey,
});
console.log('Vote cast:', vote.signature);
}
Delegated Voting
// Delegate voting power to another address
async function delegateVote(delegateTo: PublicKey) {
const delegation = await governance.setGovernanceDelegate({
governancePk: governanceAccount.publicKey,
newGovernanceDelegate: delegateTo,
voterTokenOwnerRecord: voterRecord.publicKey,
});
console.log('Vote delegated to:', delegateTo.toString());
}
NFT-Based Voting
Implement custom voting mechanisms using NFT collections as governance tokens.
Setting up NFT Governance
import { VoterWeightPlugin } from '@solana/spl-governance';
// Configure NFT-based voting
const nftVotingConfig = {
collection: new PublicKey("your-nft-collection-address"),
maxVoterWeight: 10000, // Max voting power
digitialAssetType: 'NFT',
};
// Create voter weight plugin
const voterWeightPlugin = new VoterWeightPlugin({
programId: NFT_VOTER_WEIGHT_PROGRAM_ID,
config: nftVotingConfig,
});
// Use in realm creation
const realm = await governance.createRealm({
name: "NFT DAO",
communityMintPk: communityMint,
voterWeightAddin: voterWeightPlugin.programId,
});
Integration Examples
React Component Example
import React, { useEffect, useState } from 'react';
import { useWallet } from '@solana/wallet-adapter-react';
import { GovernanceSDK } from '@solana/spl-governance';
export function ProposalList() {
const { connection, publicKey } = useWallet();
const [proposals, setProposals] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchProposals() {
if (!connection || !publicKey) return;
const governance = new GovernanceSDK({ connection, wallet: publicKey });
const realmProposals = await governance.getProposals(realmPk);
setProposals(realmProposals);
setLoading(false);
}
fetchProposals();
}, [connection, publicKey]);
if (loading) return Loading proposals...;
return (
{proposals.map(proposal => (
{proposal.account.name}
Status: {proposal.account.state}
))}
);
}
Next.js API Route
// pages/api/proposals.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { Connection } from '@solana/web3.js';
import { GovernanceSDK } from '@solana/spl-governance';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const connection = new Connection(process.env.SOLANA_RPC_URL!);
const governance = new GovernanceSDK({ connection });
try {
const proposals = await governance.getProposals();
res.status(200).json({ proposals });
} catch (error) {
res.status(500).json({ error: 'Failed to fetch proposals' });
}
}
Node.js Backend Integration
const express = require('express');
const { Connection } = require('@solana/web3.js');
const { GovernanceSDK } = require('@solana/spl-governance');
const app = express();
const connection = new Connection('https://api.mainnet-beta.solana.com');
app.get('/api/dao/:realm/proposals', async (req, res) => {
try {
const governance = new GovernanceSDK({ connection });
const proposals = await governance.getProposalsByRealm(req.params.realm);
res.json({
success: true,
data: proposals,
count: proposals.length
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
app.listen(3000, () => {
console.log('DAO API server running on port 3000');
});