Star 历史趋势
数据来源: GitHub API · 生成自 Stargazers.cn
README.md

Wadoozie DAO — Smart Contracts

Fully on-chain governance system for the Wadoozie ecosystem. Token holders vote on proposals that control the DAO treasury and can modify governance parameters. No single entity retains admin privileges after deployment.

Table of Contents


Contracts

ContractFilePurpose
Wadooziecontracts/Wadoozie.solERC-20 governance token with fixed supply, delegation, and gasless approvals
Headquarterscontracts/Headquarters.solOpenZeppelin Governor — proposal creation, voting, queueing, execution
WadoozieTreasurycontracts/WadoozieTreasury.solTimelockController wrapper — treasury, execution delay, role-based access
WadoozieFeeRoutercontracts/WadoozieFeeRouter.solUniswap V2 wrapper that skims 0.5% on every WADZ buy / sell and forwards it to the DAO treasury

WadoozieFeeRouter

Thin, non-upgradeable wrapper around the canonical Uniswap V2 Router. On every swap it takes feeBps (default 50 = 0.5%, hard-capped at 100 = 1%) from the input token, sends the fee to feeRecipient (the DAO treasury multisig in production), and routes the remainder through Uniswap with the user as the direct recipient. The router holds nothing between transactions.

Three swap shapes, mirroring the buy-wadz UI's spend-token picker:

FunctionPathFee taken inUse case
buyWadzWithETH(amountOutMin, deadline) payable[WETH, WADZ]ETH (msg.value)Native-ETH buys
buyWadzWithToken(token, amountIn, amountOutMin, deadline)[token, WETH, WADZ]the input ERC-20USDC / USDT / any other ERC-20 spend
sellWadzForETH(amountIn, amountOutMin, deadline)[WADZ, WETH]WADZSell back to ETH

The non-ETH paths require an approve(WadoozieFeeRouter, ≥ amountIn) on the input token before the call (V2-standard UX, identical to what Uniswap's own interface requires).

Admin surface (Ownable, owner = DAO multisig post-deploy):

FunctionPurpose
setFeeBps(uint16)Lower / raise the fee, capped at MAX_FEE_BPS = 100 (1%)
setRouter(address)Swap in a different V2-compatible router if the canonical one is ever deprecated
pause() / unpause()Emergency stop — all swap functions revert while paused
rescueTokens(token, to, amount)Recover any ERC-20 accidentally sent to the contract
rescueEth(to, amount)Same, for native ETH

feeRecipient is deliberately not in this table. It is set once in the constructor and stored in an immutable slot — there is no setter, and a compromised owner key cannot redirect the fee stream. If the recipient ever needs to change, deploy a new WadoozieFeeRouter and have the frontend repoint.

Safety invariants (all enforced at the contract level, not by convention):

  • WADZ, WETH, and feeRecipient are immutable and pinned at deploy — no admin action can repurpose the contract for a different token or redirect the fee stream.
  • Fee is hard-capped at 100 bps. A malicious / compromised owner cannot raise it above 1%.
  • ReentrancyGuard on every swap function.
  • whenNotPaused on every swap function.
  • Fees forward atomically — the router never holds user funds between calls.
  • WADZ-as-input and WETH-as-input rejected on buyWadzWithToken to prevent path tricks.

Token Specification

PropertyValue
NameWadoozie
SymbolWADZ
Total Supply2,000,000,000 (totalSupply() is fixed at this value forever)
Effective Supply1,000,000,001 (after the genesis dead-address burn)
Decimals18
StandardERC-20

Extensions:

ExtensionPurpose
ERC20VotesOn-chain voting power tracking with checkpoints and delegation
ERC20Permit (EIP-2612)Gasless token approvals via off-chain signatures

Genesis Distribution

The constructor takes six wallet addresses and distributes the supply atomically — there are no admin functions, so this is the only allocation event the contract will ever see.

AllocationAmount% of effectiveRecipient
Dead-address burn999,999,9990x000…dEaD (BURN_ADDRESS)
Liquidity Pool750,000,00175% (+ 1 token ceremony residue)LP_WALLET
Treasury100,000,00010%TREASURY (multisig)
Publisher Rewards70,000,0007%PUBLISHER_REWARDS (multisig)
Signal Fragments50,000,0005%SIGNAL_FRAGMENTS (multisig)
Team Vesting30,000,0003%TEAM_VESTING (timelock)

totalSupply() permanently equals 2,000,000,000: the burn is implemented as a transfer to 0x…dEaD, not an OpenZeppelin _burn, so supply does not decrease. The 999,999,999 burned tokens sit in 0x…dEaD forever (no key controls that address). All five allocation addresses are exposed as immutable public getters (LP_WALLET, TREASURY, PUBLISHER_REWARDS, SIGNAL_FRAGMENTS, TEAM_VESTING).

After the constructor finishes, the deployer holds zero tokens and has no role. There is nothing to renounce.

Immutability guarantees:

  • No mint function — supply is fixed at deployment
  • No burn function — tokens cannot be destroyed post-genesis
  • No pause function — transfers cannot be halted
  • No owner / Ownable — no admin key exists

Auto-Delegation (WAD-04)

To avoid governance stalling on un-delegated supply, Wadoozie auto self-delegates recipients the first time they receive tokens via a transfer — voting power activates on arrival without requiring a separate delegate() call. Because the genesis distribution flows through _transfer, all five allocation wallets are auto-self-delegated at deployment, with voting power equal to their allocation. The 0x…dEaD burn address is also self-delegated; its 999,999,999 voting power is permanently inert because no key controls the address. Any delegation a holder has already set — to self or someone else — is never overridden by a later transfer.


Governance Parameters

Production (ignition/modules/WadoozieDAO.ts)

ParameterValueDescription
Voting Delay7,200 blocks (~1 day)Time between proposal creation and vote start
Voting Period50,400 blocks (~1 week)Duration the voting window stays open
Proposal Threshold1,000 tokensMinimum delegated voting power to create a proposal
Quorum4% of total supply (40,000,000 tokens)Minimum participation for a vote to be valid
Timelock Delay86,400 seconds (1 day)Mandatory wait after a proposal is queued before execution

Testnet (ignition/modules/WadoozieDAO_Test.ts)

ParameterValueDescription
Voting Delay1 block (~12 seconds)Near-instant for testing
Voting Period75 blocks (~15 minutes)Short window for fast iteration
Proposal Threshold1,000 tokensSame as production
Quorum4%Same as production
Timelock Delay600 seconds (10 minutes)Shortened for testing

All governance parameters are modifiable through governance proposals via GovernorSettings (setVotingDelay, setVotingPeriod, setProposalThreshold, updateQuorumNumerator).


Proposal Guardian

Headquarters includes the GovernorProposalGuardian extension — an emergency address that can cancel any non-executed proposal.

PropertyDetail
Set atConstructor (_guardian parameter)
Can doCancel any proposal in Pending, Active, Succeeded, or Queued state
Cannot doCreate proposals, vote, execute, or change parameters
Change/removeOnly via governance proposal (setProposalGuardian)
Remove entirelyPass address(0) to setProposalGuardian

Deadlock risk: If the guardian is compromised, it can cancel the proposal attempting to replace it. Mitigation: always use a multisig wallet as guardian, never a single EOA.


Governance Lifecycle

Propose  ──>  Voting Delay  ──>  Active Voting  ──>  Succeeded  ──>  Queue  ──>  Timelock Delay  ──>  Execute
                                                         │
                                                     Defeated
                                                     (quorum not met or majority Against)
StepFunctionWho
1. Proposepropose(targets, values, calldatas, description)Any address with >= proposalThreshold delegated votes
2. VotecastVote(proposalId, support)Any address with delegated voting power (0=Against, 1=For, 2=Abstain)
3. Queuequeue(targets, values, calldatas, descriptionHash)Anyone, if proposal succeeded
4. Executeexecute(targets, values, calldatas, descriptionHash)Anyone, after timelock delay has passed
Cancelcancel(targets, values, calldatas, descriptionHash)Proposer (if Pending) or Proposal Guardian

Timelock Roles

After deployment and role configuration, the Timelock access control is:

RoleAssigned ToPurpose
PROPOSER_ROLEHeadquarters (Governor)Queue approved proposals
CANCELLER_ROLEHeadquarters (Governor)Cancel queued proposals
EXECUTOR_ROLEaddress(0) (anyone)Execute proposals after delay
DEFAULT_ADMIN_ROLERenounced (nobody)No human can grant or revoke roles

The Timelock holds all DAO funds and is the contract that executes on-chain actions.


Tech Stack

ComponentVersion
Solidity^0.8.28
OpenZeppelin Contracts5.6.1
Hardhat3.0
Ethers.js6.x
TypeScript5.x
Node.js>= 18

Requirements

  • Node.js >= 18
  • npm >= 9
  • A .env file based on .env.example:
DEPLOYER_PRIVATE_KEY=your_private_key_here
ETHEREUM_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY
ETHERSCAN_API_KEY=your_etherscan_api_key

Installation

git clone https://github.com/wadoozie/SmartContracts.git
cd SmartContracts
npm install

Compile

npm run compile

Artifacts are written to artifacts/ (gitignored).


Testing

npm test

79 tests across three suites:

SuiteFileCoverage
WadoozieTokentest/Wadoozie.test.tsDeployment, genesis distribution, constructor reverts, transfers, permit, votes, auto-delegation, immutability
Headquarterstest/Headquarters.test.tsConfiguration, proposal creation, voting, proposal guardian, proposal states
GovernanceLifecycletest/GovernanceLifecycle.test.tsFull propose-vote-queue-execute flow, timelock enforcement, cancellation, access control, ETH handling, self-modification

Deployment

Deployment Order

Contracts must be deployed in this order due to constructor dependencies:

1. Wadoozie Token
2. WadoozieTreasury
3. Headquarters (requires token + timelock addresses)
4. Grant PROPOSER_ROLE to Headquarters on Timelock
5. Grant CANCELLER_ROLE to Headquarters on Timelock
6. Renounce DEFAULT_ADMIN_ROLE on Timelock

The Ignition modules handle all six steps automatically.

Ethereum Mainnet

npm run deploy:mainnet

Deploys all three contracts with production parameters, grants roles, and renounces admin — fully automated via Hardhat Ignition.

Local Network

# Terminal 1 — start a local Hardhat node
npx hardhat node

# Terminal 2 — deploy with production parameters
npm run deploy:local

Sepolia Testnet

# Production parameters
npm run deploy:sepolia

# Fast test parameters
npm run deploy:sepolia:test

Available npm Scripts

ScriptDescription
npm run compileCompile all contracts
npm testRun the full test suite
npm run deploy:mainnetIgnition deploy to Ethereum mainnet
npm run deploy:localIgnition deploy to localhost (production params)
npm run deploy:local:testIgnition deploy to localhost (test params)
npm run deploy:sepoliaIgnition deploy to Sepolia (production params)
npm run deploy:sepolia:testIgnition deploy to Sepolia (test params)

Deployment Checklist

Before deploying to Ethereum mainnet:

  1. Run all tests and confirm 79/79 pass:

    npm test
  2. Configure .env with mainnet RPC URL, deployer private key, and Etherscan API key.

  3. Set the six wallet addresses for the genesis distribution. Each must be the final holder of its allocation — there is no admin to change them later. Use multisigs for everything except the LP wallet (which will pair with ETH on Uniswap immediately post-deploy).

    Constructor parameterAllocationRecommended type
    deployer_0 (drains during constructor)The signer running the deploy tx
    lpWallet_750,000,001 WADZEOA or multisig that will pair LP on Uniswap
    treasury_100,000,000 WADZDAO treasury multisig
    publisherRewards_70,000,000 WADZPublisher payouts multisig
    signalFragments_50,000,000 WADZSignal Fragments prize-pool multisig
    teamVesting_30,000,000 WADZTeam vesting timelock contract
  4. Deploy:

    npm run deploy:mainnet
  5. Verify contracts on Etherscan (see below).

  6. Confirm roles on Etherscan:

    • Timelock hasRole(PROPOSER_ROLE, governorAddress) returns true
    • Timelock hasRole(CANCELLER_ROLE, governorAddress) returns true
    • Timelock hasRole(DEFAULT_ADMIN_ROLE, deployerAddress) returns false
  7. Delegation — all five genesis allocation wallets are auto-self-delegated by the constructor (their voting power is live the moment the deploy tx confirms). No manual delegate() calls are required to activate quorum. Downstream recipients (anyone who later receives WADZ via transfer) are also auto-self-delegated on first receipt; see the Auto-Delegation (WAD-04) section for details.


Contract Verification

After deployment, verify source code on Etherscan:

# Token
npx hardhat verify --network mainnet <TOKEN_ADDRESS> \
  "<DEPLOYER_ADDRESS>" \
  "<LP_WALLET_ADDRESS>" \
  "<TREASURY_ADDRESS>" \
  "<PUBLISHER_REWARDS_ADDRESS>" \
  "<SIGNAL_FRAGMENTS_ADDRESS>" \
  "<TEAM_VESTING_ADDRESS>"

# Timelock
npx hardhat verify --network mainnet <TIMELOCK_ADDRESS> \
  86400 "[]" '["0x0000000000000000000000000000000000000000"]' "<DEPLOYER_ADDRESS>"

# Governor
npx hardhat verify --network mainnet <GOVERNOR_ADDRESS> \
  "<TOKEN_ADDRESS>" "<TIMELOCK_ADDRESS>" 7200 50400 "1000000000000000000000" 4 "<GUARDIAN_ADDRESS>"

Or use the convenience script (requires ETHERSCAN_API_KEY in environment):

export ETHERSCAN_API_KEY=your_key_here
bash scripts/verify-etherscan.sh

Security

Design Principles

  • Immutable token — no mint, burn, pause, or admin functions
  • No admin keysDEFAULT_ADMIN_ROLE is renounced after setup
  • Timelock protection — mandatory delay before any governance action executes
  • Proposal guardian — emergency cancellation via multisig
  • Battle-tested dependencies — built entirely on OpenZeppelin's audited contract library
  • No upgradeability — contracts cannot be changed after deployment

Inheritance

Wadoozie
├── ERC20
├── ERC20Permit
└── ERC20Votes

Headquarters
├── Governor
├── GovernorSettings
├── GovernorCountingSimple
├── GovernorVotes
├── GovernorVotesQuorumFraction
├── GovernorTimelockControl
└── GovernorProposalGuardian

WadoozieTreasury
└── TimelockController

Known Considerations

IssueMitigation
Guardian deadlock — compromised guardian cancels its own replacement proposalUse a multisig as guardian, never a single wallet
Voter apathy — quorum not reachedRecipients are auto self-delegated on first transfer (WAD-04 mitigation), so most circulating supply contributes to quorum without manual opt-in. Quorum is also intentionally low (4%) and adjustable via governance.
Flash loan attacks on votingERC20Votes uses checkpoints at proposal snapshot block, not current balance
Timelock bypassNot possible — GovernorTimelockControl enforces queueing for all proposals

License

MIT

关于 About

No description, website, or topics provided.

语言 Languages

Solidity77.2%
TypeScript12.3%
Python6.2%
JavaScript4.3%
Shell0.1%

提交活跃度 Commit Activity

代码提交热力图
过去 52 周的开发活跃度
17
Total Commits
峰值: 11次/周
Less
More

核心贡献者 Contributors