1

I am testing an ERC20 contract based on Openzeppelin-solidity template. But I am observing a curious behavior with reading a global variable. Here is the contract:

pragma solidity ^0.4.24;

import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";


contract FunnyToken is ERC20 {
    string public constant name = "FunnyToken";
    string public constant symbol = "FYT";
    uint8 public constant decimals = 18;
    uint256 private _totalSupply = 10000 * (10 ** uint256(decimals));
    address private owner;

    constructor() public {
        owner = msg.sender;
    }
}

then I truffle migrate it to ganache-cli and run the following commands on truffle console:

FunnyToken.deployed().then(inst=> tok=inst);
tok.totalSupply();

the value returne is: BigNumber { s: 1, e: 0, c: [ 0 ] }. So I conclude that the _totalSupply global variable is not being initialized properly, because the function totalSupply is implemented like this:

function totalSupply() public view returns (uint256) {
    return _totalSupply;
  }

Can anyone explain me what is going on?

  • Are you sure that contract is deployed when you call totalSupply? – Maxpeinas Oct 22 '18 at 19:47
1

The problem is that you are creating a new storage variable in your FunnyToken contract. The base contract will still access the old storage variable.

One solution is to assign the value in the constructor.

pragma solidity ^0.4.0;

contract TokenBase {
    uint _totalSupply;
    function totalSupply() public view returns (uint) {
        return _totalSupply;
    }
}

contract Token is TokenBase {
    // uint _totalSupply = 4321; // <-- this creates a new storage variable
    constructor() public {
        _totalSupply = 1234; // It is better to initialize the old variable
    }
}

Another possible solution is to override the function totalSupply() in your contract, but you will be wasting an extra slot of storage.

  • I believe I tried assigning the value of _totalSupply in the constructor as well but it did not solve the issue. I ended up giving up on inheritance, for now. – fccoelho Oct 24 '18 at 14:43
  • I think this is because new version of OpenZeppelin that variable is private, and you do not have access from child contracts. But their example github.com/OpenZeppelin/openzeppelin-solidity/blob/master/… show how you do it calling internal function _mint. – Ismael Oct 24 '18 at 15:30
0

All you need to do is convert the bignumber to an actual number. Additionally, considering how many people use open zeppelin, seems pretty unusual for this to happen. Try to display the bignumber as a number.

const number = tok.totalSupply()
number.toNumber()

See How to convert BigNumber to Number in Truffle framework?

  • That gives an error message that toNumber is not a function. if you try to access it as an attribute it returns undefined. – fccoelho Oct 22 '18 at 18:37
  • Never really used truffle console, I'll update the code. – GrandFleet Oct 22 '18 at 18:39
  • In anycase the error returned in BigNumber type, is wrong, it is the equivalent to 0 – fccoelho Oct 22 '18 at 18:47
0

I found the answer to my own question: Upon inheritance, derived contracts cannot access private variables from the base contract (funny, but true) therefore the when I call totalSupply (defined the base contract) it will access the _totalSupply from the base contract, instead of the one I defined on the derived contract, thus returning 0.

I guess that to get around this I'd have to overload the totalSupply method on the derived contract. I haven't tested that though.

0

You declared _totalSupply as

uint256 private _totalSupply = 10000 * (10 ** uint256(decimals));

Since it's a private variable inside your base contract, you won't be able to call it from any of your derived contracts (Reason).

Now, it's even simpler to bypass the same in Solidity ^0.5.0:

pragma solidity ^0.5.0;

import 'openzeppelin-solidity/contracts/token/ERC721/ERC721Full.sol';
import 'openzeppelin-solidity/contracts/token/ERC721/ERC721Mintable.sol';

contract FunnyToken is ERC20 {
    string public constant name = "FunnyToken";
    string public constant symbol = "FYT";
    uint8 public constant decimals = 18;
    uint256 public _totalSupply = 10000;
    address private owner;

    constructor() public {
        owner = msg.sender;
    }
}

Hope am clear on the above. Thanks

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.