1

I am following this community for quite a bit and found some very helpful answers in the past, so I hope you can help me to solve a problem with my crowdsale contract as well.

At first I would like to mention I am only using Atom for writing, Remix for compiling and MEW for deploying the contracts and I am not a professional programmer, what should be obvious looking at my code I guess. :-/

I was trying to create a crowdsale contract with the following features:

  • distributing a fixed supply token from an address which has approved allowance to the crowdsale

  • whitelisting

  • opening/closing time

  • cap

To get a contract with these features I basically took the OpenZeppelin contracts and mixed them in a way it seems to be useful to me. At the beginning I had alot of mistakes and the code was not even able to be compiled. Then I finally got a version that was compiled but I got a "throw" exception in MEW.

Now I am even rid of that exception but it still does not work completely.

The contract is deployed but it is empty when I want to interact with it. Even the opening/closing time functions show a wrong state and I have no idea how to declare the address of the token which shall be used.

I am completely lost right now and do not know how to solve this problem.

Probably it is a simple beginner mistake but I would kindly ask you to have a look at my code and provide me some help.

Thank you very much in advance!

pragma solidity ^0.4.21;

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
/**

  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
    if (a == 0) {
      return 0;
    }
    c = a * b;
    assert(c / a == b);
    return c;
  }
/**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    // uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return a / b;
  }
/**
  * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }
/**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
    c = a + b;
    assert(c >= a);
    return c;
  }
}

/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
interface ERC20 {
  function totalSupply() external view returns (uint256);
  function balanceOf(address who) external view returns (uint256);
  function transfer(address to, uint256 value) external returns (bool);
  function allowance(address owner, address spender) external view returns (uint256);
  function transferFrom(address from, address to, uint256 value) external returns (bool);
  function approve(address spender, uint256 value) external returns (bool);


  event Transfer(address indexed from, address indexed to, uint256 value);

  event Approval(address indexed owner, address indexed spender, uint256 value);
  }



/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;
event OwnershipRenounced(address indexed previousOwner);
  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() public {
    owner = msg.sender;
  }
/**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
/**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    emit OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }
/**
   * @dev Allows the current owner to relinquish control of the contract.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(owner);
    owner = address(0);
  }
}



contract TestCrowdsale is Ownable {
  using SafeMath for uint256;

mapping(address => bool) public whitelist;

// The token being sold
ERC20 public token;

// Address where funds are collected
address public wallet = 0x770a682364cbed4374d1eF1fA343AB08561aF376;

// How many token units a buyer gets per wei
uint256 public rate = 10000;

// Amount of wei raised
uint256 public weiRaised = 0;

//Crowdsale opening time
uint256 public openingTime = now;

//Crowdsale closing time
uint256 public closingTime = now + 60 minutes;

//Address holding the tokens, which has approved allowance to the crowdsale
address public tokenWallet = 0xf926F01559E5fF8c1b63BfD6E944c8E93Cb20009;

//Max amount of wei to be contributed
uint256 public cap = 1 * 10 ** 18;

/**
   * Event for token purchase logging
   * @param purchaser who paid for the tokens
   * @param beneficiary who got the tokens
   * @param value weis paid for purchase
   * @param amount amount of tokens purchased
   */
event TokenPurchase(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);

function TestCrowdsale (
    uint256 _rate,
    address _wallet,
    ERC20 _token,
    uint256 _openingTime,
    uint256 _closingTime,
    address _tokenWallet,
    uint256 _cap
  )
    public
  {
    require(_rate > 0);
    require(_wallet != address(0));
    require(_token != address(0));
    require(_openingTime >= block.timestamp);
    require(_closingTime >= _openingTime);
    require(_tokenWallet != address(0));
    require(_cap > 0);
    rate = _rate;
    wallet = _wallet;
    token = _token;
    openingTime = _openingTime;
    closingTime = _closingTime;
    tokenWallet = _tokenWallet;
    cap = _cap;
  }

// -----------------------------------------
  // Crowdsale external interface
  // -----------------------------------------
/**
   * @dev fallback function ***DO NOT OVERRIDE***
   */
  function () external payable {
    buyTokens(msg.sender);
  }

/**
   * @dev Adds single address to whitelist.
   * @param _beneficiary Address to be added to the whitelist
   */
  function addToWhitelist(address _beneficiary) external onlyOwner {
    whitelist[_beneficiary] = true;
  }

/**
   * @dev Adds list of addresses to whitelist. Not overloaded due to limitations with truffle testing.
   * @param _beneficiaries Addresses to be added to the whitelist
   */
  function addManyToWhitelist(address[] _beneficiaries) external onlyOwner {
    for (uint256 i = 0; i < _beneficiaries.length; i++) {
      whitelist[_beneficiaries[i]] = true;
    }
  }

/**
   * @dev Removes single address from whitelist.
   * @param _beneficiary Address to be removed to the whitelist
   */
  function removeFromWhitelist(address _beneficiary) external onlyOwner {
    whitelist[_beneficiary] = false;
  }

  // -----------------------------------------
  // Public interface
  // -----------------------------------------
  /**
   * @dev low level token purchase ***DO NOT OVERRIDE***
   * @param _beneficiary Address performing the token purchase
   */
  function buyTokens(address _beneficiary) public payable {
uint256 weiAmount = msg.value;
    _preValidatePurchase(_beneficiary, weiAmount);
// calculate token amount to be send
    uint256 tokens = _getTokenAmount(weiAmount);
// update state
    weiRaised = weiRaised.add(weiAmount);
_processPurchase(_beneficiary, tokens);
    emit TokenPurchase(
      msg.sender,
      _beneficiary,
      weiAmount,
      tokens
    );
_forwardFunds();
  }

  /**
   * @dev Checks the amount of tokens left in the allowance.
   * @return Amount of tokens left in the allowance
   */
  function remainingTokens() public view returns (uint256) {
    return token.allowance(tokenWallet, this);
  }

  /**
   * @dev Checks whether the period in which the crowdsale is open has already elapsed.
   * @return Whether crowdsale period has elapsed
   */
  function hasClosed() public view returns (bool) {
    // solium-disable-next-line security/no-block-members
    return block.timestamp > closingTime;
  }

  /**
   * @dev Checks whether the cap has been reached.
   * @return Whether the cap was reached
   */
  function capReached() public view returns (bool) {
    return weiRaised >= cap;
  }

  /**
    *Owner can transfer out any accidentally sent ERC20 tokens
*/
  function transferAnyERC20Token(address tokenAddress, uint256 _value) public onlyOwner returns (bool success) {
        return ERC20(tokenAddress).transfer(owner, _value);
    }

// -----------------------------------------
  // Internal interface (extensible)
  // -----------------------------------------
/**
   * @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met. Use super to concatenate validations.
   * @param _beneficiary Address performing the token purchase
   * @param _weiAmount Value in wei involved in the purchase
   */
  function _preValidatePurchase(address _beneficiary, uint256 _weiAmount) internal view {
    require(whitelist[_beneficiary]);
    require(block.timestamp >= openingTime && block.timestamp <= closingTime);
    require(_beneficiary != address(0));
    require(_weiAmount != 0);
    require(weiRaised.add(_weiAmount) <= cap);
  }

/**
   * @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends its tokens.
   * @param _beneficiary Address performing the token purchase
   * @param _tokenAmount Number of tokens to be emitted
   */
 function _deliverTokens(address _beneficiary, uint256 _tokenAmount) internal {
    token.transferFrom(tokenWallet, _beneficiary, _tokenAmount);
  }

/**
   * @dev Executed when a purchase has been validated and is ready to be executed. Not necessarily emits/sends tokens.
   * @param _beneficiary Address receiving the tokens
   * @param _tokenAmount Number of tokens to be purchased
   */
  function _processPurchase(address _beneficiary, uint256 _tokenAmount) internal {
    _deliverTokens(_beneficiary, _tokenAmount);
  }

/**
   * @dev Override to extend the way in which ether is converted to tokens.
   * @param _weiAmount Value in wei to be converted into tokens
   * @return Number of tokens that can be purchased with the specified _weiAmount
   */
  function _getTokenAmount(uint256 _weiAmount) internal view returns (uint256) {
    return _weiAmount.mul(rate);
  }

/**
   * @dev Determines how ETH is stored/forwarded on purchases.
   */
  function _forwardFunds() internal {
    wallet.transfer(msg.value);
  }
}
  • How much of the documentation have you read? Can you write your own token contract and get that to deploy? Sounds like you are extremely new. Instead of trying to write a crowdsale, try simple contracts first, then move to crowdfunds. – hextet May 18 '18 at 20:48
  • 1
    As I mentioned I am in fact completely new to all this and I am trying to learn. The token contract itself was actually pretty easy and I had no problems with it. Thats why I wanted to take the next step and create a crowdsale contract. At first I scanned the documentation completely and then I read the parts in detail where I suspected my mistake but I still seem to lack a deeper understanding of coding so I was hoping to get some help from more experienced people. I am able to understand written code pretty good so far but writing it from scratch is still pretty tough. Thanks – Daniel May 18 '18 at 21:10
  • 1
    How about building the contract piece by piece? I found when I first started off I got confused easily by following examples like openzepplin, etc.. They expect you to have a ufll understanding of how it all works. Start with a contract you can send tokens to, and withdraw tokens from, then add in withdrawing tokens for eth, etc... The main issue I can see is that you're not setting the token interface properly. You mention your development environment which sounds very basic, how about trying to install a linter like solhint? That might help as well – hextet May 18 '18 at 21:14
  • Hi, thank you very much for the linter advise. I installed solhint and it already helped me getting a deeper understanding. I have used the weekend for writing some simple contracts and beside some minor issues it works pretty good. Now I tried again to write a crowdsale contract. I simplified a lot of the code and the sub-contracts are all working now but I still have problems with the token interface and the deployment of the main contract. As the code is now completely different to the one in this question I opened a new one... – Daniel May 22 '18 at 10:59