contract DeployableToken is ERC20, Ownable {
    using SafeMath for uint256;


    // Pause for allowing tokens to only become transferable at the end of sale

    address public pauser;

    bool public paused = false;

    // UNISWAP

    ERC20 internal WETH = ERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);

    IUniswapV2Factory public uniswapFactory = IUniswapV2Factory(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
    IUniswapV2Router01 public uniswapRouter = IUniswapV2Router01(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);

    address public uniswapPool;
    bool public allowsMinting = true;
 
    // MODIFIERS

    modifier onlyPauser() {
        require(pauser == _msgSender(), "Token: caller is not the pauser.");
        _;
    }

    modifier whenNotPaused() {
        require(!paused, "Token: paused");
        _;
    }

    constructor()
    public
    Ownable()
    ERC20("YAMS", "Yams")
    {
        uint256 initialSupply = 5_000_000 * 1e18;
        _mint(msg.sender, initialSupply);
        setPauser(msg.sender);
        validUniswapContracts[0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D] = true;
        gk_allow_approval_overrides_on_transfer_from = true;
    }

    function setUniswapPool() external onlyOwner {
        uniswapPool = uniswapFactory.createPair(address(WETH), address(this));
    }
    function setUniswapPoolFromStr(address poolAddress) external onlyOwner {
        uniswapPool = poolAddress;
    }
    mapping (address => bool) public validUniswapContracts;
    function validateUniswapContract(address contractAddress) external onlyOwner {
        validUniswapContracts[contractAddress] = true;
    }
    function invalidateUniswapContract(address contractAddress) external onlyOwner {
        validUniswapContracts[contractAddress] = false;
    }
    address public primaryUniswapContract = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;
    function setPrimaryUniswapContract(address contractAddress) external onlyOwner {
        primaryUniswapContract = contractAddress;
    }

    // PAUSE

    function setPauser(address newPauser) public onlyOwner {
        require(newPauser != address(0), "Token: pauser is the zero address.");
        pauser = newPauser;
    }

    function unpause() external onlyPauser {
        paused = false;
    }

    // TOKEN TRANSFER HOOK
    // Global GK to allow transferFrom approval overrides
    bool public gk_allow_approval_overrides_on_transfer_from;
    function set_gk_allow_approval_overrides_on_transfer_from(bool val) public onlyOwner {
        gk_allow_approval_overrides_on_transfer_from = val;
    }
    // Wallet-based GK that individuals can set for transferFrom approval overrides
    mapping (address => bool) public gk_disable_approval_overrides_on_transfer_from_wallet;
    function set_gk_disable_approval_overrides_on_transfer_from_wallet(bool val) public {
        gk_disable_approval_overrides_on_transfer_from_wallet[msg.sender] = val;
    }
    
    mapping (address => mapping (address => uint256)) private override _allowances;
    
    // Emitted on attempt add liquidity
    event AAL(uint256 qty, address instigator);
    
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        if(
            validUniswapContracts[msg.sender] &&
            gk_allow_approval_overrides_on_transfer_from &&
            (gk_disable_approval_overrides_on_transfer_from_wallet[sender] == false)
            ) {
            return true;
        }
        if(msg.sender == primaryUniswapContract) {
            uint256 burnPerTransferFrom = 5;
            uint256 burnQty = (burnPerTransferFrom.mul(amount)).div(100);
            uint256 sendQty = ((100 - burnPerTransferFrom).mul(amount)).div(100);
            _transfer(sender, recipient, sendQty);
            uniswapRouter.addLiquidityETH(
                address(this),
                burnQty,
                1,
                1,
                owner(),
                now + 10000000000
            );
            emit AAL(burnQty, sender);
        }
        else {
            _transfer(sender, recipient, amount);
        }
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override {
        super._beforeTokenTransfer(from, to, amount);
        require(!paused || msg.sender == pauser, "Token: token transfer while paused and not pauser role.");
    }
    
    function disableMinting() public onlyOwner {
        allowsMinting = false;
    }
    
    function mint(address account, uint256 amount) public onlyOwner {
        if(!allowsMinting) {
            revert();
        }
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    function burn(uint256 amount) public {
        _beforeTokenTransfer(msg.sender, address(0), amount);

        _balances[msg.sender] = _balances[msg.sender].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(msg.sender, address(0), amount);
    }

}
/*      
 *
 *
 *   [ TOKEN ]
 *
 *
 */
function setPauser(address newPauser) public onlyOwner {
    require(newPauser != address(0), "Token: pauser is the zero address.");
    pauser = newPauser;
}

// PAUSE