1

I am trying Zeppelin StandardToken contract, and see warnings on infinite gas. Why this happens?

Gas requirement of function BasicToken.transfer(address,uint256) high: infinite. If the gas requirement of a function is higher than the block gas limit, it cannot be executed. Please avoid loops in your functions or actions that modify large areas of storage (this includes clearing or copying arrays in storage)

======= /home/smartcontract/gex/node_modules/zeppelin-solidity/contracts/math/SafeMath.sol:SafeMath =======
Gas estimation:
construction:
   61 + 10600 = 10661
internal:
   add(uint256,uint256):    infinite
   div(uint256,uint256):    infinite
   mul(uint256,uint256):    infinite
   sub(uint256,uint256):    infinite

======= /home/smartcontract/gex/node_modules/zeppelin-solidity/contracts/token/BasicToken.sol:BasicToken =======
Gas estimation:
construction:
   246 + 205200 = 205446
external:
   balanceOf(address):  551
   totalSupply():   386
   transfer(address,uint256):   infinite

======= /home/smartcontract/gex/node_modules/zeppelin-solidity/contracts/token/ERC20.sol:ERC20 =======
Gas estimation:

======= /home/smartcontract/gex/node_modules/zeppelin-solidity/contracts/token/ERC20Basic.sol:ERC20Basic =======
Gas estimation:

======= /home/smartcontract/gex/node_modules/zeppelin-solidity/contracts/token/StandardToken.sol:StandardToken =======
Gas estimation:
construction:
   846 + 816200 = 817046
external:
   allowance(address,address):  805
   approve(address,uint256):    22298
   balanceOf(address):  617
   decreaseApproval(address,uint256):   infinite
   increaseApproval(address,uint256):   infinite
   totalSupply():   408
   transfer(address,uint256):   infinite
   transferFrom(address,address,uint256):   infinite

======= contracts/GenesisExchangeToken.sol:GenesisExchangeToken =======
Gas estimation:
construction:
   41228 + 926200 = 967428
external:
   INITIAL_SUPPLY():    351
   allowance(address,address):  893
   approve(address,uint256):    22320
   balanceOf(address):  683
   decimals():  308
   decreaseApproval(address,uint256):   infinite
   increaseApproval(address,uint256):   infinite
   name():  infinite
   symbol():    infinite
   totalSupply():   430
   transfer(address,uint256):   infinite
   transferFrom(address,address,uint256):   infinite

Source code:

pragma solidity ^0.4.18;

library SafeMath {
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

contract ERC20Basic {
  uint256 public totalSupply;
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}

contract BasicToken is ERC20Basic {
  using SafeMath for uint256;

  mapping(address => uint256) balances;

  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[msg.sender]);

    // SafeMath.sub will throw if there is not enough balance.
    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256 balance) {
    return balances[_owner];
  }

}

contract ERC20 is ERC20Basic {
  function allowance(address owner, address spender) public view returns (uint256);
  function transferFrom(address from, address to, uint256 value) public returns (bool);
  function approve(address spender, uint256 value) public returns (bool);
  event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract StandardToken is ERC20, BasicToken {

  mapping (address => mapping (address => uint256)) internal allowed;


  /**
   * @dev Transfer tokens from one address to another
   * @param _from address The address which you want to send tokens from
   * @param _to address The address which you want to transfer to
   * @param _value uint256 the amount of tokens to be transferred
   */
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);

    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    Transfer(_from, _to, _value);
    return true;
  }

  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   *
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param _spender The address which will spend the funds.
   * @param _value The amount of tokens to be spent.
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }

  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param _owner address The address which owns the funds.
   * @param _spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(address _owner, address _spender) public view returns (uint256) {
    return allowed[_owner][_spender];
  }

  /**
   * approve should be called when allowed[_spender] == 0. To increment
   * allowed value is better to use this function to avoid 2 calls (and wait until
   * the first transaction is mined)
   * From MonolithDAO Token.sol
   */
  function increaseApproval(address _spender, uint _addedValue) public returns (bool) {
    allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
    Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

  function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) {
    uint oldValue = allowed[msg.sender][_spender];
    if (_subtractedValue > oldValue) {
      allowed[msg.sender][_spender] = 0;
    } else {
      allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
    }
    Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
    return true;
  }

}

contract GenesisExchangeToken is StandardToken {

  string public constant name = "GenesisExchangeToken";
  string public constant symbol = "GEX";
  uint8 public constant decimals = 18;

  uint256 public constant INITIAL_SUPPLY = 10000 * (10 ** uint256(decimals));

  /**
   * @dev Constructor that gives msg.sender all of existing tokens.
   */
  function GenesisExchangeToken() public {
    totalSupply = INITIAL_SUPPLY;
    balances[msg.sender] = INITIAL_SUPPLY;
  }

}
  • 1
    I don't have a full answer, but it appears that the underlying problem is that all the SafeMath functions have been determined to potentially require infinite gas. (I assume that if you remove the use of SafeMath, the warning about StandardToken.transfer goes away.) – smarx Dec 14 '17 at 14:52
  • FWIW, I couldn't reproduce the warning in Remix. (Your question is tagged with "remix," but it isn't clear to me that you're using Remix at all?) – smarx Dec 14 '17 at 14:58
  • Did you enable static analysis option on Gas costs: Warn if the gas requirements of functions are too high? – Tony Chow Dec 14 '17 at 18:56
  • @TonyChow you can try replacing assert by require, assert causes the transaction to consume all the remaining gas, and require call revert that will return unspend gas to the tx sender, both causes the transaction to terminate with a failed status. – Ismael Dec 14 '17 at 19:05
  • @TonyChow Yes, I have that option checked. are you getting different results in Remix? – smarx Dec 14 '17 at 20:30

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.