A DAO delegation dashboard is a critical interface for governance participants. It allows token holders to delegate their voting power to trusted representatives and enables delegates to track their accumulated influence. Unlike a simple wallet, a dashboard aggregates data from on-chain delegation contracts, such as OpenZeppelin's Governor or Compound's GovernorBravo, to present a clear view of voting weight distribution. This tool is essential for informed participation, as it surfaces which addresses hold significant voting power and tracks delegation changes over time.
Setting Up a DAO Delegation Dashboard for Voting Power
Setting Up a DAO Delegation Dashboard for Voting Power
A step-by-step guide to building a dashboard for tracking and managing delegated voting power in decentralized autonomous organizations.
The core technical component is interacting with the DAO's delegation smart contract. Most governance systems use a token with built-in delegation, like an ERC-20Votes or ERC-721Votes token. Your dashboard must call the delegates(address) function to find a voter's current delegate and the getVotes(address, blockNumber) function to check voting power at a past block. For live data, you'll listen for DelegateChanged and DelegateVotesChanged events. A basic setup involves using a library like ethers.js or viem to connect to the blockchain and a provider like Alchemy or Infura.
Here is a simplified code snippet to fetch delegation data for an address using ethers.js and a typical ERC-20Votes contract ABI:
javascriptimport { ethers } from 'ethers'; const provider = new ethers.providers.JsonRpcProvider(RPC_URL); const contractAddress = '0x...'; // DAO Governance Token Address const abi = ["function delegates(address) view returns (address)", "function getVotes(address) view returns (uint256)"]; const contract = new ethers.Contract(contractAddress, abi, provider); async function getDelegationInfo(voterAddress) { const delegate = await contract.delegates(voterAddress); const votingPower = await contract.getVotes(voterAddress); return { delegate, votingPower: ethers.utils.formatUnits(votingPower, 18) }; }
To build a functional dashboard, you need to index and display historical data. Querying getVotes for every past proposal is inefficient. Instead, use a subgraph on The Graph protocol. Many major DAOs like Uniswap and Aave have published subgraphs that index all delegation events and voting power snapshots. Your frontend can query this indexed data with GraphQL for fast, complex queries—like "show all delegates with >1% voting power" or "plot delegation changes over the last 30 days." This decouples your UI from slow direct blockchain calls.
The final dashboard should visualize key metrics: a list of top delegates by voting power, a history of delegation transactions, and the current delegation state for the connected wallet. Integrate wallet connection via WalletConnect or MetaMask to allow users to delegate directly from the interface by calling the contract's delegate(address) function. Always include links to the official DAO governance portal, such as Tally or Snapshot, for context. Security is paramount: clearly distinguish between read-only data displays and transaction prompts.
Maintaining your dashboard requires monitoring for contract upgrades and governance migrations. DAOs like Optimism and Arbitrum have undergone governance system upgrades that changed token contracts. Subscribe to the DAO's governance forums and announcements. Your tool's value increases with additional features: simulating proposal outcomes, tracking delegate voting history, or sending notifications for new proposals. By providing transparency into the often-opaque flow of governance power, a well-built delegation dashboard strengthens the entire DAO's decision-making process.
Prerequisites and Setup
Before building a DAO delegation dashboard, you must configure your development environment and understand the core data you'll need to query.
A DAO delegation dashboard visualizes voting power distribution by querying on-chain data. The primary prerequisites are a working Node.js environment (v18+ recommended) and a basic understanding of Ethereum smart contracts. You will need to install essential packages: an Ethereum provider library like ethers.js (v6) or viem for interacting with the blockchain, a framework like Next.js or Vite for the frontend, and a charting library such as Recharts or D3.js for data visualization. Setting up a .env file to securely store your RPC provider URL (e.g., from Alchemy or Infura) is a critical first step.
The core technical requirement is identifying the DAO's governance contract addresses. For a token-based DAO like Uniswap or Compound, you need the address of the governance token (e.g., UNI or COMP) and the main governor contract (e.g., GovernorBravoDelegate). You will use these addresses to query two key data points: token balances and delegation events. The balanceOf function shows a user's raw token holdings, while the getVotes function returns the voting power delegated to an address at a specific block number, which is essential for historical snapshots.
To track delegation flows, you must listen to the DelegateChanged and DelegateVotesChanged events emitted by the token contract. These events log when a user changes their delegate and when the voting power of a delegate updates. Your backend service or subgraph will need to index these events to build a relational map of delegators, delegates, and the amount of power delegated. For performance, consider using The Graph to create a subgraph that indexes this data, as querying events directly for a large DAO can be slow and costly.
You will also need access to a blockchain archive node or a service that provides historical state. Calculating a user's voting power for a past proposal requires querying the getVotes function at the specific block number when the proposal was created. Standard RPC endpoints often lack historical state access, so a provider with archive data is necessary. Alternatively, you can use the subgraph approach, which stores this historical data in a queryable format, simplifying your frontend logic significantly.
Finally, structure your project to separate concerns: a data-fetching layer (using ethers/viem or GraphQL), a state management layer (using React context, Zustand, or similar), and the visualization layer. Start by building a function to fetch the top delegates by voting power for the current block, then expand to historical lookups. This modular setup makes it easier to add features like searching for a specific address or filtering by time period once the foundational data pipeline is working.
Key Concepts: Delegation and Voting Power
A practical guide to building a dashboard that visualizes delegation and voting power for on-chain governance.
In token-based DAOs, delegation is the mechanism by which token holders transfer their voting power to another address, called a delegate. This is critical for scalable governance, as it allows less active members to participate by proxy. A delegation dashboard aggregates this on-chain data to show who holds voting power, how it's distributed, and the delegation graph. For example, in Compound's Governor Bravo system, the delegate function on the token contract (like COMP) is called to assign votes. Building a dashboard requires querying these delegation events and calculating the resulting vote weight.
The core technical challenge is calculating voting power at a specific block number. A user's voting power is not simply their token balance; it is the sum of tokens delegated to them, minus any tokens they have delegated away. This must be computed from historical events. For an ERC-20Votes token (OpenZeppelin's standard used by Uniswap and others), you would track DelegateChanged and DelegateVotesChanged events. The formula is: votingPower = getPastVotes(delegateAddress, blockNumber). A dashboard must index these events to reconstruct the state for any past proposal or the current moment.
To build a basic dashboard, start by setting up an indexer. You can use The Graph with a subgraph that indexes your governance token. The subgraph schema would include Delegate and Voter entities to map relationships. Alternatively, for a simpler approach, use Ethers.js to query events directly from a node provider. You'll need to fetch all DelegateChanged events to build the delegation map and DelegateVotesChanged events to track historical balances. Store this data in a local database (like PostgreSQL) to enable efficient queries for the frontend.
The frontend visualization should answer key questions: Who are the top delegates? How concentrated is the voting power? What is the delegation path for a given voter? Use libraries like D3.js or vis-network to create a force-directed graph showing delegates and their delegators. Display tables with sortable columns for address, voting power, and delegation count. For live data, subscribe to new events via WebSocket. Always display the block number used for calculations, as voting power is time-dependent. This transparency is crucial for user trust.
Consider advanced features like delegate profiles, where users can see a delegate's voting history (using Tally or Boardroom APIs) and delegation statements. Implement vote delegation strategies, such as liquid delegation (where tokens can be delegated to different addresses for different proposals) or delegation pools. Security is paramount: your dashboard should verify all on-chain data and warn users about common risks, like delegating to a malicious or inactive address. Finally, make the dashboard composable by providing a public API, allowing other developers to build on your delegation data.
Essential Resources and Tools
These tools and protocols are commonly used to build a DAO delegation dashboard that tracks voting power, delegates, and proposal outcomes across governance systems like Snapshot and onchain governors.
Common Delegation Functions and Patterns
Comparison of delegation function signatures and governance patterns used by major DAO frameworks.
| Function / Pattern | OpenZeppelin Governor | Compound Governor Bravo | Aave Governance v2 |
|---|---|---|---|
Delegate by Signature | |||
Delegate by Transaction | |||
Delegation with Expiry | |||
Gasless Delegation Support | Via EIP-712 | Not Native | Via EIP-712 |
Delegation to Self | |||
Batch Delegation | |||
Voting Power Lookup | getVotes(address) | getCurrentVotes(address) | getPowerCurrent(address, uint256) |
Delegation Event Emitted | DelegateChanged | DelegateChanged | DelegateChanged |
Step 1: Fetching Delegation State
Before building any dashboard, you need reliable on-chain data. This step covers how to query the current delegation state for a DAO's governance token.
The delegation state is the foundational dataset for any voting power dashboard. It answers the core question: who holds voting power and who delegated it? For a token like Uniswap's UNI or Compound's COMP, this involves querying the token's delegation contract to retrieve a list of all delegators (token holders) and their chosen delegates. This data is not typically indexed by standard block explorers, requiring direct interaction with the smart contract or a specialized indexer.
You can fetch this data directly using the token contract's ABI. The key function is often delegates(address delegator), which returns the delegate address for a given token holder. To get a complete snapshot, you must iterate over token holders. A more efficient method is to query The Graph, a decentralized indexing protocol. Subgraphs for major DAOs like Uniswap index delegation events, allowing you to fetch all delegations with a single GraphQL query.
Here is a practical example using ethers.js to call a contract directly:
javascriptconst delegatorAddress = '0x123...'; const tokenContract = new ethers.Contract(tokenAddress, tokenABI, provider); const delegateAddress = await tokenContract.delegates(delegatorAddress); console.log(`Delegator ${delegatorAddress} has delegated to ${delegateAddress}`);
For a full snapshot, listening to the DelegateChanged event log is necessary, as it fires whenever a user updates their delegate.
When using The Graph, your query will target the subgraph's Delegation entity. A typical query to get all current delegations for a token might look like this GraphQL snippet, which returns the delegator, delegate, and the block number of the last update. This method is scalable and avoids the complexity of processing raw event logs.
The output of this step is a structured dataset, often a JSON array or database table, mapping every token holder to their delegate. Critical edge cases to handle include: addresses that delegate to themselves (self-delegation), zero-address delegations (undelegated votes), and delegations that have been changed multiple times, where only the most recent record is valid. This clean dataset becomes the source of truth for all subsequent calculations and visualizations in your dashboard.
Displaying Delegate Profiles and Metrics
This step focuses on fetching and visualizing delegate data to create an informative dashboard for voters.
The core of a delegation dashboard is presenting clear, actionable data about potential delegates. You'll need to query and display key metrics for each delegate profile. Essential data points include their voting power, proposal participation rate, delegation history, and a voting alignment score with the user. This information helps voters assess a delegate's activity, reliability, and philosophical alignment with their own views on governance. For platforms like Compound or Uniswap, this data is often sourced from their subgraphs or governance smart contracts.
To fetch this data, you'll interact with on-chain sources and indexing services. A common approach is to query a Graph Protocol subgraph using GraphQL. For example, to get a list of delegates for a specific DAO, you might run a query to fetch their address, voting weight, and number of votes cast. You can also call view functions on the governance contract directly using a library like ethers.js or viem to get real-time voting power. Always cache this data client-side to improve performance and reduce RPC calls.
Once you have the raw data, the next step is designing the UI components to display it effectively. Create a reusable DelegateCard component that renders each delegate's ENS name or truncated address, a progress bar for voting power, and key stats like "Voted on 45 of last 50 proposals." Consider adding filters and sort options, allowing users to organize delegates by highest voting power, most active, or best alignment. Visual clarity is critical for helping users make informed delegation decisions quickly.
For a more advanced feature, implement a delegate comparison tool. This allows a user to select two delegates and see a side-by-side breakdown of their voting history on specific proposals. You can calculate an agreement score by comparing their votes (FOR, AGAINST, ABSTAIN) across a historical window. Displaying this data in a table or chart provides deep insight into a delegate's decision-making patterns, which is more valuable than raw metrics alone.
Finally, ensure your dashboard stays updated. Implement real-time listeners for delegate change events (like DelegateChanged or DelegateVotesChanged) from the governance contract. When a user delegates their tokens or a delegate votes, your UI should reflect these changes without requiring a page refresh. Combine this with periodic refetching of subgraph data to maintain an accurate, live view of the delegation landscape, building trust and utility for your users.
Step 3: Handling the Delegation Transaction
This step covers the technical process of constructing, signing, and broadcasting a delegation transaction to the blockchain using your dashboard.
With the delegate's address selected and the delegation amount confirmed, the next step is to construct the transaction. This involves creating a transaction object that calls the delegate function on the governance token's smart contract. The key parameters are the delegatee (the recipient address) and the amount (in the token's smallest unit, e.g., wei). Your dashboard's backend should use a library like ethers.js or web3.js to encode this function call into transaction data. It's critical to fetch the current network gas prices at this stage to estimate a reasonable maxFeePerGas and maxPriorityFeePerGas for EIP-1559 transactions.
Before signing, the user must be presented with a clear transaction preview. This should display the delegatee's ENS name or truncated address, the exact token amount in a human-readable format, the estimated gas cost in ETH, and the resulting change to their voting power. Security best practices require you to never ask for or handle the user's private key. Instead, trigger a signature request through the user's connected wallet (e.g., MetaMask, WalletConnect). The wallet will present the transaction details for the user to sign cryptographically, proving they authorize this action.
Once signed, the raw transaction is broadcast to the network. Your dashboard should monitor its status by subscribing to transaction receipts via a provider like Alchemy or Infura. Implement feedback for the user: a pending state, a link to a block explorer (e.g., Etherscan), and confirmation upon a specified number of block confirmations (typically 1-5 for Ethereum). Important: The delegation does not take effect until the transaction is finalized on-chain. Only then should the UI update to reflect the user's new delegated voting power and the delegatee's increased total.
UX Patterns for Delegation Interfaces
A comparison of common user interface patterns for delegating voting power in DAOs, focusing on user comprehension and transaction clarity.
| UX Pattern | Simple Slider | Advanced Delegate Search | Gasless Signature (EIP-712) | Batch Delegation |
|---|---|---|---|---|
Primary User Intent | Quick delegation to a known delegate | Discover and vet new delegates | Zero-cost intent signaling | Delegate to multiple tokens at once |
Best For Token Count | 1-3 tokens | Any amount | Any amount | 5+ tokens |
Avg. Time to Delegate | < 30 sec | 2-5 min | < 15 sec | 1-2 min |
Shows Delegate Metrics | ||||
Requires Wallet TX | ||||
Supports Partial Delegation | ||||
Common Gas Cost Estimate | $3-8 | $3-8 | $0 | $10-25 |
Implementation Complexity | Low | High | Medium | Medium |
Step 4: State Management and Data Refresh
This section details how to implement dynamic state management and periodic data fetching to keep your delegation dashboard current with on-chain activity.
Effective state management is critical for a real-time dashboard. You need to track user wallet connections, current delegate selections, and, most importantly, live voting power data. Use React's useState and useEffect hooks or a state management library like Zustand or Redux Toolkit to create a centralized store. This store should hold key data structures: the user's connected address, a list of available delegates with their addresses and metadata, and the user's current and historical voting power. Initializing this state after a wallet connection is the first step to a functional UI.
To display meaningful data, you must fetch and calculate voting power. This typically involves querying the DAO's governance token contract (e.g., an ERC-20Votes token) and its associated snapshot/block number. Use the balanceOf and getPastVotes methods. For example, to get voting power at a past block: const votingPower = await contract.getPastVotes(address, blockNumber);. You'll need to determine the correct block number, often from the latest proposal snapshot. Libraries like ethers.js or viem are essential for these contract calls. Cache this data locally to minimize RPC calls and improve performance.
A static snapshot isn't enough; voting power changes with token transfers and delegations. Implement a data refresh strategy using setInterval within a useEffect hook or a more sophisticated polling library. Consider fetching updates every 10-15 seconds for high-frequency dashboards, or trigger refreshes on specific user actions like connecting a wallet or submitting a delegation transaction. Always pair this with loading states and error handling to manage RPC latency and failures gracefully. This ensures the user interface reflects the true, current state of their governance influence.
For complex DAOs with sub-governance or vesting schedules, voting power calculation extends beyond simple token balance. You may need to aggregate data from multiple sources: - Token vesting contracts (e.g., Merkle distributors) - Staking/Locking contracts (e.g., ve-token models) - Cross-chain governance bridges. Architect your data-fetching logic to asynchronously call these various sources, combine the results, and present a unified total. Using Promise.all for parallel fetching can significantly reduce load times. Document the sources clearly in your UI to build user trust in the displayed figures.
Finally, structure your application state to handle the delegation transaction lifecycle. When a user initiates a delegation via a contract call (e.g., contract.delegate(delegateAddress)), your state should reflect a pending transaction, disable relevant UI elements, and then poll for transaction confirmation. Upon success, immediately trigger a refresh of the user's voting power and delegate list to confirm the change on-chain. This creates a seamless, responsive user experience where the dashboard's state is always synchronized with the blockchain, making it a reliable tool for active governance participants.
Frequently Asked Questions
Common technical questions and solutions for developers building or integrating delegation dashboards to track and manage voting power across DAOs.
To calculate a user's aggregate voting power, you must query the balance and delegation state from each relevant token contract. For ERC-20Votes or ERC-721Votes tokens, call the getVotes(address account) function for the current block number. For snapshot-based systems like Compound or Uniswap, you need to fetch the user's delegated balance at a specific past block. A robust implementation involves:
- Aggregating on-chain calls: Use a multicall contract (e.g., MakerDAO's Multicall3) to batch
getVotesqueries for efficiency. - Handling snapshots: For historical power, query
getPriorVotes(address account, uint256 blockNumber). - Including staked/locked tokens: Check balances in staking contracts (e.g., veCRV, veBAL) which often represent voting power directly.
Always verify the token's governance module adheres to a standard interface for reliable integration.
Conclusion and Next Steps
You have successfully built a functional DAO delegation dashboard. This section summarizes the key components and provides resources for extending your application.
Your dashboard now connects to a user's wallet, fetches their governance token balance and delegation status, and displays a clear interface for managing votes. The core flow involves using the useAccount and useBalance hooks from Wagmi to read on-chain data, and the useContractWrite hook to send delegation transactions. Remember that the user experience is paramount; clear feedback for pending transactions and success/failure states is critical for a production-ready tool.
To enhance your dashboard, consider implementing several advanced features. Add support for multiple DAOs and governance contracts (like Compound Governor Bravo or OpenZeppelin's Governor) by creating a configurable provider. Integrate real-time proposal data from subgraphs (e.g., The Graph) or indexers to show active votes. Implement delegation history tracking to visualize past delegation changes. For security, add transaction simulation using tools like Tenderly or the eth_call RPC method before broadcasting to prevent failed transactions.
The next logical step is to deploy your dashboard. You can host the static files on services like Vercel, Netlify, or IPFS (via Fleek or Pinata). Ensure your next.config.js is properly configured for CORS and environment variables. For mainnet readiness, conduct thorough testing on a testnet like Sepolia or Goerli, and consider adding analytics to track usage patterns. The complete code for this guide is available in the Chainscore Labs GitHub repository. Continue exploring by reading the Wagmi documentation and EIP-712 for typed structured data signing in future voting features.