Appendix B. Full SimpleCrowdsale application

Listing B.1. Full SimpleCrowdsale application, including crowdsale and coin contracts
pragma solidity ^0.4.24;

import "./Listing5_8_SimpleCoin.sol";
import "./Listing6_4_Ownable.sol";

interface ReleasableToken {
    function mint(address _beneficiary, uint256 _numberOfTokens) external;
    function release() external;
    function transfer(address _to, uint256 _amount) external;
}

contract ReleasableSimpleCoin is ReleasableToken, SimpleCoin { 
    bool public released = false;

    modifier canTransfer() { 
        if(!released) {
            revert();
        }

        _;
    }

    constructor(uint256 _initialSupply) 
        SimpleCoin(_initialSupply) public {} 

    function release() onlyOwner public { 
        released = true;
    }

    function transfer(address _to, uint256 _amount) 
        canTransfer public { 
        super.transfer(_to, _amount);
    }

    function transferFrom(address _from, address _to, 
        uint256 _amount) 
        canTransfer public returns (bool) {
        super.transferFrom(_from, _to, _amount);
    }  
}

contract FundingLimitStrategy{
    function isFullInvestmentWithinLimit(uint256 _investment, 
        uint256 _fullInvestmentReceived)     
        public view returns (bool);
}

contract CappedFundingStrategy is FundingLimitStrategy {
    uint256 fundingCap;

    constructor(uint256 _fundingCap) public {
        require(_fundingCap > 0);
        fundingCap = _fundingCap;
    }

    function isFullInvestmentWithinLimit(uint256 _investment, 
        uint256 _fullInvestmentReceived) 
        public view returns (bool) {
        
        bool check = _fullInvestmentReceived + _investment < fundingCap; 
        return check;
    }
}

contract UnlimitedFundingStrategy is FundingLimitStrategy {
    function isFullInvestmentWithinLimit(uint256 _investment, 
        uint256 _fullInvestmentReceived) 
        public view returns (bool) {
        return true;
    }
}

contract SimpleCrowdsale is Ownable {
    uint256 public startTime;
    uint256 public endTime; 
    uint256 public weiTokenPrice;
    uint256 public weiInvestmentObjective;

    mapping (address => uint256) public investmentAmountOf;
    uint256 public investmentReceived;
    uint256 public investmentRefunded;

    bool public isFinalized;
    bool public isRefundingAllowed; 

    ReleasableToken public crowdsaleToken; 

    FundingLimitStrategy internal fundingLimitStrategy;

    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _weiTokenPrice, uint256 _etherInvestmentObjective) 
     payable public
    {
        require(_startTime >= now);
        require(_endTime >= _startTime);
        require(_weiTokenPrice != 0);
        require(_etherInvestmentObjective != 0);

        startTime = _startTime;
        endTime = _endTime;
        weiTokenPrice = _weiTokenPrice;
        weiInvestmentObjective = _etherInvestmentObjective 
            * 1000000000000000000;

        crowdsaleToken = createToken();
        isFinalized = false;
        fundingLimitStrategy = createFundingLimitStrategy();
    } 

    event LogInvestment(address indexed investor, uint256 value);
    event LogTokenAssignment(address indexed investor, uint256 numTokens);
    event Refund(address investor, uint256 value);

    function invest() public payable {
        require(isValidInvestment(msg.value)); 

        address investor = msg.sender;
        uint256 investment = msg.value;

        investmentAmountOf[investor] += investment; 
        investmentReceived += investment; 

        assignTokens(investor, investment);
        emit LogInvestment(investor, investment);
    }

    function createToken() 
        internal returns (ReleasableToken) {
            return new ReleasableSimpleCoin(0);
        }

    function createFundingLimitStrategy() 
        internal returns (FundingLimitStrategy);

    function isValidInvestment(uint256 _investment) 
        internal view returns (bool) {
        bool nonZeroInvestment = _investment != 0;
        bool withinCrowsalePeriod = now >= startTime && now <= endTime; 
             
        return nonZeroInvestment && withinCrowsalePeriod
           && fundingLimitStrategy.isFullInvestmentWithinLimit(
           _investment, investmentReceived);
    }

    function assignTokens(address _beneficiary, 
        uint256 _investment) internal {

        uint256 _numberOfTokens = calculateNumberOfTokens(_investment); 

        crowdsaleToken.mint(_beneficiary, _numberOfTokens);
    }

    function calculateNumberOfTokens(uint256 _investment) 
        internal returns (uint256) {
        return _investment / weiTokenPrice; 
    }

    function finalize() onlyOwner public {
        if (isFinalized) revert();

        bool isCrowdsaleComplete = now > endTime; 
        bool investmentObjectiveMet = investmentReceived 
           >= weiInvestmentObjective;

        if (isCrowdsaleComplete)
        {     
            if (investmentObjectiveMet)
                crowdsaleToken.release();
            else 
                isRefundingAllowed = true;
            isFinalized = true;
        }               
    }

    function refund() public {
        if (!isRefundingAllowed) revert();

        address investor = msg.sender;
        uint256 investment = investmentAmountOf[investor];
        if (investment == 0) revert();
        investmentAmountOf[investor] = 0;
        investmentRefunded += investment;
        emit Refund(msg.sender, investment);

        if (!investor.send(investment)) revert();
    }    
}

contract TranchePricingCrowdsale is SimpleCrowdsale  {

    struct Tranche {
        uint256 weiHighLimit;
        uint256 weiTokenPrice;
    }

    mapping(uint256 => Tranche) public trancheStructure;
    uint256 public currentTrancheLevel;

    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _etherInvestmentObjective) 
     SimpleCrowdsale(_startTime, _endTime,
        1, _etherInvestmentObjective)
     payable public
    {
        trancheStructure[0] = Tranche(3000 ether, 0.002 ether);
        trancheStructure[1] = Tranche(10000 ether, 0.003 ether);
        trancheStructure[2] = Tranche(15000 ether, 0.004 ether);
        trancheStructure[3] = Tranche(1000000000 ether, 0.005 ether);

        currentTrancheLevel = 0;
    } 

    function calculateNumberOfTokens(uint256 investment) 
        internal returns (uint256) {
        updateCurrentTrancheAndPrice();
        return investment / weiTokenPrice; 
    }

    function updateCurrentTrancheAndPrice() 
        internal {
        uint256 i = currentTrancheLevel;

        while(trancheStructure[i].weiHighLimit < investmentReceived) 
            ++i;

        currentTrancheLevel = i;

        weiTokenPrice =
           trancheStructure[currentTrancheLevel].weiTokenPrice;
    }
}

contract FixedPricingCrowdsale is SimpleCrowdsale {     

    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _weiTokenPrice, uint256 _etherInvestmentObjective)
     SimpleCrowdsale(_startTime, _endTime, 
     _weiTokenPrice, _etherInvestmentObjective)

     payable public  {
    }

    function calculateNumberOfTokens(uint256 investment) 
        internal returns (uint256) {
        return investment / weiTokenPrice;
    }    
}

contract UnlimitedFixedPricingCrowdsale is FixedPricingCrowdsale {

    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _weiTokenPrice, uint256 _etherInvestmentObjective)
     FixedPricingCrowdsale(_startTime, _endTime, 
     _weiTokenPrice, _etherInvestmentObjective)
     payable public  {
    }

    function createFundingLimitStrategy() 
        internal returns (FundingLimitStrategy) {
        
        return new UnlimitedFundingStrategy(); 
    }
}

contract CappedFixedPricingCrowdsale is FixedPricingCrowdsale {

    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _weiTokenPrice, uint256 _etherInvestmentObjective)
     FixedPricingCrowdsale(_startTime, _endTime, 
     _weiTokenPrice, _etherInvestmentObjective)
     payable public  {
    }
    
    function createFundingLimitStrategy() 
        internal returns (FundingLimitStrategy) {
        
        return new CappedFundingStrategy(10000); 
    }
}

contract UnlimitedTranchePricingCrowdsale is TranchePricingCrowdsale {
    
    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _etherInvestmentObjective)
     TranchePricingCrowdsale(_startTime, _endTime, 
     _etherInvestmentObjective)
     payable public  {
    }
    
    function createFundingLimitStrategy() 
        internal returns (FundingLimitStrategy) {
        
        return new UnlimitedFundingStrategy(); 
    }
}

contract CappedTranchePricingCrowdsale is TranchePricingCrowdsale {
    
    constructor(uint256 _startTime, uint256 _endTime, 
     uint256 _etherInvestmentObjective)
     TranchePricingCrowdsale(_startTime, _endTime, 
     _etherInvestmentObjective)
     payable public  {
    }
    
    function createFundingLimitStrategy() 
        internal returns (FundingLimitStrategy) {
        
        return new CappedFundingStrategy(10000); 
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset