contract __unstable__ERC20PrimaryAdmin is Initializable, ERC20, ERC20Detailed, Secondary {
    uint256 private constant UINT256_MAX = 2**256 - 1;

    function initialize(string memory name, string memory symbol, uint8 decimals, address sender) public initializer {
        ERC20Detailed.initialize(name, symbol, decimals);
        Secondary.initialize(sender);
    }

    // The primary account (GSNRecipientERC20Fee) can mint tokens
    function mint(address account, uint256 amount) public onlyPrimary {
        _mint(account, amount);
    }

    // The primary account has 'infinite' allowance for all token holders
    function allowance(address owner, address spender) public view returns (uint256) {
        if (spender == primary()) {
            return UINT256_MAX;
        } else {
            return super.allowance(owner, spender);
        }
    }

    // Allowance for the primary account cannot be changed (it is always 'infinite')
    function _approve(address owner, address spender, uint256 value) internal {
        if (spender == primary()) {
            return;
        } else {
            super._approve(owner, spender, value);
        }
    }

    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        if (recipient == primary()) {
            _transfer(sender, recipient, amount);
            return true;
        } else {
            return super.transferFrom(sender, recipient, amount);
        }
    }
}
// solhint-disable-next-line contract-name-camelcase
function allowance(address owner, address spender) public view returns (uint256) {
    if (spender == primary()) {
        return UINT256_MAX;
    } else {
        return super.allowance(owner, spender);
    }
}

// The primary account has 'infinite' allowance for all token holders