2

Hi I am a newbie to the Ethereum development. I have successfully deployed a burnable, pausable, capped token contract (TC) on rinkeby test network, and was able to interact with it - minted and transferred tokens without problem.

I have now written and successfully deployed a simple Crowdsale contract (CSC) wrapping TC above on Rinkeby, but have a hard time interacting with it. I kept getting "fail" transaction after sending ETH to purchase token on Metamask, and "The contract won't allow this transaction to be executed" error on Mist error. I don't know of any good tool to debug what would have gone wrong at run time. Any help will be greatly appreciated!

After reviewing other thread and comments below, i have done the following to further debug what the issue is:

  1. changed coin contract to interface
  2. added back fallback function() to accept payment
  3. commented out ValidPurchase() in the buyToken function

But still no cigar. Please help!

Thank you so much for your help in advance!

The deployed Token contract (TC) can be found here: https://rinkeby.etherscan.io/address/0x8A175aE6aCBC6b90812B547719ACEfaa975987AC#code

The updated deployed Crowdsale contract (CSC) can be found here: https://rinkeby.etherscan.io/address/0x686c4f0c9be46e6b45781ecf0cc745fd9fb85dde#code

Here is the CSC code:


pragma solidity ^0.4.18;

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  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 c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b = a);
    return c;
  }
}

/**
 * @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 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));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }

}


/**
 * @title Pausable
 * @dev Base contract which allows children to implement an emergency stop mechanism.
 */
contract Pausable is Ownable {
  event Pause();
  event Unpause();

  bool public paused = false;


  /**
   * @dev Modifier to make a function callable only when the contract is not paused.
   */
  modifier whenNotPaused() {
    require(!paused);
    _;
  }

  /**
   * @dev Modifier to make a function callable only when the contract is paused.
   */
  modifier whenPaused() {
    require(paused);
    _;
  }

  /**
   * @dev called by the owner to pause, triggers stopped state
   */
  function pause() onlyOwner whenNotPaused public {
    paused = true;
    Pause();
  }

  /**
   * @dev called by the owner to unpause, returns to normal state
   */
  function unpause() onlyOwner whenPaused public {
    paused = false;
    Unpause();
  }
}


/*******************************************************************************************
 * Token contract begins
 * Based on references from OpenZeppelin: https://github.com/OpenZeppelin/zeppelin-solidity
 *******************************************************************************************/
interface Token { 
    function mint(address _to, uint256 _amount) public returns (bool);
    function transferOwnership(address newOwner) public;
    function finishMinting() public returns(bool);
    function totalSupply() public constant returns (uint256 supply);
}

/*******************************************************************************************
 * @dev IHT Crowdsale contract. 
 * Based on references from OpenZeppelin: https://github.com/OpenZeppelin/zeppelin-solidity
 *******************************************************************************************/
contract IHTCSFiveFive is Ownable, Pausable {
    using SafeMath for uint256;

    /**************************************************************************
     * Constants
     **************************************************************************/
    uint256 public constant DECIMALS = 4;
    uint256 public constant MAX_TOKENS_AVAILABLE = 1 * (10**8) * (10**DECIMALS);        // 100Mil IHTTokenFive total
    uint256 public constant MAX_TOKENS_FOR_SALE = 35 * (10**6) * (10**DECIMALS);        // 35Mil IHTTokenFive

    /**************************************************************************
     * Variables
     **************************************************************************/
    Token public token;                         // Deployed token being sold

    uint256 public startTime;                   // Start and end timestamps where investments are allowed (both inclusive)
    uint256 public endTime;
    address public wallet;                      // Address where funds are collected
    uint256 public rate;                        // # token units a buyer gets per wei
    uint256 public weiRaised;                   // Amount of raised money in wei

    bool public isFinalized = false;            // Finalization

    /**************************************************************************
     * Events
     **************************************************************************/
    event RateChange(uint256 _rate);
    event WalletChange(address indexed _wallet);
    event EndTimeChange(uint256 _endTime);

    /**
    * 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);

    event Finalized();

    /**************************************************************************
     * Event Implementation
     **************************************************************************/
    /**
    * @dev Sets IHTTokenFive to Ether rate
    * @param _rate defines IHTv5/ETH rate: 1 ETH = _rate * IHTTokenFive
    */
    function setRate(uint256 _rate) external onlyOwner {
        require(_rate != 0x0);
        rate = _rate;

        RateChange(_rate);
    }

    /**
    * @dev Allows to adjust the crowdsale end time
    */
    function setEndTime(uint256 _endTime) external onlyOwner {
        require(!isFinalized);
        require(_endTime >= startTime);
        require(_endTime >= now);
        endTime = _endTime;

        EndTimeChange(_endTime);
    }

    /**
    * @dev Sets the wallet to forward ETH collected funds
    */
    function setWallet(address _wallet) external onlyOwner {
        require(_wallet != 0x0);
        wallet = _wallet;

        WalletChange(_wallet);
    }

    /**************************************************************************
     * Constructor
     **************************************************************************/
    /**
    * @dev Contructor
    * @param _startTime startTime of crowdsale
    * @param _endTime endTime of crowdsale
    * @param _rate IHT / ETH rate
    * @param _wallet wallet to forward the collected funds
    * @param _token token contract to link to this crowdsale contract
    */
    function IHTCSFiveFive(
        uint256 _startTime,
        uint256 _endTime,
        uint256 _rate,
        address _wallet,
        address _token
    ) public
    {
        require(_startTime >= now);
        require(_endTime >= _startTime);
        require(_rate > 0);
        require(_wallet != address(0));
        require(_token != 0x0);

        startTime = _startTime;
        endTime = _endTime;
        rate = _rate;
        wallet = _wallet;        

        token = Token(_token);
    }

    // fallback function don't accept purchase
    function () external payable {
        buyTokens(msg.sender);
    }

    /**************************************************************************
     * Finalization methods
     **************************************************************************/
    /**
     * @dev Must be called after crowdsale ends, to do some extra finalization
     * work. Calls the contract's finalization function.
     */
    function finalize() onlyOwner public {
        require(!isFinalized);
        require(hasEnded());

        finalization();
        Finalized();

        isFinalized = true;
    }

    // Overrided methods
    /**
    * @dev Finalizes the crowdsale
    */
    function finalization() internal {
        // Mint tokens up to MAX_TOKENS_AVAILABLE and assign to owner wallet
        if (token.totalSupply() = startTime) && (now = MAX_TOKENS_FOR_SALE;
        return now > endTime || capReached;
    }
}

but still no avail. In Mist, it still says the execute will fail...etherscan said the transaction is canceled, and failed...

https://rinkeby.etherscan.io/tx/0x306a9cfebf689342eec94e6e26d8fe9c7d8dad35538d36d128d477ff4d49e92b

the start / end time is within the valid period:

    start time: 1512981000 Is equivalent to: 12/11/2017 @ 8:30am (UTC)
    end time: 1513130400 Is equivalent to: 12/13/2017 @ 2:00am (UTC)

I just couldn't figure out why it would fail for such a simple contract, and not knowing where to start debugging is frustrating...

6
  • Did you call buy or buyTokens functions? You can only send ether through functions with payable modifier, your fallback function is payable but it does revert() immediately so you cannot senr ether directly, only with buy and buyTokens.
    – Ismael
    Dec 10, 2017 at 17:38
  • Thanks for the response. Yes, i don't want to let user to send ether call function() inadvertently, so i requested to use buy(). Isn't buy() the function to call by EVM when using Mist/Metamask to send token to the contract?
    – Guru
    Dec 11, 2017 at 2:03
  • I read this thread, and changed the token contract to an interface.
    – Guru
    Dec 11, 2017 at 2:07
  • I think you have to explicitely call buy(). I do not use Mist/Metamask but I doubt they automaticaly call buy() from a contract, the most reasonable function to call is the fallback but you have disabled it. In any case you should check all the requires and asserts (including those in modifiers) called by buy or buyTokens.
    – Ismael
    Dec 11, 2017 at 2:54
  • Thanks Ismael, i re-added back function() to call buyToken in the another contract, but again, no cigar. I checked all the modifiers to ensure all the conditions are met. I am working on a version without the modifier to see if they are indeed the issue. Is there any tool recommendation on figuring out what could be the issue? e.g. if it is indeed the modifier, which one is the culprit to help tremendously. Thanks again!
    – Guru
    Dec 11, 2017 at 7:41

1 Answer 1

0

I have been struggling with an extremely similar problem with my crowdsale/token contracts that use open-zeppelin. After a lot of digging, I believe it is due to the use of Ownable. I still don't know how to solve this issue, so I would appreciate someone smarter than me chiming in.

When the token contract is deployed and the address of the token is passed into the crowdsale, calls to the token contract that require onlyOwner fail.

This is because when Contract A calls a method on Contract B, msg.sender gets changed from the account that called Contract A's method to the address of Contract A.

For example:

contract A is Ownable {
  B public b;

  function A(address _bAddress) public {
    b = B(_bAddress);      
  }

  function callSomeMethodOnB() public {
    b.someMethod();
  }
}

contract B is Ownable {
  uint256 public callCounter;

  function B() public {

  }

  function someMethod() public onlyOwner {
    callCounter = callCounter + 1;
  }  
}

When someone calls callSomeMethodOnB the account that calls the method is msg.sender inside that method's context. However, inside of someMethod the addess of contract A shows up as msg.sender. This causes the onlyOwner modifier from Ownable to fail and revert the transaction.

The question is, how can we make this call to contract B and pass the original msg.sender in. tx.origin is a possibility, but I have read it can be spoofed and is insecure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.