contract ERC20Token is SafeMath {
  string public name;
  string public symbol;
  uint256 public totalSupply;
  uint8 public decimals;

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

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

  modifier onlyPayloadSize(uint size) {   
    require(msg.data.length == size + 4);
    _;
  }

  /**
    @dev send coins
    throws on any error rather then return a false flag to minimize user errors

    @param _to      target address
    @param _value   transfer amount

    @return true if the transfer was successful, false if it wasn't
  */
  function transfer(address _to, uint256 _value)
      public
      onlyPayloadSize(2 * 32)
      returns (bool success)
  {
    balances[msg.sender] = safeSub(balances[msg.sender], _value);
    balances[_to] = safeAdd(balances[_to], _value);
    Transfer(msg.sender, _to, _value);
    return true;
  }

  /**
    @dev an account/contract attempts to get the coins
    throws on any error rather then return a false flag to minimize user errors

    @param _from    source address
    @param _to      target address
    @param _value   transfer amount

    @return true if the transfer was successful, false if it wasn't
  */
  function transferFrom(address _from, address _to, uint256 _value)
    public
    onlyPayloadSize(3 * 32)
    returns (bool success)
  {
    allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
    balances[_from] = safeSub(balances[_from], _value);
    balances[_to] = safeAdd(balances[_to], _value);
    Transfer(_from, _to, _value);
    return true;
  }
  
  function approve(address _spender, uint256 _value)
    public
    onlyPayloadSize(2 * 32)
    returns (bool success)
  {
    // if the allowance isn't 0, it can only be updated to 0 to prevent an allowance change immediately after withdrawal
    require(_value == 0 || allowed[msg.sender][_spender] == 0);

    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }

  function allowance(address _owner, address _spender) public constant returns (uint) {
    return allowed[_owner][_spender];
  }

  function balanceOf(address _holder) public constant returns (uint) {
    return balances[_holder];
  }
}
function transferFrom(address _from, address _to, uint256 _value)
  public
  onlyPayloadSize(3 * 32)
  returns (bool success)
{
  allowed[_from][msg.sender] = safeSub(allowed[_from][msg.sender], _value);
  balances[_from] = safeSub(balances[_from], _value);
  balances[_to] = safeAdd(balances[_to], _value);
  Transfer(_from, _to, _value);
  return true;
}

/**
 @dev an account/contract attempts to get the coins
 throws on any error rather then return a false flag to minimize user errors
 
 @param _from    source address
 @param _to      target address
 @param _value   transfer amount
 
 @return true if the transfer was successful, false if it wasn't
 */