// 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 {AvatarMetadataProxyV1} from "src/nft/AvatarMetadataProxyV1.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 AvatarMetadataTest 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();
AvatarMetadataProxyV1 metadata = new AvatarMetadataProxyV1(crs, avatarController.baseNode());
avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature(
"setProxyConfig(bytes32,address,bytes4,address)",
avatarNFT.baseNode(),
address(avatarNFT),
bytes4(keccak256("tokenURI(uint256,string,string)")),
address(metadata)
));
expToken = new ERC1155BurnableMock("https://test.metadata/{id}");
expToken.mint(user, 1, 190000, "");
avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature(
"setProjectLevelingRules(bytes32,address,address,uint256,bytes4)",
avatarBasenode,
address(0),
address(expToken),
1,
bytes4(0xf5298aca)
));
avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature(
"setText(bytes32,string,string)",
avatarBasenode,
"L7L_REWARDS_DISTRIBUTOR",
string(abi.encode(address(rewarder)))
));
vm.stopPrank();
}
function testMetadataValidness() public {
vm.startPrank(user);
registerAvatarNFT(user, keccak256("secret"), YEAR, "johndoe");
string memory rawMetadata = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
string memory refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image_data\":\"\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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);
registerAvatarNFT(user, keccak256("secret"), YEAR, "johndoe");
expToken.setApprovalForAll(address(resolver), true);
assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 1200) == 1200);
string memory rawMetadata = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
string memory refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image_data\":\"\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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);
registerAvatarNFT(user, keccak256("secret"), YEAR, "johndoe");
resolver.setText(0x4a6c793793ade8d7fdb541a00812644c538b8b37b9262d9c4c659b03d6773518, "L7L_AVATAR_IMAGE", "ipfs://chubaka.jpg");
string memory rawMetadata = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
string memory refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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);
registerAvatarNFT(user, keccak256("secret"), YEAR, "johndoe");
resolver.setText(0x4a6c793793ade8d7fdb541a00812644c538b8b37b9262d9c4c659b03d6773518, "L7L_AVATAR_IMAGE", "ipfs://chubaka.jpg");
// 0.00
rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 0);
string memory rawMetadata = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
string memory refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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 = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.05}]}'))
));
// 0.50
rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e17);
rawMetadata = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"trait_type\":\"Level\",\"value\":1},{\"trait_type\":\"Experience\",\"value\":0},{\"trait_type\":\"L7L claims\",\"value\":0.50}]}'))
));
// 5.00
rewarder.setRewardFor(86745341786912841616557368118532256523691956314975099975829920571153145112669, 5e18);
rawMetadata = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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 = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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 = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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 = avatarNFT.tokenURI(86745341786912841616557368118532256523691956314975099975829920571153145112669);
refMetadata = string(abi.encodePacked(
"data:application/json;base64,",
EncodeUtils.base64(bytes('{\"name\":\"johndoe.avatar\",\"description\":\"LE7EL avatar\",\"image\":\"ipfs://chubaka.jpg\",\"attributes\":[{\"trait_type\":\"Type\",\"value\":\"Avatar\"},{\"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();
}
}