// SPDX-License-Identifier: MPL-2.0 pragma solidity ^0.8.17; import {ERC20BurnableMock} from "@openzeppelin/contracts/mocks/ERC20BurnableMock.sol"; import {ERC1155BurnableMock} from "@openzeppelin/contracts/mocks/ERC1155BurnableMock.sol"; import {MockERC20} from "solmate/test/utils/mocks/MockERC20.sol"; import {TestWithDeployments} from "./util/TestWithDeployments.sol"; contract CustomFormula { constructor() {} function expToLevel(uint256 experience) external pure returns (uint256) { return experience / (10**21) + 1; } } contract LevelingResolverTest is TestWithDeployments { uint256 internal constant YEAR = 365 days; 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); vm.stopPrank(); // Register avatar NFT vm.startPrank(user); registerAvatarNFT(user, keccak256("secret"), YEAR, "johndoe"); vm.stopPrank(); } function testDefaultLevel() public { vm.prank(admin); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 1); } function testDifferentLevelsForDefaultFormula() public { ERC20BurnableMock expToken = new ERC20BurnableMock("Avatar experience", "EXP", user, 190000e18); vm.prank(admin); avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setProjectLevelingRules(bytes32,address,address,uint256,bytes4)", avatarBasenode, address(0), address(expToken), 0, bytes4(0) )); (address _formula, address _token, uint256 _tokenId, bytes4 _burnInterface) = resolver.levelingProjects(avatarController.baseNode()); assertTrue(_formula == address(0)); assertTrue(_token == address(expToken)); assertTrue(_tokenId == 0); assertTrue(_burnInterface == bytes4(0)); vm.startPrank(user); expToken.approve(address(resolver), 190000e18); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 999e18) == 999e18); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 1); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 1e18) == 1000e18); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 2); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 189000e18) == 190000e18); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 20); vm.stopPrank(); } function testSolmateERC20AsExperience() public { MockERC20 expToken = new MockERC20("Avatar experience", "EXP", 10); expToken.mint(user, 190000e10); vm.prank(admin); avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setProjectLevelingRules(bytes32,address,address,uint256,bytes4)", avatarBasenode, address(0), address(expToken), 0, bytes4(0x9dc29fac) )); (address _formula, address _token, uint256 _tokenId, bytes4 _burnInterface) = resolver.levelingProjects(avatarController.baseNode()); assertTrue(_formula == address(0)); assertTrue(_token == address(expToken)); assertTrue(_tokenId == 0); assertTrue(_burnInterface == 0x9dc29fac); vm.startPrank(user); expToken.approve(address(resolver), 190000e10); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 999e10) == 999e10); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 1); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 1e10) == 1000e10); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 2); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 189000e10) == 190000e10); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 20); vm.stopPrank(); } function testERC1155AsExperience() public { ERC1155BurnableMock expToken = new ERC1155BurnableMock("https://test.metadata/{id}"); expToken.mint(user, 1, 190000, ""); vm.prank(admin); avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setProjectLevelingRules(bytes32,address,address,uint256,bytes4)", avatarBasenode, address(0), address(expToken), 1, bytes4(0xf5298aca) )); (address _formula, address _token, uint256 _tokenId, bytes4 _burnInterface) = resolver.levelingProjects(avatarController.baseNode()); assertTrue(_formula == address(0)); assertTrue(_token == address(expToken)); assertTrue(_tokenId == 1); assertTrue(_burnInterface == 0xf5298aca); vm.startPrank(user); expToken.setApprovalForAll(address(resolver), true); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 999) == 999); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 1); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 1) == 1000); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 2); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 189000) == 190000); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 20); vm.stopPrank(); } function testCustomLevelingFormula() public { CustomFormula formula = new CustomFormula(); ERC20BurnableMock expToken = new ERC20BurnableMock("Avatar experience", "EXP", user, 190000e18); vm.prank(admin); avatarNFT.setBasenodeResolverSettings(abi.encodeWithSignature( "setProjectLevelingRules(bytes32,address,address,uint256,bytes4)", avatarBasenode, address(formula), address(expToken), 0, bytes4(0) )); (address _formula, address _token, uint256 _tokenId, bytes4 _burnInterface) = resolver.levelingProjects(avatarController.baseNode()); assertTrue(_formula == address(formula)); assertTrue(_token == address(expToken)); assertTrue(_tokenId == 0); assertTrue(_burnInterface == bytes4(0)); vm.startPrank(user); expToken.approve(address(resolver), 190000e18); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 999e18) == 999e18); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 1); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 1e18) == 1000e18); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 2); assertTrue(resolver.advanceToNextLevel(avatarBasenode, nameToAvatarNode("johndoe"), 189000e18) == 190000e18); assertTrue(resolver.level(avatarBasenode, nameToAvatarNode("johndoe")) == 191); vm.stopPrank(); } }