2

In case people send ERC20 tokens to my contract, I want to be able to retrieve them. Hence the following function:

/**
   * @dev Allows owner to transfer ERC20 tokens to vault
   * @param _token the contract address of the ERC20 contract
   */
  function retrieveTokens(address _token) public onlyOwner {
    ERC20 erctoken = ERC20(_token);
    erctoken.transfer(Vault, erctoken.balanceOf(this));
  }

On Ropsten testnet, I successfully sent some tokens to the contract. Then I run the above, but it fails. (It used very little gas and did not run out. I entered a gas limit of 6000000, which was much more than needed.)

In remix.ethereum.org (with Injected Web3), I get the following error:

transact to browser/Test.sol:TestSale.retrieveTokens errored: Gas required exceeds limit: 4000000. An important gas estimation might also be the sign of a problem in the contract code. Please check loops and be sure you did not sent value to a non payable function (that's also the reason of strong gas estimation).

In remix.ethereum.org (with Javascript VM), I'm getting the following error:

from:0xca3...a733c, to:broswer/Test.sol:TestSale.retrieveTokens(address) 0x643...62e55, value:0 wei, data:0xac4...95963, 0 logs, hash:0xe76...c0094

transact to browser/Test.sol:TestSale.retrieveTokens errored: VM error: invalid opcode. The constructor should be payable if you send value. The execution might have thrown. Debug the transaction to get more information.

How do I fix this? I'm not sending any value when I call this transaction.

I copied the code from TenX and modified it for my Solidity smart contracts. You can see all of my code at https://gist.github.com/anonymous/3497e6b4e09953a009a4fdbacd11946a

1

Being payable is the important part to allow you to transfer, the owner check is secondary. Use:

function retrieveTokens(address _token) public payable {
   require(msg.sender == owner);
   ERC20 erctoken = ERC20(_token);
   erctoken.transfer(Vault, erctoken.balanceOf(this));
}

That should take care of it.

  • Although should work, I would change the second line to require(msg.sender == owner), because an assert should never eval to false. There's a pretty good clarification of the new words over here: ethereum.stackexchange.com/questions/15166/… – Rob Hitchens - B9lab Oct 19 '17 at 21:49
  • @RobinBeckett @RobHitchens I replaced it with your code and replaced line 2 with require(msg.sender == owner). I created contracts with "Javascript VM" and called retrieveTokens. It gave me the same error as before: transact to browser/Test.sol:TestSale.retrieveTokens errored: VM error: invalid opcode. The constructor should be payable if you send value. The execution might have thrown. Debug the transaction to get more information. Should I ignore this and try it on Ropsten test net? – Curt Oct 20 '17 at 13:32
  • I'm a bit confused. Probably just ignorant. Adding payable was my first thought too, but then I thought "doesn't payable mean that the contract is allowed to receive ether if the function is called?" Where is the contract receiving ether in this case? Again, maybe I'm just missing something obvious. – Thomas Jay Rush Oct 20 '17 at 14:41
  • 1
    I suspect we're concentrating on the wrong section. The phrase "should be payable" can be misleading because it prints for all constructor failures. I'm wondering which constructor it's talking about given that we're no deploying a new ERC20. I think you should post your contract and the address you use for ERC20 so we can replicate the error and sort it out. – Rob Hitchens - B9lab Oct 20 '17 at 15:29
  • @RobHitchens You can see my code for all of the contracts at gist.github.com/anonymous/3497e6b4e09953a009a4fdbacd11946a When you create the TestSale contract, remix will create the other contracts as well, including the TestToken contract and remix will show you the address for token (TestToken). – Curt Oct 20 '17 at 18:05
3

As suspected, two issues jump out from the code posted in the gist in the comments.

First, line 1 pragma solidity ^0.4.11. This is not the case. In line 100, you use the modifier pure that was introduced with solidity 0.4.17. Therefore, it doesn't compile with a lower version and 0.4.11 misleads about the required dialect.

Second, line 297 has directional quotes (leaning left and right) and the compiler doesn't want that. It's a syntax error. Use " on both sides.

The error message is misleading in that it's suggesting a common issue with failure to deploy (make it payable) but in this case the failure has to do with failing to compile it at all.

Since compiler version can be a source of issues, in practice, it's handy to specify the exact version (without ^) and make sure it's consistently used. For example, if switching between Remix, Truffle, and solc, you'll get head-scratchers unless everything is on the same version level. You might find, for example, that truffle is forcing you to 0.4.15, so you would want to set your code to check for 0.4.15 and set Remix to load that version. Install solc at that level if using it.

Hope it helps.

  • Directional quotes are only in gist. In remix, they are " on both sides. I changed pragma solidity ^0.4.11 to pragma solidity ^0.4.18 (remix is now defaulting to 0.4.18). Hopefully this will not introduce more bugs. I created contract TestSale, called retrieveTokens and still got the same error: transact to browser/Test.sol:TestSale.retrieveTokens errored: VM error: invalid opcode. The constructor should be payable if you send value. The execution might have thrown. Debug the transaction to get more information. Should I ignore this and try it on Ropsten test net? – Curt Oct 21 '17 at 18:00
  • The issue is there are multiple ways to deploy a contract and you don't say how you do it. Any inconsistency in the tooling is going to generate this error. Now the code requires solidity 0.4.18. Are you sure your command line tools used for deployment (solc, truffle, etc.) provide 0.4.18? – Rob Hitchens - B9lab Oct 21 '17 at 18:07
  • I create the contract in remix (Javascript VM). I call retrieveTokens in remix and get the error in remix. If there were not any errors, I would create the contract in remix (Injected Web3 with MetaMask) into Ropsten network and test it there. If there are no errors on Ropsten, then I would create the contract in remix (Injected Web3 with MetaMask) into Main network. Does that answer your question about how I would deploy the contract? I'm not using command tools. I wrote this code 2 months ago. It worked fine. When I tried it this week, remix 0.4.17 gave warnings, so I added pure. – Curt Oct 21 '17 at 18:59
  • Please see my comment to Robin Beckett's answer. – Curt Oct 23 '17 at 19:12

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.