contract ArtvatarsMintableERC721 is
ERC721,
AccessControlMixin,
NativeMetaTransaction,
IMintableERC721,
ContextMixin
{
	bytes32 public constant PREDICATE_ROLE = keccak256("PREDICATE_ROLE");

	mapping(uint256 => Artvatar) public tokenToArtvatar;

	struct Attribute {
		string title;
		string name;
	}

	struct Artvatar {
		uint256 id;
		string series;
		string title;
		string description;
		string image;
		Attribute[] attributes;
		bool metadataChanged;
	}

	constructor(string memory name_, string memory symbol_, address predicateProxy_)
	public
	ERC721(name_, symbol_)
	{
		_setupContractId("ArtvatarsMintableERC721");
		_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
		_setupRole(PREDICATE_ROLE, _msgSender());
		_setupRole(PREDICATE_ROLE, predicateProxy_);
		_initializeEIP712(name_);
	}

	function _msgSender()
	internal
	override
	view
	returns (address payable sender)
	{
		return ContextMixin.msgSender();
	}

	/**
	 * @dev See {IMintableERC721-mint}.
	 */
	function mint(address user, uint256 tokenId) external override only(PREDICATE_ROLE) {
		_mint(user, tokenId);
	}

	/**
	 * If you're attempting to bring metadata associated with token
	 * from L2 to L1, you must implement this method, to be invoked
	 * when minting token back on L1, during exit
	 */
	function setTokenMetadata(uint256 tokenId, bytes memory data) internal virtual {
		// This function should decode metadata obtained from L2
		// and attempt to set it for this `tokenId`
		//
		// Following is just a default implementation, feel
		// free to define your own encoding/ decoding scheme
		// for L2 -> L1 token metadata transfer
		(Artvatar memory _artvatar, string memory uri) = abi.decode(data, (Artvatar, string));

		Artvatar storage artvatar = tokenToArtvatar[tokenId];
		Attribute[] memory _attributes = _artvatar.attributes;
		artvatar.id = _artvatar.id;
		artvatar.series = _artvatar.series;
		artvatar.title = _artvatar.title;
		artvatar.description = _artvatar.description;
		artvatar.image = _artvatar.image;

		for (uint256 i = 0; i < _attributes.length; i++) {
			Attribute memory attribute = _attributes[i];
			artvatar.attributes.push(attribute);
		}

		artvatar.metadataChanged = true;

		_setTokenURI(tokenId, uri);
	}

	function getArtvatarByTokenId(uint256 _tokenId) public view returns (Artvatar memory artvatar) {
		return tokenToArtvatar[_tokenId];
	}

	/**
	 * @dev See {IMintableERC721-mint}.
	 *
	 * If you're attempting to bring metadata associated with token
	 * from L2 to L1, you must implement this method
	 */
	function mint(address user, uint256 tokenId, bytes calldata metaData) external override only(PREDICATE_ROLE) {
		_mint(user, tokenId);

		setTokenMetadata(tokenId, metaData);
	}


	/**
	 * @dev See {IMintableERC721-exists}.
	 */
	function exists(uint256 tokenId) external view override returns (bool) {
		return _exists(tokenId);
	}
}
function exists(uint256 tokenId) external view override returns (bool) {
	return _exists(tokenId);
}

/**
 	 * @dev See {IMintableERC721-exists}.
 	 */