creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/AvatarService.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IERC165 {\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n\ninterface IERC721 {\n    function ownerOf(uint256 tokenId) external view returns (address);\n    function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n\ninterface IERC1155 {\n    function balanceOf(address account, uint256 id) external view returns (uint256);\n    function uri(uint256 tokenId) external view returns (string memory);\n}\n\ncontract AvatarService {\n    bytes4 private constant INTERFACE_ID_ERC721 = 0x80ac58cd;\n    bytes4 private constant INTERFACE_ID_ERC1155 = 0xd9b67a26;\n\n    struct Avatar {\n        address tokenAddress;\n        uint256 tokenId;\n    }\n\n    struct AvatarInfo {\n        Avatar avatar;\n        bool owned;\n        string uri;\n    }\n\n    mapping(address => Avatar) public avatars;\n\n    event AvatarSet(address indexed walletAddress, address indexed tokenAddress, uint256 indexed tokenId);\n\n    function setAvatar(address tokenAddress, uint256 tokenId) external {\n        Avatar memory currentAvatar = avatars[msg.sender];\n\n        require(!(currentAvatar.tokenAddress == tokenAddress && currentAvatar.tokenId == tokenId), \"Avatar is already set\");\n\n        require(_isTokenOwner(msg.sender, tokenAddress, tokenId), \"Caller is not the owner of the NFT\");\n\n        avatars[msg.sender] = Avatar(tokenAddress, tokenId);\n\n        emit AvatarSet(msg.sender, tokenAddress, tokenId);\n    }\n\n    function getAvatar(address walletAddress) external view returns (Avatar memory) {\n        return avatars[walletAddress];\n    }\n\n    function getAvatarInfo(address walletAddress) external view returns (AvatarInfo memory) {\n        Avatar memory avatar = avatars[walletAddress];\n\n        bool owned = _isTokenOwner(walletAddress, avatar.tokenAddress, avatar.tokenId);\n\n        string memory uri = _getTokenUri(avatar.tokenAddress, avatar.tokenId);\n\n        return AvatarInfo(avatar, owned, uri);\n    }\n\n    function _getTokenUri(address tokenAddress, uint256 tokenId) internal view returns (string memory) {\n        if (tokenAddress == address(0)) {\n            return \"\";\n        } else if (IERC165(tokenAddress).supportsInterface(INTERFACE_ID_ERC721)) {\n            return IERC721(tokenAddress).tokenURI(tokenId);\n        } else if (IERC165(tokenAddress).supportsInterface(INTERFACE_ID_ERC1155)) {\n            return IERC1155(tokenAddress).uri(tokenId);\n        } else {\n            return \"\";\n        }\n    }\n\n    function _isTokenOwner(address walletAddress, address tokenAddress, uint256 tokenId) internal view returns (bool) {\n        if (tokenAddress == address(0)) {\n            return true;\n        } else if (IERC165(tokenAddress).supportsInterface(INTERFACE_ID_ERC721)) {\n            try IERC721(tokenAddress).ownerOf(tokenId) returns (address owner) {\n                return owner == walletAddress;\n            } catch {\n                return false;\n            }\n        } else if (IERC165(tokenAddress).supportsInterface(INTERFACE_ID_ERC1155)) {\n            return IERC1155(tokenAddress).balanceOf(walletAddress, tokenId) > 0;\n        } else {\n            revert(\"Unsupported token type\");\n        }\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "evmVersion": "paris",
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      }
    }
  }}