abstract contract ERC721Tradable2 is
    ContextMixin,
    ERC721Enumerable,
    NativeMetaTransaction,
    Ownable
{
    using SafeMath for uint256;

    address public proxyRegistryAddress;
    uint256 private _currentTokenId = 0;

    constructor(
        string memory _name,
        string memory _symbol,
        address _proxyRegistryAddress
    ) ERC721(_name, _symbol) {
        proxyRegistryAddress = _proxyRegistryAddress;
        _initializeEIP712(_name);
    }

    /**
     * @dev Mints a token to an address with a tokenURI.
     * @param _to address of the future owner of the token
     */
    function mintTo(address _to) public onlyOwner {
        _mint(_to, _getTokenId(_to));
    }

    function _mintTo(address _to) internal returns (uint256) {
        uint256 newTokenId = _getTokenId(_to);
        _mint(_to, newTokenId);
        return newTokenId;
    }

  function _getTokenId(address _to) internal view virtual returns (uint256);
  function _getImg(uint256 _tokenId) internal view virtual returns (string memory);

    function baseTokenURI() public view virtual returns (string memory);

    function tokenURI(uint256 _tokenId)
        public
        view
        override
        returns (string memory)
    {

        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "FDT #', Strings.toString(_tokenId), '", "description": "FreedomTrucker represents the unflinching spirit of the truckers and their supporters who take concrete actions against tyranny in the Freedom Convoy.", "image": "', baseTokenURI(),_getImg(_tokenId), '"}'))));
        string memory output = string(abi.encodePacked('data:application/json;base64,', json));

        return output;
    }

    

    /**
     * Override isApprovedForAll to whitelist user's OpenSea proxy accounts to enable gas-less listings.
     */
    function isApprovedForAll(address owner, address operator)
        public
        view
        override
        returns (bool)
    {
        // Whitelist OpenSea proxy contract for easy trading.
        ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
        if (address(proxyRegistry.proxies(owner)) == operator) {
            return true;
        }

        return super.isApprovedForAll(owner, operator);
    }

    /**
     * This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea.
     */
    function _msgSender() internal view override returns (address sender) {
        return ContextMixin.msgSender();
    }
}
function _msgSender() internal view override returns (address sender) {
    return ContextMixin.msgSender();
}

/**
 * This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea.
 */