2

I am sending ETH on Rinkeby network from my wallet in Metamask to a contract that has been deployed on Rinkeby. This is a crowdsale contract based on Open Zeppelin.

However when I check the transaction details on Etherscan, I get the following error:

TxReceipt Status: Fail

How do I find out the problem?


Update

Metamask's suggested gas amount is always unusually high when the transaction is to fail...

ETH was sent to the TestTokenSale.sol contract.

Rinkeby transaction: 0xbbcff212c72e201412a3c4f4304d13e517212b793f04ae597399d2f375052b36

geth debug.traceTransaction: [Gist]

The TestToken.sol is first deployed, followed by TestTokenSale.sol

TestToken.sol

Constructor Arguments: 'qwe', 'qwe, 'qwe', 123

  pragma solidity ^0.4.15;

  import "./libs/zeppelin/token/MintableToken.sol";

  contract TestToken is MintableToken {

     string public name;
     string public symbol;
     uint8 public constant decimals = 18;
     string public constant version = "1.0";

     string public location;
     uint8 public power;

     uint256 public constant tokenUnit = 10 ** 18;

     function TestToken(string _name, string _symbol, string _location, uint8 _power) {
        name = _name;
        symbol = _symbol;

        location = _location;
        power = _power;
     }
  }

TestTokenSale.sol

Constructor arguments: 1520889758, 1530889758, 500, 10000000, 0xcede48d8ac162d1b08ed9419010de3c99f2cfdd6, 0x37b925b6c72cc313bea41b95629b74478d9d442b

pragma solidity ^0.4.15;

import "./libs/zeppelin/crowdsale/CappedCrowdsale.sol";
import "./libs/zeppelin/crowdsale/FinalizableCrowdsale.sol";
import './TestToken.sol';



contract TestTokenSale is CappedCrowdsale, FinalizableCrowdsale {

  address public tokenContractAddress;

  function TestTokenSale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _cap, address _wallet, address _tokenContractAddress)
    CappedCrowdsale(_cap)
    FinalizableCrowdsale()
    Crowdsale(_startTime, _endTime, _rate, _wallet)
  {
    tokenContractAddress = _tokenContractAddress;
  }

  function createTokenContract(address tokenContractAddress) internal returns (MintableToken) {
    return TestToken(tokenContractAddress);
  }


  function finalization() internal {
  }

}

Update 2

ETH send to TestTokenSale.sol still fails...

Tx: 0x640771750ded31c0ef817d1e0df3a1ec16c186fd353a6034dd1799af26e486ed

TestTokenSale.sol

Constructor arguments: 1511235849, 1530889758, 500, 10000000, 0xcede48d8ac162d1b08ed9419010de3c99f2cfdd6, 0x47a27fb4722f293b7ab499ef910d1f2ca78b94b6

pragma solidity ^0.4.15;

import "./libs/zeppelin/crowdsale/CappedCrowdsale.sol";
import "./libs/zeppelin/crowdsale/FinalizableCrowdsale.sol";
import './TestToken.sol';



contract TestTokenSale is CappedCrowdsale, FinalizableCrowdsale {

  address public tokenContractAddress;

  function TestTokenSale(uint256 _startTime, uint256 _endTime, uint256 _rate, uint256 _cap, address _wallet, address _tokenContractAddress)
    CappedCrowdsale(_cap)
    FinalizableCrowdsale()
    Crowdsale(_startTime, _endTime, _rate, _wallet)
  {
    token = TestToken(_tokenContractAddress);
  }

  function finalization() internal {
  }

}

Update 3

Tx: 0x561f9cb4630905c2bb1391db3d3d1afd3b29cc454b238b25dbc3372f19c4a274

ETH sends successfully to TestTokenSale.sol contract only if Crowdsale.sol was edited to comment out require(validPurchase()) :

Code works

  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    // require(validPurchase());
    ...

Code fails

ETH send will fail if I dont comment out that line, but instead set validPurchase() to return true:

  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    require(validPurchase());
    ...


  function validPurchase() internal constant returns (bool) {
    return true;
    // bool withinPeriod = now >= startTime && now <= endTime;
    // bool nonZeroPurchase = msg.value != 0;
    // return withinPeriod && nonZeroPurchase;
  }

Code works!!!

  // low level token purchase function
  function buyTokens(address beneficiary) public payable {
    require(beneficiary != address(0));
    require(now >= startTime);
    require(now <= endTime);
    require(msg.value != 0);
    // require(validPurchase());

Shouldnt require(validPurchase()) not throw any errors if validPurchase() returns true?

Why does it work if the 3 conditions are moved from validPurchase() out to buyTokens, but dont work when they are inside `validPurchase()~?

What's happening here?

  • Do you have the contract code? From the geth trace it is making a revert after some checks. And it is early on the execution, likely one of the require/assert has failed. Without the source code is hard to say anything more. – Ismael Nov 19 '17 at 22:51
  • @Ismael I have posted the contract code in the question, and tried deploying this again, so please refer to the latest transaction hash 0xbbcff212c72e201412a3c4f4304d13e517212b793f04ae597399d2f375052b36. Do you see anything wrong with the contract code? – Athena Wisdom Nov 21 '17 at 2:45
  • Your contract rinkeby.etherscan.io/address/… has parameters startTime: 0x5a139137 (1511231799) 2017-11-21T02:36:39+00:00, endTime: 0x5b3f861e (1530889758) 2018-07-06T15:09:18+00:00. Your tx was processed at (1511232006) 2017-11-21T02:40:06+00:00. So that appears to be ok. – Ismael Nov 21 '17 at 3:16
  • The problem is your constructor calls Crowdsale() which in turn will call createTokenContract() which will return TestToken(tokenContractAddress), but it will return 0x0, because tokenContractAddress is not yet initialzed. Drop variable tokenContractAddress and assign directly in your constructor token = MintableToken(_tokenContractAddress); – Ismael Nov 21 '17 at 3:26
  • @Ismael Should I still override createTokenContract? – Athena Wisdom Nov 21 '17 at 3:31
4

We had some of the same problems as you did. What we figured out was the following:

  1. startTime and endTime must be set so that when you call the contract, you are in fact buying tokens when the sale is open. We added a hasStarted() method and called both this and the hasEnded() method to make sure that we were in fact within the sale period.
  2. The startTime must be in the future. If it is not, nothing will work. This is why we add 90 seconds to the current timestamp.
  3. The data types in the migration script is really important.
    • You cannot just send inn accounts[0] in the constructor - the address needs to be a string when it is called from the migration file.
    • You cannot send in a normal number (like 25) as the rate - it needs to be a web3.BigNumber(25).

For reference, here is our migration file: 2_deploy_contracts.js

var MyTokenCrowdsale = artifacts.require("MyTokenCrowdsale");

module.exports = function(deployer, network, accounts) {
  const start = web3.eth.getBlock(web3.eth.blockNumber).timestamp + 90;
  const end = start + (86400 * 30); // 30 days
  const rate = new web3.BigNumber(25);
  wallet = accounts[1].toString();
  deployer.deploy(MyTokenCrowdsale, start, end, rate, wallet);
};
  • Working! Why did you pass a web3.BigNumber instead of a regular int for the rate – Athena Wisdom Nov 25 '17 at 16:59
  • Because the constructor expects the number to be a web3.BigNumber and not an int. – karianneberg Nov 26 '17 at 11:00
1

Looking at the contract code one can see that the contract accepts Ether only during the period in which the token sale takes place. If you send ether outside of this period, the contract will interrupt execution and return your ether (i.e. what is left after paying the gas required to execute the contract up to this point).

The period of the token sale is set when creating the contract by parameters _starttime and _endtime of the constructor. I did not look at contract storage to verify which values were set for _starttime and _endtime. However, you could start trouble shooting at this point and check that reasonable values for _starttime and _endtime were set at contract creation.

  • I checked that the time I sent the ETH to contract was between the _startTime and _endTime. But the transaction still failed... – Athena Wisdom Nov 19 '17 at 21:36
  • For example, _startTime=1511127652, _endTime=1530889758, and the time I sent the ETH to the contract was after 1511127656 according to unixtimestamp.com/index.php – Athena Wisdom Nov 19 '17 at 21:42
  • So that should be ok. You can try to debug the code, using Remix, for example. Or take out line by line from the buyTokens-function, deploy the contract every time you took out a line and find out in which line things are not running as they should. A little tedious, though... – gisdev_p Nov 19 '17 at 22:10
  • Great approach! I commented out each line of code one by one starting from the last line in the buyTokens function, and token.mint(beneficiary, tokens); seem to be the line causing the ETH send to fail! – Athena Wisdom Nov 19 '17 at 22:55
  • The MintableToken was deployed separately from the Crowdsale contract, I wonder if this causes a problem with the mint function having the modifiers onlyOwner canMint, maybe the crowdsale contract is not the owner of the MintableToken? – Athena Wisdom Nov 19 '17 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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