Skip to content

Latest commit

 

History

History
221 lines (172 loc) · 6.5 KB

File metadata and controls

221 lines (172 loc) · 6.5 KB

Crowdsale Implementation Guide

This project contains two crowdsale implementations with advanced features for managing token sales.

Contracts Overview

1. TimedCrowdsale (Basic Implementation)

Location: packages/contracts/src/TimedCrowdsale.sol

A fully-featured crowdsale contract with the following capabilities:

Features:

  • Dynamic Pricing: Owner can update token price during the crowdsale
  • Whitelist System: Only whitelisted addresses can purchase tokens
  • Timed Sales: Opening and closing times control when purchases are allowed
  • Contribution Limits: Minimum and maximum token purchase amounts per transaction
  • Direct ETH Purchases: Users can send ETH directly to the contract
  • Owner Controls: Finalize sale and withdraw funds

Key Functions:

  • whitelistAddress(address) - Add address to whitelist (owner only)
  • setPrice(uint256) - Update token price (owner only)
  • buyTokens(uint256) - Purchase tokens with ETH
  • isOpen() - Check if crowdsale is currently active
  • finalize() - End sale and transfer remaining tokens + ETH to owner

2. RefundableCrowdsale (OpenZeppelin-based Implementation)

Location: packages/contracts/src/RefundableCrowdsale.sol

An advanced crowdsale using OpenZeppelin libraries with goal-based refund mechanism.

Features:

All features from TimedCrowdsale, plus:

  • Funding Goal: Minimum ETH goal that must be reached
  • Refund Mechanism: Investors can claim refunds if goal not reached
  • Goal Tracking: Real-time goal progress monitoring
  • Batch Whitelisting: Add multiple addresses at once
  • OpenZeppelin Integration: Uses battle-tested ERC20 and security patterns
  • Reentrancy Protection: Enhanced security with ReentrancyGuard
  • Ownable Pattern: Secure ownership management

Key Functions:

  • addToWhitelist(address) - Add single address to whitelist
  • addToWhitelistBatch(address[]) - Add multiple addresses to whitelist
  • removeFromWhitelist(address) - Remove address from whitelist
  • setPrice(uint256) - Update token price
  • buyTokens(uint256) - Purchase tokens with ETH
  • finalize() - End sale (transfers funds if goal reached, enables refunds if not)
  • claimRefund() - Claim refund if goal not reached
  • goalReachedStatus() - Check if funding goal was reached

Scripts

Deployment Scripts

  1. Deploy TimedCrowdsale

    forge script script/DeployCrowdsale.s.sol:DeployCrowdsaleScript --rpc-url <RPC_URL> --broadcast
  2. Deploy RefundableCrowdsale

    forge script script/DeployRefundableCrowdsale.s.sol:DeployRefundableCrowdsaleScript --rpc-url <RPC_URL> --broadcast

Management Scripts

  1. Manage Whitelist

    CROWDSALE_ADDRESS=<ADDRESS> forge script script/ManageWhitelist.s.sol:ManageWhitelistScript --rpc-url <RPC_URL> --broadcast
  2. Update Price

    CROWDSALE_ADDRESS=<ADDRESS> NEW_PRICE=<PRICE_IN_WEI> forge script script/UpdatePrice.s.sol:UpdatePriceScript --rpc-url <RPC_URL> --broadcast

Testing

All features are thoroughly tested with 35 comprehensive test cases.

Run all tests:

forge test

Run specific test suite:

forge test --match-path test/TimedCrowdsale.t.sol -vv
forge test --match-path test/RefundableCrowdsale.t.sol -vv

Test Coverage

TimedCrowdsale Tests (14 tests):

  • Deployment validation
  • Whitelist management
  • Purchase validations (timing, whitelist, min/max)
  • Price updates
  • Finalization
  • Direct ETH purchases

RefundableCrowdsale Tests (21 tests):

  • All TimedCrowdsale tests
  • Batch whitelist operations
  • Goal tracking
  • Finalization with/without goal reached
  • Refund mechanism
  • Multiple users refund scenarios

Usage Examples

Deploying a Crowdsale

// Deploy token
Token token = new Token("MyToken", "MTK", 1000000);

// Deploy crowdsale
uint256 openingTime = block.timestamp + 1 hours;
uint256 closingTime = block.timestamp + 30 days;

TimedCrowdsale crowdsale = new TimedCrowdsale(
    token,
    0.001 ether,        // price per token
    500000 * 10**18,    // max tokens for sale
    openingTime,
    closingTime,
    1,                  // min contribution (1 token)
    10000               // max contribution (10,000 tokens)
);

// Transfer tokens to crowdsale
token.transfer(address(crowdsale), 500000 * 10**18);

Managing Whitelist

// Add single address
crowdsale.whitelistAddress(investorAddress);

// Add multiple addresses (RefundableCrowdsale only)
address[] memory investors = new address[](3);
investors[0] = address1;
investors[1] = address2;
investors[2] = address3;
crowdsale.addToWhitelistBatch(investors);

Purchasing Tokens

// Method 1: Direct ETH send
(bool success,) = address(crowdsale).call{value: 1 ether}("");

// Method 2: Call buyTokens function
uint256 tokenAmount = 1000 * 10**18;
uint256 cost = (tokenAmount / 10**18) * price;
crowdsale.buyTokens{value: cost}(tokenAmount);

Finalizing Sale

// After closing time
crowdsale.finalize();

// For RefundableCrowdsale, if goal not reached:
crowdsale.claimRefund(); // Investors call this

Security Features

Both implementations include:

  • ✅ Owner-only administrative functions
  • ✅ Reentrancy protection (RefundableCrowdsale)
  • ✅ Input validation on all parameters
  • ✅ Safe ETH transfers
  • ✅ Proper access controls

Contract Addresses

After deployment, save your contract addresses:

Token: 0x...
Crowdsale: 0x...

Requirements Checklist

Section 4: Update Crowdsale Functionality

  • ✅ Add function to update price (owner only)
  • ✅ Create script to update price
  • ✅ Require investors be whitelisted
  • ✅ Store whitelisted users in smart contract
  • ✅ Function for owner to add people to whitelist
  • ✅ Only whitelisted can buy tokens
  • ✅ Add open/closed status with timestamp
  • ✅ Restrict purchases to after opening time
  • ✅ Require date is in past before purchase
  • ✅ Add minimum contribution amount
  • ✅ Add maximum contribution amount

Section 5: Bonus Challenges

  • ✅ Create crowdsale with OpenZeppelin
  • ✅ Use ERC20 token library
  • ✅ Import crowdsale contracts
  • ✅ Create refundable crowdsale with minimum funding goal
  • ✅ Allow refunds if goal not reached by deadline
  • ✅ Adapt contracts to use Foundry
  • ✅ Cleanup old, unused contracts

Next Steps

  1. Deploy contracts to testnet
  2. Verify contracts on Etherscan
  3. Add frontend integration
  4. Create user documentation
  5. Conduct security audit before mainnet deployment