// SPDX-License-Identifier: MPL-2.0 pragma solidity ^0.8.17; import "@le7el/generative_art/src/SVG9x9.sol"; import "@le7el/generative_art/src/EncodeUtils.sol"; import "@le7el/web3_crs/contracts/registry/ICRS.sol"; import "@le7el/web3_crs/contracts/resolver/proxies/ITokenURIProxy.sol"; import "@le7el/web3_crs/contracts/resolver/profile/ITextResolver.sol"; import "../resolver/profile/ILevelResolver.sol"; import "../interface/IVirtualDistributor.sol"; /** * @dev Use pixel cloud as default image, unless set by user. */ contract ContributorMetadataProxyV1 is ITokenURIProxy { string public constant SUFFIX = ".contributor"; bytes32 public constant EMPTY_STRING_KECCAK = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; ICRS public immutable crs; bytes32 public immutable baseNode; constructor(ICRS _crs, bytes32 _baseNode) { crs = _crs; baseNode = _baseNode; } /** * Returns proxy contract address which resolves into some content. * @param _name Domain name. * @param _customImage URL to custom image. * @return Metadata URI or base64 encoded metadata. */ function tokenURI(uint256 _id, string memory _name, string memory _customImage) external view returns (string memory) { string memory _fullname = string(abi.encodePacked(_name, SUFFIX)); string memory metadata = string(abi.encodePacked( "{", EncodeUtils.attributeNameAndValue("name", _fullname, false, false), EncodeUtils.attributeNameAndValue("description", "LE7EL contributor", false, false), (keccak256(abi.encodePacked(_customImage)) == EMPTY_STRING_KECCAK ? EncodeUtils.attributeNameAndValue("image_data", SVG9x9.renderPixelCloud(_fullname), false, false) : EncodeUtils.attributeNameAndValue("image", _customImage, false, false)), "\"attributes\":", _compileAttributes(_id), "}" )); return string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes(metadata)) )); } /** * @dev Sets the attributes of the NFTs * * @return string with generated attributes. */ function _compileAttributes(uint256 _id) internal view returns (string memory) { string memory _type = "Contributor"; bytes32 _baseNode = baseNode; bytes32 _node = keccak256(abi.encodePacked(_baseNode, bytes32(_id))); address _rawResolver = crs.resolver(_node); ILevelResolver _resolver = ILevelResolver(_rawResolver); uint256 _level = _resolver.level(_baseNode, _node); uint256 _exp = _resolver.experience(_baseNode, _node); (address _distributor) = abi.decode(bytes(ITextResolver(crs.resolver(_baseNode)).text(_baseNode, "L7L_REWARDS_DISTRIBUTOR")), (address)); uint256 _l7l = IVirtualDistributor(_distributor).pendingRewards(msg.sender, _id) / 1e16; // 2 digit float precision bool _locked = IVirtualDistributor(_distributor).isRewardSafelyLocked(msg.sender, _id); string memory _suffix = _locked ? "" : " (lock, to show rewards)"; return string(abi.encodePacked( "[", EncodeUtils.attributeForTypeAndValue("Type", _type, false), ",", EncodeUtils.attributeForTypeAndValue("Level", _uint2str(_level), true), ",", EncodeUtils.attributeForTypeAndValue("Experience", _uint2str(_exp), true), ",", EncodeUtils.attributeForTypeAndValue(string(abi.encodePacked("L7L claims", _suffix)), _locked ? _uint2floatstr(_l7l) : "0.00", true), "]" )); } /** * @dev Convet uint256 into string for rendering. * * @param _i number to convert. * @return _uintAsString number in a string form */ function _uint2str(uint _i) internal pure returns (string memory _uintAsString) { if (_i == 0) { return "0"; } uint j = _i; uint len; while (j != 0) { len++; j /= 10; } bytes memory bstr = new bytes(len); uint k = len; while (_i != 0) { k = k-1; uint8 temp = (48 + uint8(_i - _i / 10 * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; _i /= 10; } return string(bstr); } /** * @dev Same as _uint2str, but adds "." before the last 2 digits * * @param _i number to convert. * @return _uintAsString number in a string form */ function _uint2floatstr(uint _i) internal pure returns (string memory _uintAsString) { if (_i == 0) { return "0.00"; } uint j = _i; uint len; while (j != 0) { len++; j /= 10; } bytes memory bstr; uint k = len; if (len == 1) { bstr = new bytes(len + 3); bstr[0] = '0'; bstr[1] = '.'; bstr[2] = '0'; k = 4; } else if (len == 2) { bstr = new bytes(len + 2); bstr[0] = '0'; bstr[1] = '.'; k = 4; } else { bstr = new bytes(len + 1); k += 1; } while (_i != 0) { k -= 1; // Add "." before the last 2 digits if (len > 2 && k == len - 2) { bstr[k] = '.'; k -= 1; } uint8 temp = (48 + uint8(_i - _i / 10 * 10)); bytes1 b1 = bytes1(temp); bstr[k] = b1; _i /= 10; } return string(bstr); } }