// SPDX-License-Identifier: MPL-2.0 pragma solidity ^0.8.17; import {console} from "forge-std/console.sol"; import "@le7el/generative_art/src/SVG9x9.sol"; import "@le7el/generative_art/src/EncodeUtils.sol"; import {ContributorMetadataProxyV1} from "src/nft/ContributorMetadataProxyV1.sol"; import {TestWithDeployments} from "./util/TestWithDeployments.sol"; import {ERC1155BurnableMock} from "@openzeppelin/contracts/mocks/ERC1155BurnableMock.sol"; import {IVirtualDistributor} from "../src/interface/IVirtualDistributor.sol"; contract MockRewarder is IVirtualDistributor { mapping(uint256 => uint256) public rewardsFor; mapping(uint256 => bool) public unlockedFor; function test() public {} function setRewardFor(uint256 _tokenId, uint256 _amount) external { rewardsFor[_tokenId] = _amount; } function setUnlockedFor(uint256 _tokenId, bool _status) external { unlockedFor[_tokenId] = _status; } function pendingRewards(address, uint256 _tokenId) external view returns (uint256) { return rewardsFor[_tokenId]; } function isRewardSafelyLocked(address, uint256 _tokenId) external view returns (bool) { return !unlockedFor[_tokenId]; } } contract ContributorMetadataTest is TestWithDeployments { uint256 internal constant YEAR = 365 days; ERC1155BurnableMock internal expToken; MockRewarder internal rewarder; address internal admin = address(1); address internal user = address(2); function setUp() public { vm.label(admin, "Admin"); vm.label(user, "User"); // Setup smart contracts vm.startPrank(admin); deployAll(admin); rewarder = new MockRewarder(); ContributorMetadataProxyV1 metadata = new ContributorMetadataProxyV1(crs, contributorController.baseNode()); contributorNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setProxyConfig(bytes32,address,bytes4,address)", contributorNFT.baseNode(), address(contributorNFT), bytes4(keccak256("tokenURI(uint256,string,string)")), address(metadata) )); expToken = new ERC1155BurnableMock("https://test.metadata/{id}"); expToken.mint(user, 1, 190000, ""); contributorNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setProjectLevelingRules(bytes32,address,address,uint256,bytes4)", contributorController.baseNode(), address(0), address(expToken), 1, bytes4(0xf5298aca) )); contributorNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setText(bytes32,string,string)", contributorController.baseNode(), "L7L_REWARDS_DISTRIBUTOR", string(abi.encode(address(rewarder))) )); vm.stopPrank(); } function testMetadataValidness() public { vm.startPrank(user); registerContributorNFT(user, keccak256("secret"), YEAR, "johndoe"); string memory rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); string memory refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image_data\":\"johndoe.contributor\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.00}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); vm.stopPrank(); } function testMetadataWithLevels() public { vm.startPrank(user); registerContributorNFT(user, keccak256("secret"), YEAR, "johndoe"); expToken.setApprovalForAll(address(resolver), true); assertTrue(resolver.advanceToNextLevel(contributorController.baseNode(), nameToContributorNode("johndoe"), 1200) == 1200); string memory rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); string memory refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image_data\":\"johndoe.contributor\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":2},{\"trait_type\":\"Experience\",\"value\":1200},{\"trait_type\":\"L7L claims\",\"value\":0.00}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); vm.stopPrank(); } function testCustomNFTImages() public { vm.startPrank(user); registerContributorNFT(user, keccak256("secret"), YEAR, "johndoe"); resolver.setText(0xc7c7c25e735ebd8bc31c2434182c6c760cfadb7ffaa60d3b08a287c50ad57554, "L7L_CONTRIBUTOR_IMAGE", "ipfs://chubaka.jpg"); string memory rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); string memory refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.00}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); vm.stopPrank(); } function testMetadataWithLevelTokens() public { vm.startPrank(user); registerContributorNFT(user, keccak256("secret"), YEAR, "johndoe"); resolver.setText(0xc7c7c25e735ebd8bc31c2434182c6c760cfadb7ffaa60d3b08a287c50ad57554, "L7L_CONTRIBUTOR_IMAGE", "ipfs://chubaka.jpg"); // 0.00 rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 0); string memory rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); string memory refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.00}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); // 0.05 rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e16); rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.05}]}')) )); // 0.50 rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e17); rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.50}]}')) )); // 5.00 rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e18); rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":5.00}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); // 5.55 rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e18 + 5e17 + 5e16); rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":5.55}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); // 55.55 rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e19 + 5e18 + 5e17 + 5e16); rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":55.55}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); // 55.5555 overflow rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e19 + 5e18 + 5e17 + 5e16 + 5e15 + 5e14); rawMetadata = contributorNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669); refMetadata = string(abi.encodePacked( "data:application/json;base64,", EncodeUtils.base64(bytes('{\"name\":\"johndoe.contributor\",\"description\":\"LE7EL contributor\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Contributor\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":55.55}]}')) )); assertTrue(keccak256(bytes(rawMetadata)) == keccak256(bytes(refMetadata))); vm.stopPrank(); } }