Documentation
Complete reference for the OnChain DAO protocol — a fully autonomous, on-chain governance system deployed on BNB Smart Chain. This guide covers smart contracts, deployment, governance workflows, tokenomics, and staking.
Overview
OnChain DAO is a decentralized autonomous organization built on BNB Smart Chain (BSC). It features a two-token economic model and fully on-chain governance where every parameter change must pass through a proposal-vote-timelock lifecycle.
Key Properties
- Two-token system — DAOToken (governance) + TaxToken (revenue)
- Fully autonomous — deployer renounces all admin roles after setup
- On-chain governance — proposals, voting, and execution happen entirely on-chain via OpenZeppelin Governor
- Revenue sharing — TaxToken trading fees are split between stakers, burn, and development
- Anti-whale protection — configurable max transaction and max wallet limits on TaxToken
The protocol is composed of six smart contracts that interact to provide governance, trading with taxes, revenue distribution, and staking rewards.
Architecture
The system has two main flows: a governance flow (proposals controlling protocol parameters) and a revenue flow (trading taxes distributed to stakeholders).
DAOToken Holders
|
| delegate voting power
v
DAOGovernor ──propose──> Proposal
| |
| vote (For/Against/ | passes quorum
| Abstain) |
v v
Voting Period Queue in DAOTimelock
|
| 1 hour delay
v
Execute on-chain
(TaxToken / RevenueSplitter / StakingVault)TaxToken DEX Trade
|
| buy/sell tax (5% default)
v
RevenueSplitter
|
|── 50% ──> StakingVault.addRewards()
| (distributed to DAOToken stakers)
|
|── 20% ──> 0x000...dEaD (burned)
|
└── 30% ──> Dev WalletDAOTimelock (autonomous - no admin)
├── owns TaxToken → setBuyTax, setSellTax, setTradingEnabled, ...
├── owns RevenueSplitter → setShares, setDevWallet, ...
└── owns StakingVault → setMinLockPeriodSmart Contracts
All contracts are written in Solidity ^0.8.20 and built on OpenZeppelin v5. They are compiled with the Paris EVM target and optimizer enabled at 200 runs.
DAOToken
ERC20 governance token with ERC20Votes and ERC20Permit extensions. Holders must delegate voting power (to themselves or another address) before it counts toward proposals and quorum.
| Parameter | Value |
|---|---|
Name | DAOToken |
Symbol | DAO |
Initial Supply | 1,000,000 DAO |
Decimals | 18 |
Minting | Constructor only (fixed supply) |
Inherits | ERC20, ERC20Permit, ERC20Votes |
No admin functions exist on this contract. The entire supply is minted to the deployer at construction and can only change hands via standard ERC20 transfers. Vote checkpoints are automatically maintained on every transfer through the _update override.
DAOTimelock
Thin wrapper around OpenZeppelin's TimelockController. Enforces a mandatory delay between a proposal passing and its on-chain execution, giving the community time to react.
| Parameter | Value |
|---|---|
Min Delay | 3,600 seconds (1 hour) |
Proposer | DAOGovernor (set in setup) |
Executor | address(0) (anyone can execute) |
Canceller | DAOGovernor |
Admin | Renounced after setup |
After governance setup, the deployer's DEFAULT_ADMIN_ROLE is renounced, making the DAO fully autonomous. No single address can bypass the timelock.
DAOGovernor
Core governance contract using OpenZeppelin Governor with counting, quorum fraction, and timelock control extensions. Manages the full proposal lifecycle.
| Parameter | Value |
|---|---|
Voting Delay | 1 block |
Voting Period | 300 blocks (~15 min on BSC) |
Proposal Threshold | 0 (any holder can propose) |
Quorum | 4% of total supply |
Vote Types | 0 = Against, 1 = For, 2 = Abstain |
Proposals target functions on contracts owned by the DAOTimelock. When a proposal passes quorum, it is queued in the timelock and becomes executable after the 1-hour delay.
TaxToken
ERC20 token with configurable buy/sell taxes on DEX trades, anti-whale limits, and a trading toggle. After setup, all parameters are controlled by DAO governance.
| Parameter | Default | Range |
|---|---|---|
Buy Tax | 500 (5%) | 0 - 2,500 bps (25% max) |
Sell Tax | 500 (5%) | 0 - 2,500 bps (25% max) |
Max Transaction | 1% of supply | Configurable |
Max Wallet | 2% of supply | Configurable |
Trading | Disabled | Enabled via governance |
Tax Recipient | RevenueSplitter | Configurable |
Governance-Controlled Functions
| Function | Description |
|---|---|
setBuyTax(uint256) | Update buy tax (0-2500 bps) |
setSellTax(uint256) | Update sell tax (0-2500 bps) |
setTaxRecipient(address) | Change where taxes are sent |
setMaxTransactionAmount(uint256) | Update per-tx limit |
setMaxWalletAmount(uint256) | Update per-wallet limit |
setTradingEnabled(bool) | Enable/disable public trading |
setAmmPair(address, bool) | Register DEX pair addresses |
setTaxExempt(address, bool) | Grant/revoke tax exemption |
setLimitExempt(address, bool) | Grant/revoke limit exemption |
RevenueSplitter
Receives TaxToken proceeds from trades and distributes them across three streams. Thedistribute() function is permissionless — anyone can trigger it.
| Stream | Default Share | Destination |
|---|---|---|
Staking Rewards | 50% | StakingVault.addRewards() |
Burn | 20% | 0x000...dEaD |
Development | 30% | Dev wallet |
Governance-Controlled Functions
| Function | Description |
|---|---|
setShares(uint256, uint256, uint256) | Update staking/burn/dev split (sum <= 10000 bps) |
setDevWallet(address) | Change dev wallet address |
setStakingVault(address) | Change staking vault address |
StakingVault
Allows DAOToken holders to stake and earn TaxToken rewards. Uses the SynthetixrewardPerToken accumulator pattern for gas-efficient pro-rata distribution.
| Parameter | Value |
|---|---|
Staking Token | DAOToken |
Reward Token | TaxToken |
Min Lock Period | 7 days (default) |
Reward Model | Synthetix rewardPerToken accumulator |
| Function | Description |
|---|---|
stake(uint256) | Deposit DAOTokens into the vault |
withdraw(uint256) | Withdraw after lock period expires |
claimRewards() | Claim accrued TaxToken rewards |
addRewards(uint256) | Called by RevenueSplitter to fund rewards |
setMinLockPeriod(uint256) | Governance-controlled lock duration |
Deployment Guide
Prerequisites
- Node.js v18+ and npm
- A funded deployer wallet (BNB for gas)
- BscScan API key (for contract verification)
1. Install Dependencies
npm install2. Configure Environment
Copy the example env file and fill in your values:
PRIVATE_KEY=your_deployer_private_key
BSCSCAN_API_KEY=your_bscscan_api_key3. Compile Contracts
npx hardhat compile4. Deploy Contracts
The deploy script deploys all six contracts in dependency order and configures initial TaxToken exemptions.
npx hardhat run scripts/deploy.ts --network bscTestnetThe script outputs contract addresses as environment variables. Copy them into your.env file:
DAO_TOKEN_ADDRESS=0x...
DAO_TIMELOCK_ADDRESS=0x...
DAO_GOVERNOR_ADDRESS=0x...
TAX_TOKEN_ADDRESS=0x...
STAKING_VAULT_ADDRESS=0x...
REVENUE_SPLITTER_ADDRESS=0x...5. Setup Governance
This script grants timelock roles to the Governor, transfers contract ownership to the Timelock, and renounces the deployer's admin role. This is irreversible — after this step, all parameter changes require a governance proposal.
npx hardhat run scripts/setup-governance.ts --network bscTestnetWarning: The setup-governance script renounces the deployer's admin role. Ensure all initial configuration is correct before running this step.
6. Verify Contracts
npx hardhat verify --network bscTestnet <CONTRACT_ADDRESS> <CONSTRUCTOR_ARGS>Deployment Order Summary
| Step | Contract | Dependencies |
|---|---|---|
1 | DAOToken | None |
2 | DAOTimelock | None |
3 | DAOGovernor | DAOToken, DAOTimelock |
4 | TaxToken | None |
5 | StakingVault | DAOToken, TaxToken |
6 | RevenueSplitter | TaxToken, StakingVault |
Frontend Setup
The frontend is a Next.js 15 app with React 19, Tailwind CSS v4, wagmi v2 for wallet interactions, and Reown AppKit for the wallet connection modal.
1. Get a Reown Project ID
Sign up at cloud.reown.com and create a project to get your Project ID.
2. Configure Environment
NEXT_PUBLIC_REOWN_PROJECT_ID=your_project_id
NEXT_PUBLIC_DAO_TOKEN_ADDRESS=0x...
NEXT_PUBLIC_DAO_TIMELOCK_ADDRESS=0x...
NEXT_PUBLIC_DAO_GOVERNOR_ADDRESS=0x...
NEXT_PUBLIC_TAX_TOKEN_ADDRESS=0x...
NEXT_PUBLIC_REVENUE_SPLITTER_ADDRESS=0x...
NEXT_PUBLIC_STAKING_VAULT_ADDRESS=0x...3. Install and Run
cd frontend
npm install
npm run devThe dev server starts at http://localhost:3000. The app connects to BSC Testnet by default.
4. Production Build
npm run build
npm run startTech Stack
| Technology | Version | Purpose |
|---|---|---|
Next.js | 15 | React framework (App Router) |
React | 19 | UI library |
Tailwind CSS | 4 | Utility-first styling |
wagmi | 2 | React hooks for Ethereum |
viem | 2 | Low-level Ethereum client |
Reown AppKit | 1.6 | Wallet connection modal |
TanStack Query | 5 | Async data fetching/caching |
Governance Guide
Governance follows the standard OpenZeppelin Governor lifecycle. Any DAOToken holder with delegated voting power can participate.
Step 1: Delegate Voting Power
Before you can vote or propose, you must delegate your voting power. You can delegate to yourself or to another address. Go to the /delegate page in the app.
// Self-delegate to activate your own voting power
DAOToken.delegate(yourAddress)Step 2: Create a Proposal
Navigate to /proposals/create. A proposal specifies one or more on-chain actions (target contract, function call, and parameters) plus a description.
The proposal threshold is currently 0, so any token holder with delegated power can propose.
Step 3: Vote
After the 1-block voting delay, the proposal enters the Active state for 300 blocks (~15 minutes on BSC). Token holders can vote For, Against, or Abstain. Voting power is based on your delegated balance at the block the proposal was created.
Step 4: Queue
If the proposal passes (more For than Against votes, and at least 4% quorum), it moves to the Succeeded state. Anyone can then queue it in the DAOTimelock, which starts the 1-hour delay.
Step 5: Execute
After the timelock delay elapses, anyone can execute the proposal. The on-chain actions are carried out through the Timelock contract.
Proposal Lifecycle
| State | Description |
|---|---|
Pending | Created, waiting for voting delay |
Active | Voting is open |
Defeated | Did not reach quorum or more Against votes |
Succeeded | Passed, ready to queue |
Queued | In timelock, waiting for delay |
Executed | Actions performed on-chain |
Canceled | Canceled by the proposer or Governor |
Expired | Queued but not executed before grace period |
Tokenomics
The protocol uses a two-token model: DAOToken for governance and staking, and TaxToken for revenue generation through trading taxes.
DAOToken (DAO)
| Property | Value |
|---|---|
Type | ERC20 + Votes + Permit |
Total Supply | 1,000,000 DAO (fixed) |
Minting | Disabled (constructor-only mint) |
Use Cases | Governance voting, staking for rewards |
TaxToken (TAX)
| Property | Value |
|---|---|
Type | ERC20 + Ownable |
Total Supply | 1,000,000 TAX (fixed) |
Buy Tax | 5% (configurable, max 25%) |
Sell Tax | 5% (configurable, max 25%) |
Max Transaction | 1% of supply |
Max Wallet | 2% of supply |
Revenue Distribution
Taxes collected from TaxToken DEX trades are sent to the RevenueSplitter contract, which distributes them across three streams:
50%
Staking Rewards
20%
Burned (Deflationary)
30%
Development
All tax rates and revenue splits are governance-controlled. The DAO can vote to adjust these parameters at any time through proposals.
Staking
DAOToken holders can stake their tokens in the StakingVault to earn TaxToken rewards from trading fees. Rewards are distributed proportionally to each staker's share of the total staked pool.
How to Stake
- Navigate to the
/stakingpage - Enter the amount of DAOTokens to stake
- Approve the StakingVault to spend your DAOTokens (first time only)
- Confirm the stake transaction
Lock Period
Staked tokens are subject to a minimum lock period of 7 days (default). You cannot withdraw before this period expires. The lock resets each time you add more stake. The lock period is governance-controlled and can be adjusted via proposal.
Rewards
Rewards accumulate continuously as trading fees flow through the RevenueSplitter. The StakingVault uses a rewardPerToken accumulator (Synthetix pattern) to efficiently calculate each staker's pro-rata share without iterating over all stakers.
Claiming Rewards
- View your pending rewards on the
/stakingpage - Click "Claim Rewards" to receive your accrued TaxToken rewards
- Claiming does not affect your staked balance or lock period
Withdrawing
- After the lock period expires, enter the amount to withdraw
- Any unclaimed rewards are automatically claimed on withdrawal
- Partial withdrawals are supported
Staking Parameters
| Parameter | Value | Controlled By |
|---|---|---|
Staking Token | DAOToken | Immutable |
Reward Token | TaxToken | Immutable |
Min Lock Period | 7 days | Governance |
Reward Source | 50% of trading taxes | Governance (RevenueSplitter shares) |