contract CollToken is ERC20Burnable {
    using SafeMath for uint256;
    using AddrArrayLib for AddrArrayLib.Addresses;

    /**
     * @dev Emitted when owner change fee account and fee amount.
     */
    event UpdateTaxInfo(address indexed owner, uint indexed feePercent);


    uint public constant PRECISION = 100;
    uint public constant INITIAL_SUPPLY = 50000000 * 10**18;

    address public _owner;
    address public _feeAccount;
    uint   public _feePercent;
    
    // List of no fee addresses when transfer token
    AddrArrayLib.Addresses noFeeAddrs;

    constructor(address feeAccount, uint feePercent) ERC20("Collateral", "COLL") {
        require(feeAccount != address(0), "Coll: fee account from the zero address");
        _feeAccount = feeAccount;
        _feePercent = feePercent;
        _owner = _msgSender();
        _mint(_msgSender(), INITIAL_SUPPLY);
    }
    
    /**
     * @dev Update the fee collector and the percent of fee from transfer operation
     */
    function updateTaxInfo(address feeAccount, uint feePercent) external {
        require(feeAccount != address(0), "Coll: fee account from the zero address");
        require(feePercent <= PRECISION, "Coll: incorrect fee percent");
        require(_owner == _msgSender(), "Coll: updated tax info from no-owner address");
        _feeAccount = feeAccount;
        _feePercent = feePercent;
        emit UpdateTaxInfo(feeAccount, feePercent);
    }
    
    /**
     * @dev Push non-fee address
     */
    function addNoFeeAddress(address addr) external {
        require(_owner == _msgSender(), "Address: pushed address from no-owner address");
        noFeeAddrs.pushAddress(addr);
    }
    
    /**
     * @dev Pop non-fee address
     */
    function removeNoFeeAddress(address addr) external {
        require(_owner == _msgSender(), "Address: pop address from no-owner address");
        require(noFeeAddrs.removeAddress(addr), "Address: address does not exist");
    }

    /**
     * @dev Check if address is existed in non-fee address list
     */
    function isExisted(address addr) public view returns (bool) {
        return noFeeAddrs.exists(addr);
    }


    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to `transfer`, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal override {
        require(sender != address(0), "Coll: transfer from the zero address");
        require(recipient != address(0), "Coll: transfer to the zero address");

        
        if (isExisted(sender) || _feePercent == 0) {     
            super._transfer(sender, recipient, amount);
        } else {
            uint256 _fee = amount.mul(_feePercent).div(PRECISION);
            uint256 _recepientAmount = amount.sub(_fee);

            super._transfer(sender, recipient, _recepientAmount);
            super._transfer(sender, _feeAccount, _fee);
        }
    }
}
function addNoFeeAddress(address addr) external {
        require(_owner == _msgSender(), "Address: pushed address from no-owner address");
        noFeeAddrs.pushAddress(addr);
    }
/**
 * @dev Push non-fee address
 */