2

So I have token contract

pragma solidity ^0.4.11;

contract owned {

    address public owner;

    function owned() {
        owner = msg.sender;
    }

    modifier onlyOwner {
        if (msg.sender != owner) revert();
        _;
    }

    function transferOwnership(address newOwner) onlyOwner {
        owner = newOwner;
    }
}

contract tokenRecipient { function receiveApproval(address _from, uint256 _value, address _token, bytes _extraData); }

contract IERC20Token {

    function getTotalSupply() constant external returns (uint256 totalSupply);

    function getBalanceOf(address _owner) constant returns (uint256 balance);

    function transfer(address _to, uint256 _value) external returns (bool success);

    function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);

    function approve(address _spender, uint256 _value) returns (bool success);

    function getAllowance(address _owner, address _spender) constant returns (uint256 remaining);

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
} 

contract Token is IERC20Token, owned {
    string public standard = 'IERC20 Token';
    string public name;
    string public symbol;
    uint8 public decimals;
    uint256 public totalSupply;

    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;

    event Burn(address indexed from, uint256 value);

    function Token(
        uint256 initialSupply,
        string tokenName,
        uint8 decimalUnits,
        string tokenSymbol
    ) {
        balanceOf[msg.sender] = initialSupply;
        totalSupply = initialSupply;
        name = tokenName;
        symbol = tokenSymbol;
        decimals = decimalUnits;
    }

    function getTotalSupply() constant external returns (uint256) { return totalSupply; }

    function getBalanceOf(address _owner) constant returns (uint256) {
        return balanceOf[_owner];
    }

    function transfer(address _to, uint256 _value) external returns (bool success) {
        if (_to == 0x0) revert();
        if (balanceOf[msg.sender] < _value) revert();
        if (balanceOf[_to] + _value < balanceOf[_to]) revert();
        balanceOf[msg.sender] -= _value;
        balanceOf[_to] += _value;
        Transfer(msg.sender, _to, _value);
        return true;
    }

    function getAllowance(address _owner, address _spender) constant returns (uint256 remaining) {
        return allowance[_owner][_spender];
    }

    function approve(address _spender, uint256 _value) returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        return true;
    }

    function approveAndCall(address _spender, uint256 _value, bytes _extraData)
    returns (bool success) {
        tokenRecipient spender = tokenRecipient(_spender);
        if (approve(_spender, _value)) {
            spender.receiveApproval(msg.sender, _value, this, _extraData);
            return true;
        }
    }        

    function transferFrom(address _from, address _to, uint256 _value) external returns (bool success) {
        if (_to == 0x0) revert();
        if (balanceOf[_from] < _value) revert();
        if (balanceOf[_to] + _value < balanceOf[_to]) revert();
        if (_value > allowance[_from][msg.sender]) revert();
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        allowance[_from][msg.sender] -= _value;
        Transfer(_from, _to, _value);
        return true;
    }

    function burn(uint256 _value) returns (bool success) {
        if (balanceOf[msg.sender] < _value) revert();
        balanceOf[msg.sender] -= _value;
        totalSupply -= _value;
        Burn(msg.sender, _value);
        return true;
    }

    function burnFrom(address _from, uint256 _value) returns (bool success) {
        if (balanceOf[_from] < _value) revert();
        if (_value > allowance[_from][msg.sender]) revert();
        balanceOf[_from] -= _value;
        totalSupply -= _value;
        Burn(_from, _value);
        return true;
    }

    function destroyTokenContract() onlyOwner {
        suicide(owner);
    }
}

As you can see, it's almost unchanged contract from example. Then I have a modified crowdsale contract

contract FixcoinCrowdsale is owned {

    address public beneficiary;
    uint256 public minimumFundingGoal;
    uint256 public fundingGoal; 
    uint256 public amountRaised;
    uint8 public tokensInEth;
    uint public deadline;
    Token public tokenReward;
    mapping(address => uint256) public balanceOf;

    event MinimumGoalReached(address _beneficiary, uint _amountRaised);
    event GoalReached(address _beneficiary, uint _amountRaised);
    event FundTransfer(address _backer, uint amount, bool _isContribution);

    bool minFundingGoalReached = false;
    bool fundingGoalReached = false;
    bool crowdsaleClosed = false;

    uint startDate;

    function FixcoinCrowdsale(
        address ifSuccessfulSendTo,
        uint256 minimumFundingGoalInEther,
        uint256 fundingGoalInEther,
        uint256 durationInMinutes,
        uint8 tokensInEther,
        Token addressOfTokenUsedAsReward
    ) {
        beneficiary = ifSuccessfulSendTo;
        minimumFundingGoal = minimumFundingGoalInEther * 10**18;
        fundingGoal = fundingGoalInEther * 10**18;
        deadline = now + durationInMinutes * 1 minutes;
        tokenReward = Token(addressOfTokenUsedAsReward);
        startDate = now;
        tokensInEth = tokensInEther;
    }

    function calculateTokensAmount(uint256 ethAmount) internal returns (uint8 bonuses) {
        bonuses = uint8(ethAmount * tokensInEth / 10**18);
        return bonuses;
    }

    function sendFundsAndReceiveBonuses() payable {
        if (crowdsaleClosed) revert();
        uint amount = msg.value;
        balanceOf[msg.sender] += amount;
        amountRaised += amount;
        uint8 bonusAmount;
        if (now < startDate + 1 * 1 minutes) {
            bonusAmount += calculateTokensAmount(amount) * 2;
        }
        else if (now < startDate + 2 * 1 minutes) {
            bonusAmount += calculateTokensAmount(amount) * 150 / 100;
        }
        else if (now < startDate + 3 * 1 minutes) {
            bonusAmount += calculateTokensAmount(amount) * 133 / 100;
        }
        else if (now < startDate + 10 * 1 minutes) {
            bonusAmount += calculateTokensAmount(amount) * 125 / 100;
        }
        tokenReward.transfer(msg.sender, bonusAmount);
        FundTransfer(msg.sender, amount, true);
    }

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

    function check() internal {
        if (amountRaised >= minimumFundingGoal){
            minFundingGoalReached = true;
            MinimumGoalReached(beneficiary, amountRaised);
        }
        if (amountRaised >= fundingGoal){
            fundingGoalReached = true;
            GoalReached(beneficiary, amountRaised);
            crowdsaleClosed = true;
            deadline = now;
        }
    }

    function safeWithdrawal() afterDeadline {
        check();
        if (!fundingGoalReached && !minFundingGoalReached) {
            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 ((minFundingGoalReached || fundingGoalReached) && beneficiary == msg.sender) {
            if (beneficiary.send(amountRaised)) {
                FundTransfer(beneficiary, amountRaised, false);
            } else {
                fundingGoalReached = false;
            }
        }
    }
}

I am testing this in Remix IDE. Steps I took:

  1. Created token

  2. Created crowdsale and set token reward address to address of token I created

  3. Transferred all tokens to crowdsale

  4. Tried to send 1 Ether to the crowdsale contract by calling sendFundsAndReceiveBonuses()

  5. Got Exception during execution. (invalid opcode) error

So I started debugger and found out it gets stuck at if (balanceOf[msg.sender] + amount * tokensInEth / 10**18 >= tokenReward.getTotalSupply()) revert();, at tokenReward.getTotalSupply() to be more specific. From what I understood from documentation, external keyword makes function callable from another contract, so I don't understand why it stops here.

What did I miss? Thanks in advance.

P.S. I thought that function might have depleted its gas limit, but I don't know how to check it.

P.P.S. I tested this code in testnet, everything works, when I call sendFundsAndReceiveBonuses() from owner, but when I call it from another wallet, I get error with message "This function will probably deplete all gas given" or something like that

  • I have no idea what have happened, but it looks like now everything works. I'll confirm or refute that later – Lev Sizov Aug 6 '17 at 16:37
  • Yep, it works in testnet, but doesn't work in Remix. – Lev Sizov Aug 8 '17 at 11:24

Your Answer

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

Browse other questions tagged or ask your own question.