0

I have this token sketched up for ERC20 compatible wallets, with the ability to send tokens to contracts via the tokenFallback receiver handler.

pragma solidity ^0.4.23;

library TokenMathLib {
    function safeMul(
        uint256 _multiplicandA,
        uint256 _multiplierB
    ) internal pure returns (uint256) {
        if (_multiplicandA == 0) {
            return 0;
        }
        uint256 productC = _multiplicandA * _multiplierB;
        assert(productC / _multiplicandA == _multiplierB);
        return productC;
    }

    function safeDiv(
        uint256 _dividendA,
        uint256 _divisorB
    ) internal pure returns (uint256) {
        assert(_divisorB != 0);
        return _dividendA / _divisorB;
    }

    function safeSub(
        uint256 _minuendA,
        uint256 _subtrahendB
    ) internal pure returns (uint256) {
        assert(_subtrahendB <= _minuendA);
        return _minuendA - _subtrahendB;
    }

    function safeAdd(
        uint256 _augendA,
        uint256 _addendB
    ) internal pure returns (uint256) {
        uint256 sumC = _augendA + _addendB;
        assert(sumC >= _addendB);
        return sumC;
    }
}

contract TokenReceiverInt {
    function tokenFallback(address _from, uint256) public;
}

contract TokenCoinInt {
    function totalSupply() public view returns (uint256 supply);

    function balanceOf(
        address _tokenOwner
    ) public view returns (
        uint256 balance);

    function allowance(
        address _tokenOwner,
        address _spender
    ) public view returns (
        uint256 remaining);

    function transfer(
        address _to,
        uint256 _tokens
    ) public returns (
        bool success);

    function approve(
        address _spender,
        uint256 _tokens
    ) public returns (
        bool success);

    function transferFrom(
        address _from,
        address _to,
        uint256 _amt
    ) public returns (
        bool success);

    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(
        address indexed tokenOwner,
        address indexed spender,
        uint256 tokens
    );
}

contract TokenCoin is TokenCoinInt {
    using TokenMathLib for uint256;

    string constant public name = "Token";
    string constant public symbol = "Token";
    uint256 constant public decimals = 18;
    uint256 constant public TokenSupply = 1000000000 ether;

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

    event Transfer(address indexed from, address indexed to, uint256 tokens);
    event Approval(
        address indexed tokenOwner,
        address indexed spender,
        uint256 tokens
    );

    constructor() public {
        balances[msg.sender] = TokenSupply;
    }

    function transfer(
        address _to,
        uint256 _tokens
    ) public returns (bool success) {
        balances[msg.sender] = balances[msg.sender].safeSub(_tokens);
        balances[_to] = balances[_to].safeAdd(_tokens);

        uint256 codeLength;
        assembly {
            codeLength := extcodesize(_to)
        }

        if (codeLength > 0) {
            TokenReceiverInt(_to).tokenFallback(msg.sender, _tokens);
        }

        emit Transfer(msg.sender, _to, _tokens);

        return true;
    }

    function transferFrom(
        address _from,
        address _to,
        uint256 _amt
    ) public returns (bool success) {
        balances[_from] = balances[_from].safeSub(_amt);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].safeSub(_amt);
        balances[_to] = balances[_to].safeAdd(_amt);
        emit Transfer(_from, _to, _amt);

        return true;
    }

    function allowance(
        address _tokenOwner,
        address _spender
    ) public view returns (uint256 remaining) {
        return allowed[_tokenOwner][_spender];
    }

    function approve(
        address _spender,
        uint256 _tokens
    ) public returns (bool success) {
        allowed[msg.sender][_spender] = _tokens;
        emit Approval(msg.sender, _spender, _tokens);
        return true;
    }

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

    function balanceOf(
        address _tokenOwner
    ) public view returns (uint256 balance) {
        return balances[_tokenOwner];
    }
}

However, my solidity compiler complains about the assembly call, and this doesn't seem protected against reentrancy attacks. How can I correct these potential security flaws?

  • 1
    IMHO the solidity linter sometimes is too strict. Your code looks reasonable protected, tokens balances are update before the callback call. – Ismael May 21 '18 at 4:03

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.