// SPDX-License-Identifier: MIT
pragma solidity 0.8.6;
interface Receiver {
function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns (bytes4);
}
contract Metadata {
string public name = "Yat NFT";
string public symbol = "Yats";
function contractURI() external pure returns (string memory) {
return "https://a.y.at/nft_transfers/contract/";
}
function baseTokenURI() public pure returns (string memory) {
return "https://a.y.at/nft_transfers/metadata/";
}
function tokenURI(uint256 _tokenId) external pure returns (string memory) {
bytes memory _base = bytes(baseTokenURI());
uint256 _digits = 1;
uint256 _n = _tokenId;
while (_n > 9) {
_n /= 10;
_digits++;
}
bytes memory _uri = new bytes(_base.length + _digits);
for (uint256 i = 0; i < _uri.length; i++) {
if (i < _base.length) {
_uri[i] = _base[i];
} else {
uint256 _dec = (_tokenId / (10**(_uri.length - i - 1))) % 10;
_uri[i] = bytes1(uint8(_dec) + 48);
}
}
return string(_uri);
}
}
contract YAT {
address constant private USE_GLOBAL_SIGNER = address(type(uint160).max);
struct User {
uint256 balance;
mapping(uint256 => uint256) list;
mapping(address => bool) approved;
mapping(uint256 => uint256) indexOf;
}
struct Token {
address owner;
address cosigner;
address approved;
address pointsTo;
address resolvesTo;
string token;
uint256 records;
mapping(uint256 => bytes32) keys;
mapping(bytes32 => string) values;
mapping(bytes32 => uint256) indexOf;
uint256 nonce;
}
struct Info {
uint256 totalSupply;
mapping(uint256 => Token) list;
mapping(bytes32 => uint256) idOf;
mapping(bytes32 => string) dictionary;
mapping(address => string) resolve;
mapping(address => User) users;
Metadata metadata;
address owner;
address signer;
}
Info private info;
mapping(bytes4 => bool) public supportsInterface;
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Transfer(address indexed from, address indexed to, bytes32 indexed tokenHash, string token);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
event Mint(bytes32 indexed tokenHash, uint256 indexed tokenId, address indexed account, string token);
event Burn(bytes32 indexed tokenHash, uint256 indexed tokenId, address indexed account, string token);
event RecordUpdated(bytes32 indexed tokenHash, address indexed manager, bytes32 indexed keyHash, string token, string key, string value);
event RecordAdded(bytes32 indexed tokenHash, address indexed manager, bytes32 indexed keyHash, string token, string key);
event RecordDeleted(bytes32 indexed tokenHash, address indexed manager, bytes32 indexed keyHash, string token, string key);
modifier _onlyOwner() {
require(msg.sender == owner());
_;
}
modifier _onlyTokenOwner(uint256 _tokenId) {
require(msg.sender == ownerOf(_tokenId));
_;
}
modifier _onlyTokenOwnerOrCosigner(uint256 _tokenId) {
require(msg.sender == ownerOf(_tokenId) || msg.sender == cosignerOf(_tokenId));
_;
}
constructor(address _signer) {
info.metadata = new Metadata();
info.owner = msg.sender;
info.signer = _signer;
supportsInterface[0x01ffc9a7] = true; // ERC-165
supportsInterface[0x80ac58cd] = true; // ERC-721
supportsInterface[0x5b5e139f] = true; // Metadata
supportsInterface[0x780e9d63] = true; // Enumerable
}
function setOwner(address _owner) external _onlyOwner {
info.owner = _owner;
}
function setSigner(address _signer) external _onlyOwner {
info.signer = _signer;
}
function setMetadata(Metadata _metadata) external _onlyOwner {
info.metadata = _metadata;
}
function mint(string calldata _token, address _account, uint256 _expiry, bytes memory _signature) external {
require(block.timestamp < _expiry);
require(_verifyMint(_token, _account, _expiry, _signature));
_mint(_token, _account);
}
/**
* "Soft-burns" the NFT by transferring the token to the contract address.
**/
function burn(uint256 _tokenId) external _onlyTokenOwner(_tokenId) {
_transfer(msg.sender, address(this), _tokenId);
emit Burn(hashOf(tokenOf(_tokenId)), _tokenId, msg.sender, tokenOf(_tokenId));
}
function setCosigner(address _cosigner, uint256 _tokenId) public _onlyTokenOwner(_tokenId) {
info.list[_tokenId].cosigner = _cosigner;
}
function resetCosigner(uint256 _tokenId) external {
setCosigner(USE_GLOBAL_SIGNER, _tokenId);
}
function revokeCosigner(uint256 _tokenId) external {
setCosigner(address(0x0), _tokenId);
}
function setPointsTo(address _pointsTo, uint256 _tokenId) public _onlyTokenOwner(_tokenId) {
info.list[_tokenId].pointsTo = _pointsTo;
}
function resolveTo(address _resolvesTo, uint256 _tokenId) public _onlyTokenOwner(_tokenId) {
_updateResolvesTo(_resolvesTo, _tokenId);
}
function unresolve(uint256 _tokenId) external {
resolveTo(address(0x0), _tokenId);
}
function updateRecord(uint256 _tokenId, string memory _key, string memory _value, bytes memory _signature) external {
require(_verifyRecordUpdate(_tokenId, _key, _value, info.list[_tokenId].nonce++, _signature));
_updateRecord(_tokenId, _key, _value);
}
function updateRecord(uint256 _tokenId, string memory _key, string memory _value) public _onlyTokenOwnerOrCosigner(_tokenId) {
_updateRecord(_tokenId, _key, _value);
}
function deleteRecord(uint256 _tokenId, string memory _key) external {
updateRecord(_tokenId, _key, "");
}
function deleteAllRecords(uint256 _tokenId) external _onlyTokenOwnerOrCosigner(_tokenId) {
_deleteAllRecords(_tokenId);
}
function approve(address _approved, uint256 _tokenId) external _onlyTokenOwner(_tokenId) {
info.list[_tokenId].approved = _approved;
emit Approval(msg.sender, _approved, _tokenId);
}
function setApprovalForAll(address _operator, bool _approved) external {
info.users[msg.sender].approved[_operator] = _approved;
emit ApprovalForAll(msg.sender, _operator, _approved);
}
function transferFrom(address _from, address _to, uint256 _tokenId) external {
_transfer(_from, _to, _tokenId);
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external {
safeTransferFrom(_from, _to, _tokenId, "");
}
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) public {
_transfer(_from, _to, _tokenId);
uint32 _size;
assembly {
_size := extcodesize(_to)
}
if (_size > 0) {
require(Receiver(_to).onERC721Received(msg.sender, _from, _tokenId, _data) == 0x150b7a02);
}
}
function name() external view returns (string memory) {
return info.metadata.name();
}
function symbol() external view returns (string memory) {
return info.metadata.symbol();
}
function contractURI() external view returns (string memory) {
return info.metadata.contractURI();
}
function baseTokenURI() external view returns (string memory) {
return info.metadata.baseTokenURI();
}
function tokenURI(uint256 _tokenId) external view returns (string memory) {
return info.metadata.tokenURI(_tokenId);
}
function owner() public view returns (address) {
return info.owner;
}
function signer() public view returns (address) {
return info.signer;
}
function totalSupply() public view returns (uint256) {
return info.totalSupply;
}
function balanceOf(address _owner) public view returns (uint256) {
return info.users[_owner].balance;
}
function resolve(address _account) public view returns (string memory) {
return info.resolve[_account];
}
function reverseResolve(string memory _token) public view returns (address) {
return info.list[idOf(_token)].resolvesTo;
}
function hashOf(string memory _token) public pure returns (bytes32) {
return keccak256(abi.encodePacked(_token));
}
function idOf(string memory _token) public view returns (uint256) {
bytes32 _hash = hashOf(_token);
require(info.idOf[_hash] != 0);
return info.idOf[_hash] - 1;
}
function tokenOf(uint256 _tokenId) public view returns (string memory) {
require(_tokenId < totalSupply());
return info.list[_tokenId].token;
}
function ownerOf(uint256 _tokenId) public view returns (address) {
require(_tokenId < totalSupply());
return info.list[_tokenId].owner;
}
function cosignerOf(uint256 _tokenId) public view returns (address) {
require(_tokenId < totalSupply());
address _cosigner = info.list[_tokenId].cosigner;
if (_cosigner == USE_GLOBAL_SIGNER) {
_cosigner = signer();
}
return _cosigner;
}
function pointsTo(uint256 _tokenId) public view returns (address) {
require(_tokenId < totalSupply());
return info.list[_tokenId].pointsTo;
}
function nonceOf(uint256 _tokenId) public view returns (uint256) {
require(_tokenId < totalSupply());
return info.list[_tokenId].nonce;
}
function recordsOf(uint256 _tokenId) public view returns (uint256) {
require(_tokenId < totalSupply());
return info.list[_tokenId].records;
}
function getApproved(uint256 _tokenId) public view returns (address) {
require(_tokenId < totalSupply());
return info.list[_tokenId].approved;
}
function isApprovedForAll(address _owner, address _operator) public view returns (bool) {
return info.users[_owner].approved[_operator];
}
function tokenByIndex(uint256 _index) public view returns (uint256) {
require(_index < totalSupply());
return _index;
}
function tokenOfOwnerByIndex(address _owner, uint256 _index) public view returns (uint256) {
require(_index < balanceOf(_owner));
return info.users[_owner].list[_index];
}
function getKey(bytes32 _hash) public view returns (string memory) {
return info.dictionary[_hash];
}
function getRecord(string memory _token, string memory _key) public view returns (string memory) {
return getRecord(idOf(_token), _key);
}
function getRecord(uint256 _tokenId, string memory _key) public view returns (string memory) {
bytes32 _hash = keccak256(abi.encodePacked(_key));
return getRecord(_tokenId, _hash);
}
function getRecord(uint256 _tokenId, bytes32 _hash) public view returns (string memory) {
require(_tokenId < totalSupply());
return info.list[_tokenId].values[_hash];
}
function getFullRecord(uint256 _tokenId, bytes32 _hash) public view returns (string memory, string memory) {
return (getKey(_hash), getRecord(_tokenId, _hash));
}
function getRecords(uint256 _tokenId, bytes32[] memory _hashes) public view returns (bytes32[] memory values, bool[] memory trimmed) {
require(_tokenId < totalSupply());
uint256 _length = _hashes.length;
values = new bytes32[](_length);
trimmed = new bool[](_length);
for (uint256 i = 0; i < _length; i++) {
string memory _value = info.list[_tokenId].values[_hashes[i]];
values[i] = _stringToBytes32(_value);
trimmed[i] = bytes(_value).length > 32;
}
}
function getRecordsTable(uint256 _tokenId, uint256 _limit, uint256 _page, bool _isAsc) public view returns (bytes32[] memory hashes, bytes32[] memory keys, bool[] memory keysTrimmed, bytes32[] memory values, bool[] memory valuesTrimmed, uint256 totalRecords, uint256 totalPages) {
require(_limit > 0);
totalRecords = recordsOf(_tokenId);
if (totalRecords > 0) {
totalPages = (totalRecords / _limit) + (totalRecords % _limit == 0 ? 0 : 1);
require(_page < totalPages);
uint256 _offset = _limit * _page;
if (_page == totalPages - 1 && totalRecords % _limit != 0) {
_limit = totalRecords % _limit;
}
hashes = new bytes32[](_limit);
keys = new bytes32[](_limit);
keysTrimmed = new bool[](_limit);
for (uint256 i = 0; i < _limit; i++) {
hashes[i] = info.list[_tokenId].keys[_isAsc ? _offset + i : totalRecords - _offset - i - 1];
string memory _key = getKey(hashes[i]);
keys[i] = _stringToBytes32(_key);
keysTrimmed[i] = bytes(_key).length > 32;
}
} else {
totalPages = 0;
hashes = new bytes32[](0);
keys = new bytes32[](0);
keysTrimmed = new bool[](0);
}
(values, valuesTrimmed) = getRecords(_tokenId, hashes);
}
function getYAT(string memory _token) public view returns (uint256 tokenId, address tokenOwner, address tokenCosigner, address pointer, address approved, uint256 nonce, uint256 records) {
tokenId = idOf(_token);
( , tokenOwner, tokenCosigner, pointer, approved, nonce, records) = getYAT(tokenId);
}
function getYAT(uint256 _tokenId) public view returns (string memory token, address tokenOwner, address tokenCosigner, address pointer, address approved, uint256 nonce, uint256 records) {
return (tokenOf(_tokenId), ownerOf(_tokenId), cosignerOf(_tokenId), pointsTo(_tokenId), getApproved(_tokenId), nonceOf(_tokenId), recordsOf(_tokenId));
}
function getYATs(uint256[] memory _tokenIds) public view returns (bytes32[] memory tokens, address[] memory owners, address[] memory cosigners, address[] memory pointers, address[] memory approveds) {
uint256 _length = _tokenIds.length;
tokens = new bytes32[](_length);
owners = new address[](_length);
cosigners = new address[](_length);
pointers = new address[](_length);
approveds = new address[](_length);
for (uint256 i = 0; i < _length; i++) {
string memory _token;
(_token, owners[i], cosigners[i], pointers[i], approveds[i], , ) = getYAT(_tokenIds[i]);
tokens[i] = _stringToBytes32(_token);
}
}
function getYATsTable(uint256 _limit, uint256 _page, bool _isAsc) public view returns (uint256[] memory tokenIds, bytes32[] memory tokens, address[] memory owners, address[] memory cosigners, address[] memory pointers, address[] memory approveds, uint256 totalYATs, uint256 totalPages) {
require(_limit > 0);
totalYATs = totalSupply();
if (totalYATs > 0) {
totalPages = (totalYATs / _limit) + (totalYATs % _limit == 0 ? 0 : 1);
require(_page < totalPages);
uint256 _offset = _limit * _page;
if (_page == totalPages - 1 && totalYATs % _limit != 0) {
_limit = totalYATs % _limit;
}
tokenIds = new uint256[](_limit);
for (uint256 i = 0; i < _limit; i++) {
tokenIds[i] = tokenByIndex(_isAsc ? _offset + i : totalYATs - _offset - i - 1);
}
} else {
totalPages = 0;
tokenIds = new uint256[](0);
}
(tokens, owners, cosigners, pointers, approveds) = getYATs(tokenIds);
}
function getOwnerYATsTable(address _owner, uint256 _limit, uint256 _page, bool _isAsc) public view returns (uint256[] memory tokenIds, bytes32[] memory tokens, address[] memory cosigners, address[] memory pointers, address[] memory approveds, uint256 totalYATs, uint256 totalPages) {
require(_limit > 0);
totalYATs = balanceOf(_owner);
if (totalYATs > 0) {
totalPages = (totalYATs / _limit) + (totalYATs % _limit == 0 ? 0 : 1);
require(_page < totalPages);
uint256 _offset = _limit * _page;
if (_page == totalPages - 1 && totalYATs % _limit != 0) {
_limit = totalYATs % _limit;
}
tokenIds = new uint256[](_limit);
for (uint256 i = 0; i < _limit; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, _isAsc ? _offset + i : totalYATs - _offset - i - 1);
}
} else {
totalPages = 0;
tokenIds = new uint256[](0);
}
(tokens, , cosigners, pointers, approveds) = getYATs(tokenIds);
}
function allInfoFor(address _owner) external view returns (uint256 supply, uint256 ownerBalance) {
return (totalSupply(), balanceOf(_owner));
}
function _mint(string memory _token, address _account) internal {
uint256 _tokenId;
bytes32 _hash = hashOf(_token);
if (info.idOf[_hash] == 0) {
_tokenId = info.totalSupply++;
info.idOf[_hash] = _tokenId + 1;
Token storage _newToken = info.list[_tokenId];
_newToken.owner = _account;
_newToken.cosigner = USE_GLOBAL_SIGNER;
_newToken.token = _token;
uint256 _index = info.users[_account].balance++;
info.users[_account].indexOf[_tokenId] = _index + 1;
info.users[_account].list[_index] = _tokenId;
emit Transfer(address(0x0), _account, _tokenId);
emit Transfer(address(0x0), _account, _hash, _token);
} else {
_tokenId = idOf(_token);
info.list[_tokenId].approved = msg.sender;
_transfer(address(this), _account, _tokenId);
}
emit Mint(_hash, _tokenId, _account, _token);
}
function _transfer(address _from, address _to, uint256 _tokenId) internal {
address _owner = ownerOf(_tokenId);
address _approved = getApproved(_tokenId);
require(_from == _owner);
require(msg.sender == _owner || msg.sender == _approved || isApprovedForAll(_owner, msg.sender));
info.list[_tokenId].owner = _to;
info.list[_tokenId].cosigner = USE_GLOBAL_SIGNER;
info.list[_tokenId].pointsTo = _to;
if (_approved != address(0x0)) {
info.list[_tokenId].approved = address(0x0);
emit Approval(_to, address(0x0), _tokenId);
}
_updateResolvesTo(address(0x0), _tokenId);
_deleteAllRecords(_tokenId);
uint256 _index = info.users[_from].indexOf[_tokenId] - 1;
uint256 _moved = info.users[_from].list[info.users[_from].balance - 1];
info.users[_from].list[_index] = _moved;
info.users[_from].indexOf[_moved] = _index + 1;
info.users[_from].balance--;
delete info.users[_from].indexOf[_tokenId];
uint256 _newIndex = info.users[_to].balance++;
info.users[_to].indexOf[_tokenId] = _newIndex + 1;
info.users[_to].list[_newIndex] = _tokenId;
emit Transfer(_from, _to, _tokenId);
emit Transfer(_from, _to, hashOf(tokenOf(_tokenId)), tokenOf(_tokenId));
}
function _updateResolvesTo(address _resolvesTo, uint256 _tokenId) internal {
if (_resolvesTo == address(0x0)) {
delete info.resolve[info.list[_tokenId].resolvesTo];
info.list[_tokenId].resolvesTo = _resolvesTo;
} else {
require(bytes(resolve(_resolvesTo)).length == 0);
require(info.list[_tokenId].resolvesTo == address(0x0));
info.resolve[_resolvesTo] = tokenOf(_tokenId);
info.list[_tokenId].resolvesTo = _resolvesTo;
}
}
function _updateRecord(uint256 _tokenId, string memory _key, string memory _value) internal {
require(bytes(_key).length > 0);
bytes32 _hash = keccak256(abi.encodePacked(_key));
if (bytes(getKey(_hash)).length == 0) {
info.dictionary[_hash] = _key;
}
Token storage _token = info.list[_tokenId];
if (bytes(_value).length == 0) {
_deleteRecord(_tokenId, _key, _hash);
} else {
if (_token.indexOf[_hash] == 0) {
uint256 _index = _token.records++;
_token.indexOf[_hash] = _index + 1;
_token.keys[_index] = _hash;
emit RecordAdded(hashOf(tokenOf(_tokenId)), msg.sender, hashOf(_key), tokenOf(_tokenId), _key);
}
_token.values[_hash] = _value;
}
emit RecordUpdated(hashOf(tokenOf(_tokenId)), msg.sender, hashOf(_key), tokenOf(_tokenId), _key, _value);
}
function _deleteRecord(uint256 _tokenId, string memory _key, bytes32 _hash) internal {
Token storage _token = info.list[_tokenId];
require(_token.indexOf[_hash] != 0);
uint256 _index = _token.indexOf[_hash] - 1;
bytes32 _moved = _token.keys[_token.records - 1];
_token.keys[_index] = _moved;
_token.indexOf[_moved] = _index + 1;
_token.records--;
delete _token.indexOf[_hash];
delete _token.values[_hash];
emit RecordDeleted(hashOf(tokenOf(_tokenId)), msg.sender, hashOf(_key), tokenOf(_tokenId), _key);
}
function _deleteAllRecords(uint256 _tokenId) internal {
Token storage _token = info.list[_tokenId];
while (_token.records > 0) {
bytes32 _hash = _token.keys[_token.records - 1];
_deleteRecord(_tokenId, getKey(_hash), _hash);
}
}
function _getEthSignedMessageHash(bytes32 _messageHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _messageHash));
}
function _splitSignature(bytes memory _signature) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
require(_signature.length == 65);
assembly {
r := mload(add(_signature, 32))
s := mload(add(_signature, 64))
v := byte(0, mload(add(_signature, 96)))
}
}
function _recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) internal pure returns (address) {
(bytes32 r, bytes32 s, uint8 v) = _splitSignature(_signature);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
function _verifyMint(string calldata _token, address _account, uint256 _expiry, bytes memory _signature) internal view returns (bool) {
bytes32 _hash = keccak256(abi.encodePacked("yatNFT", _token, _account, _expiry));
return _recoverSigner(_getEthSignedMessageHash(_hash), _signature) == signer();
}
function _verifyRecordUpdate(uint256 _tokenId, string memory _key, string memory _value, uint256 _nonce, bytes memory _signature) internal view returns (bool) {
bytes32 _hash = keccak256(abi.encodePacked(_tokenId, _key, _value, _nonce));
address _signer = _recoverSigner(_getEthSignedMessageHash(_hash), _signature);
return _signer == ownerOf(_tokenId) || _signer == cosignerOf(_tokenId);
}
function _stringToBytes32(string memory _in) internal pure returns (bytes32 out) {
if (bytes(_in).length == 0) {
return 0x0;
}
assembly {
out := mload(add(_in, 32))
}
}
}
{
"compilationTarget": {
"YAT.sol": "YAT"
},
"evmVersion": "berlin",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"string","name":"token","type":"string"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenHash","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"string","name":"token","type":"string"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":true,"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"token","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"RecordAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":true,"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"token","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"}],"name":"RecordDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"tokenHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"manager","type":"address"},{"indexed":true,"internalType":"bytes32","name":"keyHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"token","type":"string"},{"indexed":false,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"value","type":"string"}],"name":"RecordUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"bytes32","name":"tokenHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"token","type":"string"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"allInfoFor","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"uint256","name":"ownerBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_approved","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"cosignerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"deleteAllRecords","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_key","type":"string"}],"name":"deleteRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"getFullRecord","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"getKey","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"uint256","name":"_page","type":"uint256"},{"internalType":"bool","name":"_isAsc","type":"bool"}],"name":"getOwnerYATsTable","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bytes32[]","name":"tokens","type":"bytes32[]"},{"internalType":"address[]","name":"cosigners","type":"address[]"},{"internalType":"address[]","name":"pointers","type":"address[]"},{"internalType":"address[]","name":"approveds","type":"address[]"},{"internalType":"uint256","name":"totalYATs","type":"uint256"},{"internalType":"uint256","name":"totalPages","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_key","type":"string"}],"name":"getRecord","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_token","type":"string"},{"internalType":"string","name":"_key","type":"string"}],"name":"getRecord","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes32","name":"_hash","type":"bytes32"}],"name":"getRecord","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes32[]","name":"_hashes","type":"bytes32[]"}],"name":"getRecords","outputs":[{"internalType":"bytes32[]","name":"values","type":"bytes32[]"},{"internalType":"bool[]","name":"trimmed","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"uint256","name":"_page","type":"uint256"},{"internalType":"bool","name":"_isAsc","type":"bool"}],"name":"getRecordsTable","outputs":[{"internalType":"bytes32[]","name":"hashes","type":"bytes32[]"},{"internalType":"bytes32[]","name":"keys","type":"bytes32[]"},{"internalType":"bool[]","name":"keysTrimmed","type":"bool[]"},{"internalType":"bytes32[]","name":"values","type":"bytes32[]"},{"internalType":"bool[]","name":"valuesTrimmed","type":"bool[]"},{"internalType":"uint256","name":"totalRecords","type":"uint256"},{"internalType":"uint256","name":"totalPages","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getYAT","outputs":[{"internalType":"string","name":"token","type":"string"},{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"tokenCosigner","type":"address"},{"internalType":"address","name":"pointer","type":"address"},{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"records","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_token","type":"string"}],"name":"getYAT","outputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"address","name":"tokenCosigner","type":"address"},{"internalType":"address","name":"pointer","type":"address"},{"internalType":"address","name":"approved","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"records","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"_tokenIds","type":"uint256[]"}],"name":"getYATs","outputs":[{"internalType":"bytes32[]","name":"tokens","type":"bytes32[]"},{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"address[]","name":"cosigners","type":"address[]"},{"internalType":"address[]","name":"pointers","type":"address[]"},{"internalType":"address[]","name":"approveds","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_limit","type":"uint256"},{"internalType":"uint256","name":"_page","type":"uint256"},{"internalType":"bool","name":"_isAsc","type":"bool"}],"name":"getYATsTable","outputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bytes32[]","name":"tokens","type":"bytes32[]"},{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"address[]","name":"cosigners","type":"address[]"},{"internalType":"address[]","name":"pointers","type":"address[]"},{"internalType":"address[]","name":"approveds","type":"address[]"},{"internalType":"uint256","name":"totalYATs","type":"uint256"},{"internalType":"uint256","name":"totalPages","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_token","type":"string"}],"name":"hashOf","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"_token","type":"string"}],"name":"idOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_token","type":"string"},{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_expiry","type":"uint256"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"nonceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"pointsTo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"recordsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"resetCosigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"resolve","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_resolvesTo","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"resolveTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_token","type":"string"}],"name":"reverseResolve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"revokeCosigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_operator","type":"address"},{"internalType":"bool","name":"_approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_cosigner","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"setCosigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract Metadata","name":"_metadata","type":"address"}],"name":"setMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_pointsTo","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"setPointsTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenOf","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"unresolve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_key","type":"string"},{"internalType":"string","name":"_value","type":"string"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"updateRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_key","type":"string"},{"internalType":"string","name":"_value","type":"string"}],"name":"updateRecord","outputs":[],"stateMutability":"nonpayable","type":"function"}]