Creating instance of contract inside another contract and calling it's methods results in thrown exception

1.1k views Asked by At

I have 2 basic contracts: one is for token and the second is for sale.

Token сontract:

contract MyToken is StandardToken, Ownable {

    string public constant name = "My Sample Token";

    string public constant symbol = "MST";

    uint32 public constant decimals = 18;

    function MyToken(uint _totalSupply) {
       require (_totalSupply > 0);
       totalSupply = _totalSupply;
       balances[msg.sender] = totalSupply;
    }
}

Sale Contract

contract Sale {
    address owner;

    address public founderAddress;
    uint256 public constant foundersAmount = 50;

    MyToken public token = new MyToken(1000);


    uint256 public issuedTokensAmount = 0;

    function Sale() {
        owner = msg.sender;
        founderAddress = 0x14723a09acff6d2a60dcdf7aa4aff308fddc160c;
        token.transfer(founderAddress, foundersAmount);
    }

    function() external payable {
        token.transfer(msg.sender, 1);
        owner.transfer(msg.value);
    }   
}

StandardToken and Ownable are all standard implementations from OpenZeppelin repository. Full contract source is available here.

So basically in my Sale Contract I create an instance of my token contract with fixed supply and assign all of the tokens to the caller. Then I transfer some amount of tokens to founder address. When I try to send some ethereum to Sale contract I'm attempting to transfer some of my tokens to the sender (Running all code in Remix browser, I create an instance of Sale contract and call "fallback" method specifying some ether amount). However, this fails with "Exception during execution. (invalid opcode). Please debug the transaction for more information." message. All that I can see when debugging is that code fails in payable method at line:

 token.transfer(msg.sender, 1);

I can't see the exact reason for this as I'm not able to step into this method and see whats going on inside.

Interesting thing is that when I remove a call to transfer method on token instance in Sale Contract constructor - code seems to run fine without any exceptions.

What am I missing?

2

There are 2 answers

0
Yao Sun On

I debugged into the the contract using remix, and the invalid opcode is thrown by:

290 DUP8
291 DUP1
292 EXTCODESIZE
293 ISZERO
294 ISZERO
295 PUSH2 012f
298 JUMPI
299 PUSH1 00
301 DUP1
302 INVALID

I left out the rest, but essentially it loads the address of the token contract and calls EXTCODESIZE which retrieves the contracts code size, and checks that it's not equal to 0 (the token contract exists), unfortunately, it did equate to 0. At this point, I'm unsure whether this is a limitation in remix or I've misunderstood the setup.

I tried the identical contract setup on truffle + testrpc and it deployed, accepted the currency successfully. Do note however that testrpc indicated:

Gas usage: 59137

Meaning that this is above the default sendTransaction w/ no data default (21,000 gas). This means that in a live environment, ensure that you inform users to include extra gas, otherwise the fallback function would probably fail due to OOG errors.

0
CryptoRhino On

The reason behind this is that you're using a fallback function. Try using a normal function and it should happen.