0

It seems to me that the following ERC20 function does not check where the message comes from and allow anyone to transfer tokens between two addresses:

function transferFrom (address _from, address _to, uint256 _value)
public delegatable payable returns (bool) {
  if (frozen) return false;
  else if (
    (addressFlags [_from] | addressFlags [_to]) & BLACK_LIST_FLAG ==
    BLACK_LIST_FLAG)
    return false;
  else {
    uint256 fee =
      (addressFlags [_from] | addressFlags [_to]) & ZERO_FEE_FLAG == ZERO_FEE_FLAG ?
        0 :
        calculateFee (_value);

    if (_value <= allowances [_from][msg.sender] &&
        fee <= safeSub (allowances [_from][msg.sender], _value) &&
        _value <= accounts [_from] &&
        fee <= safeSub (accounts [_from], _value)) {
      require (AbstractToken.transferFrom (_from, _to, _value));
      require (AbstractToken.transferFrom (_from, feeCollector, fee));
      return true;
    } else return false;
  }
}

In AbstractToken:

function transferFrom (address _from, address _to, uint256 _value)
public payable returns (bool success) {
  uint256 spenderAllowance = allowances [_from][msg.sender];
  if (spenderAllowance < _value) return false;
  uint256 fromBalance = accounts [_from];
  if (fromBalance < _value) return false;

  allowances [_from][msg.sender] =
    safeSub (spenderAllowance, _value);

  if (_value > 0 && _from != _to) {
    accounts [_from] = safeSub (fromBalance, _value);
    accounts [_to] = safeAdd (accounts [_to], _value);
  }
  Transfer (_from, _to, _value);
  return true;
}

Here are the approve functions

function approve (address _spender, uint256 _value)
public delegatable payable returns (bool success) {
  return AbstractToken.approve (_spender, _value);
}

In AbstractToken:

function approve (address _spender, uint256 _value)
public payable returns (bool success) {
  allowances [msg.sender][_spender] = _value;
  Approval (msg.sender, _spender, _value);

  return true;
}

Is that true ? I see a frozen variable, which seems to me the only way to control who transfers what and when.

  • 1
    The allowances variable (table) is the one controlling who can transfer from who and how much. That variable can be configured via function approve, not shown in your code. – goodvibration Jan 20 '20 at 18:40
  • True, there is not much inside them, but I've added them. Thank you. – niahoo Jan 20 '20 at 18:53
  • So what's your question then? – goodvibration Jan 20 '20 at 19:01
  • I want to be taught how this contract checks that the caller is allowed to issue a transferFrom since I see no control. approve() does no checks, it just sets values and emits Approval. – niahoo Jan 20 '20 at 19:24
  • Function approve sets the allowances table, which determines who is allowed to transfer, on behalf of whom he is allowed to transfer, and the amount that he is allowed transfer. – goodvibration Jan 20 '20 at 19:26
2

The allowances variable (table) is the one controlling who can transfer from who and how much.

This variable can be configured via function approve.

For example, if you sign the transaction erc20Token.approve(myAccount, 100) with your private key and then send it to the blockchain, then the value of allowances[yourAccount][myAccount] in the erc20Token contract will change from 0 to 100, and I will be permitted to transfer up to 100 wei tokens from your account to anywhere I want.

2

There are several checks performed. Let me explain them one by one:

if (frozen) return false;

If all transfers are frozen now, just return false.

if ((addressFlags [_from] | addressFlags [_to]) & BLACK_LIST_FLAG == BLACK_LIST_FLAG)
  return false;

If either _from or _to is in black list, return false.

_value <= allowances [_from][msg.sender] &&
fee <= safeSub (allowances [_from][msg.sender], _value)

The owner of _from address explicitly allowed msg.sender to transfer _value + fee of the owner's tokens.

_value <= accounts [_from] &&
fee <= safeSub (accounts [_from], _value)

The owner of _from address has at least _value + fee tokens.

uint256 spenderAllowance = allowances [_from][msg.sender];
if (spenderAllowance < _value) return false;

The owner of _from address explicitly allowed msg.sender to transfer _value of the owner's tokens, or just return false.

uint256 fromBalance = accounts [_from];
if (fromBalance < _value) return false;

The owner of _from address has at least _value + fee tokens, or just return false.

So it checked twice, that the caller was explicitly allowed by the owner of the tokens to transfer them.

BTW, I'm the author of this code.

  • I've set the other answer as accepted because the allowances[msg.sender] was the bit I overlooked, and it helped me to see it, and posted first, but thank you very much for those details. I like your code ! – niahoo Jan 22 '20 at 8:35

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.