I have a token contract and a crowdsale contract. When I try to send ether to the crowdsale contract from accounts[3] (or any other really), I get an opcode error:

Error: VM Exception while processing transaction: invalid opcode.

I'm testing with Truffle. I've sent Testtokens to the crowdsalecontract address. I've sent Ether to the token contract address. Everything on the token contract works, when I interface with it directly. Tried a lot of things but I remain stuck at this point. Any help much appreciated. Running these contracts on testrpc

truffle migration code:

module.exports = function(deployer,accounts) {
  var sendaccounts = web3.eth.accounts;
  var sendTo = sendaccounts[0];

  deployer.deploy(TestToken).then(function() {
    return deployer.deploy(TestCrowdSale, sendTo, TestToken.address);

web3 code that generates the error:

var sender = accounts[3];
var receiver = crowdsaleAddress;

var amount = web3.toWei(0.5, 'ether');

web3.eth.sendTransaction({from:sender, to:receiver, value: amount});

in crowdsale solidity code, if this line is commented out, the error does not occur:

tokenReward.transfer(msg.sender, amount);

token solidity code:

pragma solidity ^0.4.13;

contract TestToken {
  /* Public variables of the token */
  string public constant name = 'TestToken';
  string public constant symbol = 'TEST';
  uint256 public constant decimals = 6;
  address owner;
  address contractaddress;
  //Swap value in % of ETH
  uint256 public swapValue = 50;
  // One hundred million coins, each divided to up to 10^decimals units.
  uint256 private constant totalSupply = 100000000 * (10 ** decimals);
  uint256 public constant TestWei = 100000000000000;
  bool crowdsaleClosed = false;

  /* This creates an array with all balances */
  mapping (address => uint256) public balanceOf;
  mapping (address => mapping (address => uint256)) public allowance;

  /* This generates a public event on the blockchain that will notify clients */
  //event LogWithdrawal(address receiver, uint amount);

  modifier onlyOwner() {
    // Only owner is allowed to do this action.
    if (msg.sender != owner) {

  /* Initializes contract with initial supply tokens to the creator of the contract */
  function TestToken() {
    contractaddress = address(this);
    balanceOf[msg.sender] = totalSupply / 2;              // Give the creator half of all tokens
    balanceOf[contractaddress] = totalSupply / 2;              // Give the contract half of all tokens
    owner = msg.sender;


  /* Internal transfer, only can be called by this contract */
  function _transfer(address _from, address _to, uint256 _value) internal {
  //function _transfer(address _from, address _to, uint _value) public {
    require (_to != 0x0);                               // Prevent transfer to 0x0 address. Use burn() instead
    require (balanceOf[_from] > _value);                // Check if the sender has enough
    require (balanceOf[_to] + _value > balanceOf[_to]); // Check for overflows
    balanceOf[_from] -= _value;                         // Subtract from the sender
    balanceOf[_to] += _value;                            // Add the same to the recipient
    Transfer(_from, _to, _value);

  /// @notice Send `_value` tokens to `_to` from your account
  /// @param _to The address of the recipient
  /// @param _value the amount to send
  function transfer(address _to, uint256 _value) public returns (bool success) {
    if(_to == contractaddress ){
      swap(msg.sender, _value);
      _transfer(msg.sender, _to, _value);
      return true;

  //deposit collateral ETH
  function depositFunds() public payable onlyOwner

  /*fallback function*/
  function () public payable onlyOwner{}

  //raise the minimum eth payout, minimum will always be 50% ETH
  function raiseSwap(uint _newSwap)
    //swap can only be more than 50%
    //to guarantee there will always be at least a 50% payout
    if(_newSwap > 50){
      swapValue = _newSwap;

  //swap for swapvalue % ether (minimum 50)
  function swap(address _sender,uint256 _value) internal returns(bool success){
    //must be even integer
    uint even = _value / 2;
    require((2 * even) == _value);

    uint TestRefund = (_value / 100) * swapValue;
    uint ethRefund = TestRefund * TestWei;
    // Test is tranferred to contract balance
    uint256 originalBalance = balanceOf[_sender];
    // all necessary checks happen inside _transfer function
    _transfer(_sender, owner, _value);
    // check if tokens are returned succesfully
    if(originalBalance == balanceOf[_sender] + _value){
      //transfer swapvalue % of eth per Test back to sender
      return true;

  function getBalance(address addr) public returns(uint256) {
    return balanceOf[addr];

  function getEtherBalance() public returns(uint256) {
    //return contract ether balance;
    return this.balance;

  function getOwner() public returns(address) {
    return owner;

  /* exchange ETH for Test with the contract address */
  function buyTest() public payable returns (bool){
    require(msg.value > 0);
    uint even = msg.value / 2;
    require((2 * even) == msg.value);
    uint _value;
    if(swapValue > 100){
      uint amount = (msg.value / swapValue) * 100;
      _value = amount / TestWei;
      //Receive 10000 Test per 1 ETH
      _value = msg.value / TestWei;

    _transfer(contractaddress, msg.sender, _value);
    return true;

  function closeCrowdSale() public
    crowdsaleClosed = true;

crowdsale code:

pragma solidity ^0.4.13;
import './TestToken.sol';

contract TestCrowdSale {
  address public beneficiary;
  address public crowdsaleAddress;
  address public tokenAddress;
  uint public fundingGoal;
  uint public amountRaised;
  uint public deadline;
  uint public initiation;
  uint public price;
  uint256 public constant TestWei = 100000000000000;

  TestToken public tokenReward;
  mapping(address => uint256) public balanceOf;
  bool fundingGoalReached = false;
  bool crowdsaleClosed = false;

  event GoalReached(address beneficiary, uint amountRaised);
  event FundTransfer(address backer, uint amount, bool isContribution);

   * Constructor function
   * Setup the owner
  function TestCrowdSale(
    address ifSuccessfulSendTo,
    address addressOfTokenUsedAsReward
  ) {
    beneficiary = ifSuccessfulSendTo;
    fundingGoal = 10 * 1 ether;
    deadline = now + 100 * 1 minutes;
    initiation = now;
    price = TestWei;
    crowdsaleAddress = address(this);
    tokenAddress = addressOfTokenUsedAsReward;
    tokenReward = TestToken(addressOfTokenUsedAsReward);

   * Fallback function
   * The function without name is the default function that is called whenever anyone sends funds to a contract
  function () public payable {
    uint256 amount = msg.value / price;
    balanceOf[msg.sender] += amount;
    amountRaised += amount;
    tokenReward.transfer(msg.sender, amount);
    FundTransfer(msg.sender, amount, true);

  modifier afterDeadline() { if (now >= deadline) _; }

   * Check if goal was reached
   * Checks if the goal or time limit has been reached and ends the campaign
  function checkGoalReached() afterDeadline {
    if (amountRaised >= fundingGoal){
      fundingGoalReached = true;
      GoalReached(beneficiary, amountRaised);
    crowdsaleClosed = true;

   * Withdraw the funds
   * Checks to see if goal or time limit has been reached, and if so, and the funding goal was reached,
   * sends the entire amount to the beneficiary. If goal was not reached, each contributor can withdraw
   * the amount they contributed.
  function safeWithdrawal() afterDeadline {
    if (!fundingGoalReached) {
      uint amount = balanceOf[msg.sender];
      balanceOf[msg.sender] = 0;
      if (amount > 0) {
        if (msg.sender.send(amount)) {
          FundTransfer(msg.sender, amount, false);
        } else {
          balanceOf[msg.sender] = amount;

    if (fundingGoalReached && beneficiary == msg.sender) {
      if (beneficiary.send(amountRaised)) {
        FundTransfer(beneficiary, amountRaised, false);
      } else {
        //If we fail to send the funds to beneficiary, unlock funders balance
        fundingGoalReached = false;
  • 1
    The error was caused by an insufficient amount of gas to complete the transaction. See comments below. – hdries Oct 6 '17 at 10:02

I'm about 90% sure that it's failing on this line:


TestCrowdSale's fallback function is calling

tokenReward.transfer(msg.sender, amount);

Then TestToken.transfer(address _to, uint256 _value) is calling

_transfer(msg.sender, _to, _value);

This means that balanceOf[_from] is going always going to be balanceOf[TestCrowdSale]. If TestCrowdSale doesn't have a balance greater than msg.value / price, your transaction is going to fail.

I'd recommend creating a new function in TestToken, eg subscribe. transfer is meant for just that, transferring, so this is not appropriate for a new subscriber to your crowdsale.

  • No, the error persists, even when I put that check in a comment. balanceOf[TestCrowdSale] has sufficient amount of tokens. The ether balance of the crowdsalecontract is 0 however. Could this be the problem? when tokenReward.transfer(msg.sender, amount); is called, which address needs to pay for this transaction? – hdries Oct 6 '17 at 7:41
  • Sent 15 ether to the crowdsale address. Error still persists. – hdries Oct 6 '17 at 8:00
  • With all require statements uncommented the error still persisted, but I got another error, 'ran out of gas' so I tested the gasamount needed, and in my web3 javascript call, I added: gas: 1000000 Works now... will now add the require statements back and see if it still works. – hdries Oct 6 '17 at 9:44
  • 2
    Problem solved, not enough gas to complete the transaction was the problem. Can't believe I didn't think of this earlier myself. Thanks for the help! @nyusternie – hdries Oct 6 '17 at 10:00

Your Answer

