Skip to content

Latest commit

Β 

History

History
399 lines (318 loc) Β· 13.5 KB

File metadata and controls

399 lines (318 loc) Β· 13.5 KB

DAO Test Suite Documentation Guide

66 comprehensive tests covering complete DAO governance system with voting, community features, and deadline management

πŸ—οΈ System Architecture

Our DAO test suite validates a governance system where:

  • Deployer holds 400,000 DAPP tokens (40% - founding stake)
  • 3 investors each hold 200,000 DAPP tokens (20% each - equal voting power)
  • 1 recipient holds 0 tokens (demonstrates non-voting participant)
  • Quorum: 500,000+ tokens needed to finalize/cancel proposals (majority rule)
  • Voting: Support for For/Against/Abstain voting with net vote calculation

πŸ“Š Test Architecture

Core Setup

// Token distribution: 1M total supply
// Deployer: 400K tokens, Investors 1-3: 200K each, Recipient: 0 tokens

// Quorum = 50% + 1 token for democratic decisions = 500,000 tokens + 1 wei
dao = await DAO.deploy(token.address, '500000000000000000000001')

Complete Test Categories (66 Total)

Category Tests Purpose Learning Focus
πŸš€ Deployment 3 Basic setup validation Contract initialization, token distribution
πŸ“ Proposals 5 Creation & validation Proposal lifecycle, validation rules
πŸ—³οΈ Voting 5 Standard voting mechanics Democratic participation, vote counting
❌ Vote Against 3 Negative voting system Opposition mechanics, balanced governance
⏰ Deadline Features 12 Time-based constraints Temporal governance, deadline enforcement
πŸ‘₯ Community Features 12 User engagement tracking Participation metrics, community building
🚫 Cancellation 6 Proposal cancellation logic Governance flexibility, proposal lifecycle
βš–οΈ Governance 8 Finalization & treasury Decision execution, fund management
πŸͺ™ Token Suite 12 ERC-20 functionality Token mechanics, transfer validation
πŸ”’ Security 4 Access control & validation Permission systems, attack prevention

Total: 66 Tests covering every aspect of DAO governance from basic token operations to complex community engagement patterns.

πŸ—³οΈ Voting System Explained

  • Votes: Net result (For votes - Against votes)
  • Abstain votes: Don't affect net vote count but count toward participation
  • Quorum: Based on total token participation, not vote direction

Quorum Scenarios

βœ… Success: Deployer + 1 investor vote (600K tokens) - Reaching Quorum for Finalization

deployer.vote(proposalId, true)   // 400K tokens
investor1.vote(proposalId, true)  // 200K tokens
// Total: 600K > 500K quorum βœ“

❌ Failure: 2 investors vote (400K tokens) - Insufficient Votes

investor1.vote(proposalId, true)  // 200K tokens
investor2.vote(proposalId, true)  // 200K tokens
// Total: 400K < 500K quorum βœ—

🚫 Cancellation: 3 vote against (600K negative)

investor1.vote(proposalId, false) // -200K tokens
investor2.vote(proposalId, false) // -200K tokens
investor3.vote(proposalId, false) // -200K tokens
// Negative votes: 600K > 500K quorum β†’ CANCELLED

πŸ”§ Key Testing Structures & Patterns

Function Overloading Support

// Legacy vote (always in favor)
dao.connect(investor1)["vote(uint256)"](proposalId)

// Enhanced vote (specify direction)
dao.connect(investor1)["vote(uint256,bool)"](proposalId, false)

πŸ†” Proposal ID Management

Β Β Β Β Understanding Proposal IDs in Tests

Auto-Increment System

Β Β Β Β How Proposal IDs Are Assigned

uint256 public proposalCount; // Starts at 0

function createProposal(...) {
    proposalCount++; // Increment first (1, 2, 3...)
    proposals[proposalCount] = Proposal(...); // Store at that ID
}

Test Isolation and ID Management

Β Β Β Β Each test gets a fresh blockchain state, but within a single test:

describe('Governance', () => {
  beforeEach(async () => {
    // Creates Proposal 1 for this test suite
    transaction = await dao.connect(investor1).createProposal('Proposal 1', ...)
  })

  it('rejects finalization of cancelled proposal', async () => {
    // Need separate proposal to test cancellation scenario
    // Creates Proposal 2 (proposalCount becomes 2)
    transaction = await dao.connect(investor1).createProposal('Proposal 2', ...)

    // Work with proposalId=2 for this specific test
    await dao.connect(investor1).vote(2, false)
    await dao.connect(investor1).cancelProposal(2)
    await expect(dao.connect(investor1).finalizeProposal(2))
      .to.be.revertedWith('proposal was cancelled')
  })
})

Why We Use Different Proposal IDs

Scenario Proposal ID Purpose
Standard tests 1 Use proposal from beforeEach
Isolation needed 2 Create fresh proposal for specific test
Multiple proposals 1, 2, 3... Test interactions between proposals

Best Practice Pattern

// βœ… Good - Clear separation of concerns
it('specific test scenario', async () => {
  // Create dedicated proposal for this test
  await dao.createProposal('Test Proposal', ...)
  const newProposalId = await dao.proposalCount() // Get latest ID

  // Test specific scenario with clean state
  await dao.vote(newProposalId, false)
  await dao.cancelProposal(newProposalId)
})

// ❌ Avoid - Reusing proposals can cause test interdependence
it('test that modifies existing proposal', async () => {
  await dao.vote(1, true) // Modifies proposal from beforeEach
  // This could affect other tests
})

Key Takeaway

Using different proposal IDs (like proposalId=2) ensures test isolation and allows testing specific scenarios without interference from setup data. Each proposal ID represents a separate governance decision with its own voting history and state.

🎯 Critical Test Scenarios

Edge Cases Covered

  • Double voting prevention
  • Non-token holder restrictions
  • Insufficient fund rejections
  • State Transitions: Active β†’ Finalized, Active β†’ Cancelled
  • Cross-Feature Interactions: Cancelled proposals can't be finalized

State Verification

// Check multiple state changes in one test
const proposal = await dao.proposals(1)
expect(proposal.finalized).to.equal(true)
expect(proposal.cancelled).to.equal(false)

Error Handling

  • Specific error messages for all failure modes
  • Access control validation
  • Business logic enforcement
  • State consistency checks

Error Message Testing

// βœ… Specific error testing
await expect(dao.connect(user).vote(1, true))
  .to.be.revertedWith('must be token holder')

// ❌ Generic error testing
await expect(dao.connect(user).vote(1, true))
  .to.be.reverted

Event Emissions

await expect(transaction).to.emit(dao, "Vote")
  .withArgs(proposalId, voterAddress, inFavor)

πŸ“ˆ Analytics Integration

The test suite also supports our ProposalAnalytics component by ensuring:

  • Proposal state tracking (active/finalized/cancelled)
  • Vote counting (positive/negative/net)
  • Quorum success rates
  • Participation metrics

πŸš€ Running Tests

npx hardhat test
# Expected: 66 passing tests

πŸ’‘ Key Takeaways

  1. Comprehensive Coverage: tests validate all governance scenarios
  2. Enhanced Voting: Supports both legacy and directional voting
  3. Proposal Isolation: Each test uses appropriate proposal IDs
  4. Specific Testing: Error messages and state changes verified precisely
  5. Analytics Ready: Tests support real-time dashboard metrics

πŸ“‹ Detailed Test Breakdown

Deployment Tests (3 tests)

  • Verifies DAO receives initial ETH funding
  • Confirms token address is correctly set
  • Validates quorum value

Proposal Creation Tests (5 tests)

Success Cases:

  • Updates proposal count
  • Stores proposal data correctly
  • Emits Propose event

Failure Cases:

  • Rejects proposals exceeding treasury balance
  • Blocks non-token holders from creating proposals

Voting Tests (5 tests)

Success Cases:

  • Updates positiveVotes counter
  • Emits Vote event with correct parameters

Failure Cases:

  • Prevents non-token holders from voting
  • Blocks double voting attempts

Vote Against Tests (3 tests)

Success Cases:

  • Updates negativeVotes counter
  • Calculates net votes correctly (positive - negative)
  • Emits Vote event with false parameter

Proposal Cancellation Tests (6 tests)

Success Cases:

  • Marks proposal as cancelled when negative votes reach quorum
  • Emits Cancel event

Failure Cases:

  • Rejects cancellation with insufficient negative votes
  • Blocks non-token holders from cancelling
  • Prevents double cancellation

Governance Tests (8 tests)

Success Cases:

  • Transfers funds to recipient when finalized
  • Updates proposal status to finalized
  • Emits Finalize event

Failure Cases:

  • Blocks finalization without sufficient votes
  • Prevents non-token holders from finalizing
  • Blocks re-finalization of completed proposals
  • Prevents finalization of cancelled proposals

Token Tests (12 tests)

  • Complete ERC-20 functionality validation
  • Transfer, approval, and allowance mechanics
  • Error handling for invalid operations

πŸ†• Advanced Test Categories

⏰ Deadline Features (12 tests)

Learning Focus: Time-based governance constraints and deadline management

Key Concepts:

  • Proposal Deadlines: Time limits for voting periods
  • Deadline Enforcement: Automatic proposal closure after deadline
  • Time-based Validation: Preventing votes after deadline expiration
  • Deadline Extension: Governance flexibility for critical proposals

Test Scenarios:

// Create proposal with deadline
await dao.createProposal("Urgent Security Update", "Fix critical vulnerability", recipient.address, tokens(100), deadline)

// Test deadline enforcement
await network.provider.send("evm_increaseTime", [86400]) // Advance 1 day
await expect(dao.vote(proposalId, true)).to.be.revertedWith("Voting period has ended")

Success Cases:

  • Creates proposals with valid deadlines
  • Allows voting before deadline
  • Enforces deadline restrictions
  • Handles deadline edge cases

Failure Cases:

  • Blocks voting after deadline
  • Prevents invalid deadline creation
  • Handles time manipulation attacks

πŸ‘₯ Community Features (12 tests)

Learning Focus: User engagement tracking and community building

Key Concepts:

  • Participation Tracking: Monitor user voting activity
  • Community Metrics: Calculate engagement statistics
  • Achievement Systems: Reward active participants
  • Social Governance: Encourage community involvement

Test Scenarios:

// Track user participation
const participation = await dao.getUserParticipation(user.address)
expect(participation.proposalsVoted).to.equal(3)
expect(participation.participationRate).to.equal(75) // 3 out of 4 proposals

// Community leaderboard
const topVoters = await dao.getTopParticipants(5)
expect(topVoters[0].votes).to.be.gte(topVoters[1].votes)

Success Cases:

  • Tracks individual user participation
  • Calculates community-wide statistics
  • Maintains participation leaderboards
  • Rewards consistent participation

Failure Cases:

  • Handles users with no participation
  • Prevents manipulation of participation metrics
  • Validates participation calculations

πŸ”’ Security Tests (4 tests)

Learning Focus: Access control and attack prevention

Key Concepts:

  • Permission Systems: Role-based access control
  • Economic Security: Token-based security models

Test Scenarios:

// Access control validation
await expect(dao.connect(nonTokenHolder).vote(proposalId, true))
  .to.be.revertedWith("Insufficient token balance")

// Reentrancy protection
await expect(maliciousContract.attemptReentrancy())
  .to.be.revertedWith("ReentrancyGuard: reentrant call")

Success Cases:

  • Enforces token-based permissions
  • Prevents unauthorized access
  • Validates all user inputs
  • Protects against common attacks

Failure Cases:

  • Blocks non-token holder actions
  • Prevents reentrancy attacks
  • Handles malformed inputs
  • Protects treasury funds

πŸŽ“ Educational Value

For Blockchain Students:

  1. Smart Contract Architecture: Learn how complex governance systems are structured
  2. Testing Patterns: Understand comprehensive test coverage strategies
  3. Economic Incentives: See how tokens create aligned incentives
  4. Community Governance: Experience democratic decision-making at scale

For Developers:

  1. Best Practices: Production-ready smart contract patterns
  2. Security Considerations: Real-world attack vectors and defenses
  3. Gas Optimization: Efficient contract design principles
  4. User Experience: Building intuitive governance interfaces

For Governance Enthusiasts:

  1. Democratic Processes: Digital democracy implementation
  2. Participation Incentives: Encouraging community engagement
  3. Decision Frameworks: Structured proposal and voting systems
  4. Transparency: Open and auditable governance processes

πŸš€ Getting Started with Tests

Running the Complete Suite:

# Run all 66 tests
npx hardhat test

# Run specific categories
npx hardhat test test/DAO.js                    # Core governance (42 tests)
npx hardhat test test/DeadlineFeatures.js       # Deadline management (12 tests)
npx hardhat test test/CommunityFeatures.js      # Community engagement (12 tests)

This comprehensive test suite serves to provide examples for specific concepts while contributing to a robust, production-ready DAO system