2

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 Transfer(address indexed from, address indexed to, uint256 value);
//event LogWithdrawal(address receiver, uint amount);

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

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

/*ERC20*/


/* 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);
  }
  else{
    _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)
onlyOwner
{
  //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
      _sender.transfer(ethRefund);
      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;
  }
  else{
    //Receive 10000 Test per 1 ETH
    _value = msg.value / TestWei;
  }


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

function closeCrowdSale() public
onlyOwner{
  crowdsaleClosed = true;
}

}

crowdsale code:

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

contract TestCrowdSale {
address public beneficiary;
address public crowdsaleAddress;
//debugging
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 {
    //require(!crowdsaleClosed);
    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
0

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

require (balanceOf[_from] > _value); // Check if the sender has enough

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

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.