From 3ba30da58ef45205c606c59d04dd63c5882537b5 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Tue, 5 Sep 2023 10:40:53 +0200 Subject: [PATCH 01/16] =?UTF-8?q?=F0=9F=9A=A7=F0=9F=A7=AA=20Startup=20new?= =?UTF-8?q?=20unit=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/FrakTest.sol | 266 ++++++++++ test/minter/Minter.t.sol | 163 ++++-- {test => test_old}/FrkTokenTestHelper.sol | 0 {test => test_old}/README.md | 0 {test => test_old}/UUPSTestHelper.sol | 0 .../gas-usage/ErrorGasUsageTest.sol | 0 .../gas-usage/EventGasUsageTest.sol | 0 .../gas-usage/IsZeroGasUsageTest.sol | 0 .../gas-usage/LoopGasUsageTest.sol | 0 test_old/minter/Minter.t.sol | 477 ++++++++++++++++++ {test => test_old}/reward/Rewarder.pay.t.sol | 0 {test => test_old}/reward/Rewarder.t.sol | 0 .../reward/RewarderTestHelper.sol | 0 .../reward/pool/ContentPool.t.sol | 0 .../tokens/FraktionTokens.t.sol | 0 {test => test_old}/tokens/FrkToken.t.sol | 0 .../wallets/FrakTreasuryWallet.t.sol | 0 .../wallets/MultiVestingWallets.t.sol | 0 18 files changed, 854 insertions(+), 52 deletions(-) create mode 100644 test/FrakTest.sol rename {test => test_old}/FrkTokenTestHelper.sol (100%) rename {test => test_old}/README.md (100%) rename {test => test_old}/UUPSTestHelper.sol (100%) rename {test => test_old}/gas-usage/ErrorGasUsageTest.sol (100%) rename {test => test_old}/gas-usage/EventGasUsageTest.sol (100%) rename {test => test_old}/gas-usage/IsZeroGasUsageTest.sol (100%) rename {test => test_old}/gas-usage/LoopGasUsageTest.sol (100%) create mode 100644 test_old/minter/Minter.t.sol rename {test => test_old}/reward/Rewarder.pay.t.sol (100%) rename {test => test_old}/reward/Rewarder.t.sol (100%) rename {test => test_old}/reward/RewarderTestHelper.sol (100%) rename {test => test_old}/reward/pool/ContentPool.t.sol (100%) rename {test => test_old}/tokens/FraktionTokens.t.sol (100%) rename {test => test_old}/tokens/FrkToken.t.sol (100%) rename {test => test_old}/wallets/FrakTreasuryWallet.t.sol (100%) rename {test => test_old}/wallets/MultiVestingWallets.t.sol (100%) diff --git a/test/FrakTest.sol b/test/FrakTest.sol new file mode 100644 index 0000000..e7e53cd --- /dev/null +++ b/test/FrakTest.sol @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakToken } from "@frak/tokens/FrakToken.sol"; +import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; +import { MultiVestingWallets } from "@frak/wallets/MultiVestingWallets.sol"; +import { VestingWalletFactory } from "@frak/wallets/VestingWalletFactory.sol"; +import { FrakTreasuryWallet } from "@frak/wallets/FrakTreasuryWallet.sol"; +import { ReferralPool } from "@frak/reward/referralPool/ReferralPool.sol"; +import { Minter } from "@frak/minter/Minter.sol"; +import { ContentPool } from "@frak/reward/contentPool/ContentPool.sol"; +import { Rewarder } from "@frak/reward/Rewarder.sol"; +import { FrakRoles } from "@frak/roles/FrakRoles.sol"; +import { PRBTest } from "@prb/test/PRBTest.sol"; +import { ERC1967Proxy } from "openzeppelin/proxy/ERC1967/ERC1967Proxy.sol"; + +/// Testing the frak l2 token +contract FrakTest is PRBTest { + // User accounts + address foundation; + address deployer; + address user; + uint256 userPrivKey; + + // Contracts we will tests + FrakToken frakToken; + MultiVestingWallets multiVestingWallet; + VestingWalletFactory vestingWalletFactory; + FrakTreasuryWallet treasuryWallet; + FraktionTokens fraktionTokens; + Minter minter; + ReferralPool referralPool; + ContentPool contentPool; + Rewarder rewarder; + + function _setupTests() internal { + // Create users + deployer = _newUser("deployer"); + foundation = _newUser("foundation"); + (user, userPrivKey) = _newUserWithPrivKey("user"); + + // Deploy every contract + _deployFrakContracts(); + } + + function _deployFrakContracts() internal { + // Deploy each tokens related contract + address _frkToken = _deployFrkToken(); + address _multiVestingWallet = _deployMultiVestingWallet(_frkToken); + address _vestingWalletFactory = _deployVestingWalletFactory(_multiVestingWallet); + address _treasuryWallet = _deployTreasuryWallet(_frkToken); + + // Grant the roles to the multi vesting wallet & treausry wallet + _grantMultiVestingWalletRoles(_multiVestingWallet, _vestingWalletFactory); + _grantTreasuryWalletWalletRoles(_treasuryWallet, _frkToken); + + // Deploy each contract related to the ecosystem + address _fraktionTokens = _deployFraktionsToken(); + address _minter = _deployMinter(_frkToken, _fraktionTokens, foundation); + address _referralPool = _deployReferralPool(_frkToken); + address _contentPool = _deployContentPool(_frkToken); + address _rewarder = _deployRewarder(_frkToken, _fraktionTokens, _contentPool, _referralPool, foundation); + + // Grant each roles + _grantEcosystemRole(_rewarder, _contentPool, _referralPool, _fraktionTokens, _minter); + + // Save each contracts + frakToken = FrakToken(_frkToken); + multiVestingWallet = MultiVestingWallets(_multiVestingWallet); + vestingWalletFactory = VestingWalletFactory(_vestingWalletFactory); + treasuryWallet = FrakTreasuryWallet(_treasuryWallet); + fraktionTokens = FraktionTokens(_fraktionTokens); + minter = Minter(_minter); + referralPool = ReferralPool(_referralPool); + contentPool = ContentPool(_contentPool); + rewarder = Rewarder(_rewarder); + } + + /* -------------------------------------------------------------------------- */ + /* Tokens related contracts & roles */ + /* -------------------------------------------------------------------------- */ + + /// @dev Deploy the frk token + function _deployFrkToken() private asDeployer returns (address proxy) { + // Deploy the initial frk token + FrakToken implementation = new FrakToken(); + vm.label(address(implementation), "Impl-FrkToken"); + bytes memory initData = abi.encodeCall(FrakToken.initialize, ()); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "FrkToken"); + } + + /// @dev Deploy the multi vesting wallet + function _deployMultiVestingWallet(address _frkToken) private asDeployer returns (address proxy) { + // Deploy the initial multi vesting wallets + MultiVestingWallets implementation = new MultiVestingWallets(); + vm.label(address(implementation), "Impl-MultiVestingWallets"); + bytes memory initData = abi.encodeCall(MultiVestingWallets.initialize, (_frkToken)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "MultiVestingWallets"); + } + + /// @dev Deploy the vesting wallet factory + function _deployVestingWalletFactory(address _multiVestingWallet) private asDeployer returns (address proxy) { + // Deploy the initial vesting wallet factory contract + VestingWalletFactory implementation = new VestingWalletFactory(); + vm.label(address(implementation), "Impl-VestingWalletFactory"); + bytes memory initData = abi.encodeCall(VestingWalletFactory.initialize, (_multiVestingWallet)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "VestingWalletFactory"); + } + + /// @dev Deploy the treasury wallet + function _deployTreasuryWallet(address _frkToken) private asDeployer returns (address proxy) { + // Deploy the initial vesting wallet factory contract + FrakTreasuryWallet implementation = new FrakTreasuryWallet(); + vm.label(address(implementation), "Impl-FrakTreasuryWallet"); + bytes memory initData = abi.encodeCall(FrakTreasuryWallet.initialize, (_frkToken)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "FrakTreasuryWallet"); + } + + /// @dev Grand the required roles to the multi vesting wallet + function _grantMultiVestingWalletRoles(address _proxyAddress, address _vestingWalletFactory) private asDeployer { + // Get the contract + MultiVestingWallets implementation = MultiVestingWallets(_proxyAddress); + implementation.grantRole(FrakRoles.VESTING_MANAGER, _vestingWalletFactory); + } + + /// @dev Grand the required roles to the multi vesting wallet + function _grantTreasuryWalletWalletRoles(address _proxyAddress, address _frkToken) private asDeployer { + // Get the contract + FrakTreasuryWallet implementation = FrakTreasuryWallet(_proxyAddress); + implementation.grantRole(FrakRoles.MINTER, _frkToken); + } + + /* -------------------------------------------------------------------------- */ + /* Ecosystem related contracts & roles */ + /* -------------------------------------------------------------------------- */ + + /// @dev Deploy the fraktion tokens + function _deployFraktionsToken() private asDeployer returns (address proxy) { + // Deploy the initial frk token + FraktionTokens implementation = new FraktionTokens(); + vm.label(address(implementation), "Impl-FraktionTokens"); + bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("https://metadata.frak.id/json/{id.json}")); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "FraktionTokens"); + } + + /// @dev Deploy the minter + function _deployMinter( + address _frkToken, + address _fraktionTokens, + address _foundation + ) + private + asDeployer + returns (address proxy) + { + // Deploy the initial frk token + Minter implementation = new Minter(); + vm.label(address(implementation), "Impl-Minter"); + bytes memory initData = abi.encodeCall(Minter.initialize, (_frkToken, _fraktionTokens, _foundation)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "Minter"); + } + + /// @dev Deploy the referral pool + function _deployReferralPool(address _frkToken) private asDeployer returns (address proxy) { + // Deploy the initial frk token + ReferralPool implementation = new ReferralPool(); + vm.label(address(implementation), "Impl-ReferralPool"); + bytes memory initData = abi.encodeCall(ReferralPool.initialize, (_frkToken)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "ReferralPool"); + } + + /// @dev Deploy the content pool + function _deployContentPool(address _frkToken) private asDeployer returns (address proxy) { + // Deploy the initial frk token + ContentPool implementation = new ContentPool(); + vm.label(address(implementation), "Impl-ContentPool"); + bytes memory initData = abi.encodeCall(ContentPool.initialize, (_frkToken)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "ContentPool"); + } + + /// @dev Deploy the rewarder + function _deployRewarder( + address _frkToken, + address _fraktionToken, + address _contentPool, + address _referralPool, + address _foundation + ) + private + asDeployer + returns (address proxy) + { + // Deploy the initial frk token + Rewarder implementation = new Rewarder(); + vm.label(address(implementation), "Impl-Rewarder"); + bytes memory initData = + abi.encodeCall(Rewarder.initialize, (_frkToken, _fraktionToken, _contentPool, _referralPool, _foundation)); + // Deploy the proxy + proxy = _deployProxy(address(implementation), initData, "Rewarder"); + } + + /// @dev Grant the required roles to the rewarder + function _grantEcosystemRole( + address _rewarder, + address _contentPool, + address _referralPool, + address _fraktionTokens, + address _minter + ) + private + asDeployer + { + // Grant role for the rewarder + ReferralPool(_referralPool).grantRole(FrakRoles.REWARDER, _rewarder); + ContentPool(_contentPool).grantRole(FrakRoles.REWARDER, _rewarder); + + // Grant the callback roles on the content pool to the fraktion tokens + ContentPool(_contentPool).grantRole(FrakRoles.TOKEN_CONTRACT, _fraktionTokens); + + // Grant the mint role to the minter + FraktionTokens(_fraktionTokens).grantRole(FrakRoles.MINTER, _minter); + } + + /* -------------------------------------------------------------------------- */ + /* Utils, to ease the test process */ + /* -------------------------------------------------------------------------- */ + + modifier asDeployer() { + vm.startPrank(deployer); + _; + vm.stopPrank(); + } + + function _newUser(string memory label) internal returns (address addr) { + addr = address(bytes20(keccak256(abi.encode(label)))); + vm.label(addr, label); + } + + function _newUserWithPrivKey(string memory label) internal returns (address addr, uint256 privKey) { + privKey = uint256(keccak256(abi.encode(label))); + addr = vm.addr(privKey); + vm.label(addr, label); + } + + /// @dev Deploy the given proxy + function _deployProxy( + address logic, + bytes memory init, + string memory label + ) + internal + returns (address createdAddress) + { + ERC1967Proxy proxyTemp = new ERC1967Proxy(logic, init); + createdAddress = address(proxyTemp); + vm.label(createdAddress, label); + } +} diff --git a/test/minter/Minter.t.sol b/test/minter/Minter.t.sol index ff883e5..803264c 100644 --- a/test/minter/Minter.t.sol +++ b/test/minter/Minter.t.sol @@ -9,33 +9,19 @@ import { FraktionId } from "@frak/libs/FraktionId.sol"; import { FrakRoles } from "@frak/roles/FrakRoles.sol"; import { Minter } from "@frak/minter/Minter.sol"; import { IMinter } from "@frak/minter/IMinter.sol"; -import { FrkTokenTestHelper } from "../FrkTokenTestHelper.sol"; -import { NotAuthorized, InvalidAddress, BadgeTooLarge, InvalidFraktionType } from "@frak/utils/FrakErrors.sol"; +import { FrakTest } from "../FrakTest.sol"; +import { + NotAuthorized, + InvalidAddress, + ContractPaused, + BadgeTooLarge, + InvalidFraktionType +} from "@frak/utils/FrakErrors.sol"; /// Testing minter contract -contract MinterTest is FrkTokenTestHelper { - FraktionTokens fraktionTokens; - address foundationAddr = address(13); - - address minterAddr; - Minter minter; - +contract MinterTest is FrakTest { function setUp() public { - _setupFrkToken(); - - // Deploy fraktions token - bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("test_url")); - address fraktionProxyAddr = deployContract(address(new FraktionTokens()), initData); - fraktionTokens = FraktionTokens(fraktionProxyAddr); - - // Deploy our minter contract - initData = abi.encodeCall(Minter.initialize, (address(frakToken), fraktionProxyAddr, foundationAddr)); - minterAddr = deployContract(address(new Minter()), initData); - minter = Minter(minterAddr); - - // Grant the minter role to our minter contract - prankDeployer(); - fraktionTokens.grantRole(FrakRoles.MINTER, minterAddr); + _setupTests(); } /* @@ -59,7 +45,13 @@ contract MinterTest is FrkTokenTestHelper { uint256 diamondSupply ) ===== */ - function test_addContent() public prankExecAsDeployer { + function test_addContent() public asDeployer { + minter.addContent(address(1), 1, 1, 1, 1); + } + + function test_fail_addContent_ContractPaused() public asDeployer { + minter.pause(); + vm.expectRevert(ContractPaused.selector); minter.addContent(address(1), 1, 1, 1, 1); } @@ -68,12 +60,12 @@ contract MinterTest is FrkTokenTestHelper { minter.addContent(address(1), 1, 1, 1, 1); } - function test_fail_addContent_InvalidAddress() public prankExecAsDeployer { + function test_fail_addContent_InvalidAddress() public asDeployer { vm.expectRevert(InvalidAddress.selector); minter.addContent(address(0), 1, 1, 1, 1); } - function test_fail_addContent_InvalidSupply() public prankExecAsDeployer { + function test_fail_addContent_InvalidSupply() public asDeployer { vm.expectRevert(IMinter.InvalidSupply.selector); minter.addContent(address(1), 0, 1, 1, 1); @@ -127,10 +119,10 @@ contract MinterTest is FrkTokenTestHelper { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -141,21 +133,46 @@ contract MinterTest is FrkTokenTestHelper { (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); // Launch the buy prcess - prankDeployer(); + vm.prank(deployer); minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); // Ensure the supply is good assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); } + function test_fail_mintFraktionForUser_ContractPaused() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + vm.prank(deployer); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + vm.prank(deployer); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + vm.prank(deployer); + minter.pause(); + vm.expectRevert(ContractPaused.selector); + vm.prank(deployer); + minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); + } + function test_fail_mintFraktionForUser_NotAuthorized() public { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -174,10 +191,10 @@ contract MinterTest is FrkTokenTestHelper { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 1, 0, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -189,7 +206,7 @@ contract MinterTest is FrkTokenTestHelper { // Launch the buy prcess vm.expectRevert(FraktionTokens.InsuficiantSupply.selector); - prankDeployer(); + vm.prank(deployer); minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); } @@ -197,10 +214,10 @@ contract MinterTest is FrkTokenTestHelper { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -212,7 +229,7 @@ contract MinterTest is FrkTokenTestHelper { // Launch the buy prcess vm.expectRevert(InvalidFraktionType.selector); - prankDeployer(); + vm.prank(deployer); minter.mintFraktionForUser(contentId.freeFraktionId(), user, block.timestamp, v, r, s); } @@ -220,10 +237,10 @@ contract MinterTest is FrkTokenTestHelper { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -234,7 +251,7 @@ contract MinterTest is FrkTokenTestHelper { (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost - 1); // Launch the buy prcess - prankDeployer(); + vm.prank(deployer); vm.expectRevert(IFrakToken.InvalidSigner.selector); minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); // Ensure the supply hasn't changed @@ -255,10 +272,10 @@ contract MinterTest is FrkTokenTestHelper { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -276,14 +293,39 @@ contract MinterTest is FrkTokenTestHelper { assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); } + function test_fail_mintFraktion_ContractPaused() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + vm.prank(deployer); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + vm.prank(deployer); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + vm.prank(deployer); + minter.pause(); + vm.expectRevert(ContractPaused.selector); + vm.prank(user); + minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); + } + function test_fail_mintFraktion_TooManyFraktion() public { uint256 privateKey = 0xACAB; address user = vm.addr(privateKey); // Add an initial content - prankDeployer(); + vm.prank(deployer); ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); // Mint some token to our user - prankDeployer(); + vm.prank(deployer); frakToken.mint(user, 500 ether); // Get the cost of the buy process @@ -312,20 +354,31 @@ contract MinterTest is FrkTokenTestHelper { address to ) ===== */ - function test_mintFreeFraktionForUser() public prankExecAsDeployer { + function test_mintFreeFraktionForUser() public asDeployer { // Add an initial content ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); } - function test_fail_mintFreeFraktionForUser_ExpectingOnlyFreeFraktion() public prankExecAsDeployer { + function test_fail_mintFreeFraktionForUser_ContractPaused() public asDeployer { + minter.pause(); + vm.expectRevert(ContractPaused.selector); + minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); + } + + function test_fail_mintFreeFraktionForUser_NotAuthorized() public { + vm.expectRevert(NotAuthorized.selector); + minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); + } + + function test_fail_mintFreeFraktionForUser_ExpectingOnlyFreeFraktion() public asDeployer { // Add an initial content ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); minter.mintFreeFraktionForUser(contentId.commonFraktionId(), address(1)); } - function test_fail_mintFreeFraktionForUser_AlreadyHaveFreeFraktion() public prankExecAsDeployer { + function test_fail_mintFreeFraktionForUser_AlreadyHaveFreeFraktion() public asDeployer { // Add an initial content ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); @@ -336,19 +389,25 @@ contract MinterTest is FrkTokenTestHelper { /* * ===== TEST : increaseSupply(uint256 id, uint256 newSupply) ===== */ - function test_increaseSupply() public prankExecAsDeployer { + function test_increaseSupply() public asDeployer { // Add an initial content ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); // Increase it's diamond supply minter.increaseSupply(contentId.diamondFraktionId(), 1); } + function test_fail_increaseSupply_ContractPaused() public asDeployer { + minter.pause(); + vm.expectRevert(ContractPaused.selector); + minter.increaseSupply(FraktionId.wrap(1), 1); + } + function test_fail_increaseSupply_NotAuthorized() public { vm.expectRevert(NotAuthorized.selector); minter.increaseSupply(FraktionId.wrap(1), 1); } - function test_fail_increaseSupply_SupplyUpdateNotAllowed() public prankExecAsDeployer { + function test_fail_increaseSupply_SupplyUpdateNotAllowed() public asDeployer { // Add an initial content ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); // Revert cause of free fraktion @@ -359,7 +418,7 @@ contract MinterTest is FrkTokenTestHelper { minter.increaseSupply(contentId.creatorFraktionId(), 1); } - function test_fail_increaseSupply_RemainingSupply() public prankExecAsDeployer { + function test_fail_increaseSupply_RemainingSupply() public asDeployer { // Add an initial content ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); // Revert cause of free fraktion @@ -370,7 +429,7 @@ contract MinterTest is FrkTokenTestHelper { /* * ===== TEST : multicall(bytes[] calldata data) ===== */ - function test_multicall() public prankExecAsDeployer { + function test_multicall() public asDeployer { // Build our calldata bytes[] memory callingData = new bytes[](5); callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); diff --git a/test/FrkTokenTestHelper.sol b/test_old/FrkTokenTestHelper.sol similarity index 100% rename from test/FrkTokenTestHelper.sol rename to test_old/FrkTokenTestHelper.sol diff --git a/test/README.md b/test_old/README.md similarity index 100% rename from test/README.md rename to test_old/README.md diff --git a/test/UUPSTestHelper.sol b/test_old/UUPSTestHelper.sol similarity index 100% rename from test/UUPSTestHelper.sol rename to test_old/UUPSTestHelper.sol diff --git a/test/gas-usage/ErrorGasUsageTest.sol b/test_old/gas-usage/ErrorGasUsageTest.sol similarity index 100% rename from test/gas-usage/ErrorGasUsageTest.sol rename to test_old/gas-usage/ErrorGasUsageTest.sol diff --git a/test/gas-usage/EventGasUsageTest.sol b/test_old/gas-usage/EventGasUsageTest.sol similarity index 100% rename from test/gas-usage/EventGasUsageTest.sol rename to test_old/gas-usage/EventGasUsageTest.sol diff --git a/test/gas-usage/IsZeroGasUsageTest.sol b/test_old/gas-usage/IsZeroGasUsageTest.sol similarity index 100% rename from test/gas-usage/IsZeroGasUsageTest.sol rename to test_old/gas-usage/IsZeroGasUsageTest.sol diff --git a/test/gas-usage/LoopGasUsageTest.sol b/test_old/gas-usage/LoopGasUsageTest.sol similarity index 100% rename from test/gas-usage/LoopGasUsageTest.sol rename to test_old/gas-usage/LoopGasUsageTest.sol diff --git a/test_old/minter/Minter.t.sol b/test_old/minter/Minter.t.sol new file mode 100644 index 0000000..2b931d9 --- /dev/null +++ b/test_old/minter/Minter.t.sol @@ -0,0 +1,477 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { NotAuthorized, InvalidAddress, ContractPaused, BadgeTooLarge } from "@frak/utils/FrakErrors.sol"; +import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; +import { FrakToken } from "@frak/tokens/FrakToken.sol"; +import { IFrakToken } from "@frak/tokens/IFrakToken.sol"; +import { ContentId } from "@frak/libs/ContentId.sol"; +import { FraktionId } from "@frak/libs/FraktionId.sol"; +import { FrakRoles } from "@frak/roles/FrakRoles.sol"; +import { Minter } from "@frak/minter/Minter.sol"; +import { IMinter } from "@frak/minter/IMinter.sol"; +import { FrkTokenTestHelper } from "../FrkTokenTestHelper.sol"; +import { + NotAuthorized, + InvalidAddress, + ContractPaused, + BadgeTooLarge, + InvalidFraktionType +} from "@frak/utils/FrakErrors.sol"; + +/// Testing minter contract +contract MinterTest is FrkTokenTestHelper { + FraktionTokens fraktionTokens; + address foundationAddr = address(13); + + address minterAddr; + Minter minter; + + function setUp() public { + _setupFrkToken(); + + // Deploy fraktions token + bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("test_url")); + address fraktionProxyAddr = deployContract(address(new FraktionTokens()), initData); + fraktionTokens = FraktionTokens(fraktionProxyAddr); + + // Deploy our minter contract + initData = abi.encodeCall(Minter.initialize, (address(frakToken), fraktionProxyAddr, foundationAddr)); + minterAddr = deployContract(address(new Minter()), initData); + minter = Minter(minterAddr); + + // Grant the minter role to our minter contract + prankDeployer(); + fraktionTokens.grantRole(FrakRoles.MINTER, minterAddr); + } + + /* + * ===== TEST : initialize( + address frkTokenAddr, + address fraktionTokensAddr, + address foundationAddr + ) ===== + */ + function test_fail_InitTwice() public { + vm.expectRevert("Initializable: contract is already initialized"); + minter.initialize(address(0), address(0), address(0)); + } + + /* + * ===== TEST : addContent( + address contentOwnerAddress, + uint256 commonSupply, + uint256 premiumSupply, + uint256 goldSupply, + uint256 diamondSupply + ) ===== + */ + function test_addContent() public prankExecAsDeployer { + minter.addContent(address(1), 1, 1, 1, 1); + } + + function test_fail_addContent_ContractPaused() public prankExecAsDeployer { + minter.pause(); + vm.expectRevert(ContractPaused.selector); + minter.addContent(address(1), 1, 1, 1, 1); + } + + function test_fail_addContent_NotAuthorized() public { + vm.expectRevert(NotAuthorized.selector); + minter.addContent(address(1), 1, 1, 1, 1); + } + + function test_fail_addContent_InvalidAddress() public prankExecAsDeployer { + vm.expectRevert(InvalidAddress.selector); + minter.addContent(address(0), 1, 1, 1, 1); + } + + function test_fail_addContent_InvalidSupply() public prankExecAsDeployer { + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(address(1), 0, 1, 1, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(address(1), 501, 1, 1, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(address(1), 1, 201, 1, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(address(1), 1, 1, 51, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(address(1), 1, 1, 1, 21); + } + + /* + * ===== TEST : mintFraktionForUser( + uint256 id, + address to, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) ===== + */ + bytes32 constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + /// @dev Get permit signature for the given private key and cost + function _getSignedPermit(uint256 privateKey, uint256 cost) private view returns (uint8 v, bytes32 r, bytes32 s) { + address user = vm.addr(privateKey); + (v, r, s) = vm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + frakToken.getDomainSeperator(), + keccak256( + abi.encode( + PERMIT_TYPEHASH, user, address(minter), cost, frakToken.getNonce(user), block.timestamp + ) + ) + ) + ) + ); + } + + function test_mintFraktionForUser() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + prankDeployer(); + minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); + // Ensure the supply is good + assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); + } + + function test_fail_mintFraktionForUser_ContractPaused() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + prankDeployer(); + minter.pause(); + vm.expectRevert(ContractPaused.selector); + prankDeployer(); + minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); + } + + function test_fail_mintFraktionForUser_NotAuthorized() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + vm.expectRevert(NotAuthorized.selector); + minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); + } + + function test_fail_mintFraktionForUser_InsuficiantSupply() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 1, 0, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.premiumFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + vm.expectRevert(FraktionTokens.InsuficiantSupply.selector); + prankDeployer(); + minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); + } + + function test_fail_mintFraktionForUser_InvalidFraktionType() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + vm.expectRevert(InvalidFraktionType.selector); + prankDeployer(); + minter.mintFraktionForUser(contentId.freeFraktionId(), user, block.timestamp, v, r, s); + } + + function test_fail_mintFractionForUser_InvalidSigner() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost - 1); + + // Launch the buy prcess + prankDeployer(); + vm.expectRevert(IFrakToken.InvalidSigner.selector); + minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); + // Ensure the supply hasn't changed + assertEq(fraktionTokens.supplyOf(fraktionCommonId), 10); + } + + /* + * ===== TEST : mintFraktion( + uint256 id, + uint256 amount, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) ===== + */ + function test_mintFraktion() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + vm.prank(user); + minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); + // Ensure the supply is good + assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); + } + + function test_fail_mintFraktion_ContractPaused() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the buy prcess + prankDeployer(); + minter.pause(); + vm.expectRevert(ContractPaused.selector); + vm.prank(user); + minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); + } + + function test_fail_mintFraktion_TooManyFraktion() public { + uint256 privateKey = 0xACAB; + address user = vm.addr(privateKey); + // Add an initial content + prankDeployer(); + ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); + // Mint some token to our user + prankDeployer(); + frakToken.mint(user, 500 ether); + + // Get the cost of the buy process + FraktionId fraktionCommonId = contentId.commonFraktionId(); + uint256 cost = minter.getCostBadge(fraktionCommonId); + + // Sign the tx for the user + (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); + + // Launch the first buy process + vm.prank(user); + minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); + + // Sign the tx for the user + (v, r, s) = _getSignedPermit(privateKey, cost); + + // Launch the second buy process + vm.expectRevert(IMinter.TooManyFraktion.selector); + vm.prank(user); + minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); + } + + /* + * ===== TEST : mintFreeFraktionForUser( + uint256 id, + address to + ) ===== + */ + function test_mintFreeFraktionForUser() public prankExecAsDeployer { + // Add an initial content + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); + minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); + } + + function test_fail_mintFreeFraktionForUser_ContractPaused() public prankExecAsDeployer { + minter.pause(); + vm.expectRevert(ContractPaused.selector); + minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); + } + + function test_fail_mintFreeFraktionForUser_NotAuthorized() public { + vm.expectRevert(NotAuthorized.selector); + minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); + } + + function test_fail_mintFreeFraktionForUser_ExpectingOnlyFreeFraktion() public prankExecAsDeployer { + // Add an initial content + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); + vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); + minter.mintFreeFraktionForUser(contentId.commonFraktionId(), address(1)); + } + + function test_fail_mintFreeFraktionForUser_AlreadyHaveFreeFraktion() public prankExecAsDeployer { + // Add an initial content + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); + minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); + vm.expectRevert(IMinter.TooManyFraktion.selector); + minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); + } + + /* + * ===== TEST : increaseSupply(uint256 id, uint256 newSupply) ===== + */ + function test_increaseSupply() public prankExecAsDeployer { + // Add an initial content + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); + // Increase it's diamond supply + minter.increaseSupply(contentId.diamondFraktionId(), 1); + } + + function test_fail_increaseSupply_ContractPaused() public prankExecAsDeployer { + minter.pause(); + vm.expectRevert(ContractPaused.selector); + minter.increaseSupply(FraktionId.wrap(1), 1); + } + + function test_fail_increaseSupply_NotAuthorized() public { + vm.expectRevert(NotAuthorized.selector); + minter.increaseSupply(FraktionId.wrap(1), 1); + } + + function test_fail_increaseSupply_SupplyUpdateNotAllowed() public prankExecAsDeployer { + // Add an initial content + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); + // Revert cause of free fraktion + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + minter.increaseSupply(contentId.freeFraktionId(), 1); + // Revert cause of nft id + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + minter.increaseSupply(contentId.creatorFraktionId(), 1); + } + + function test_fail_increaseSupply_RemainingSupply() public prankExecAsDeployer { + // Add an initial content + ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); + // Revert cause of free fraktion + vm.expectRevert(FraktionTokens.RemainingSupply.selector); + minter.increaseSupply(contentId.commonFraktionId(), 1); + } + + /* + * ===== TEST : multicall(bytes[] calldata data) ===== + */ + function test_multicall() public prankExecAsDeployer { + // Build our calldata + bytes[] memory callingData = new bytes[](5); + callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[1] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[2] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[3] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[4] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + + minter.multicall(callingData); + } + + function test_fail_multicall_NotAuthorized() public { + // Build our calldata + bytes[] memory callingData = new bytes[](5); + callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[1] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[2] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[3] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + callingData[4] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); + + vm.expectRevert(NotAuthorized.selector); + minter.multicall(callingData); + } +} diff --git a/test/reward/Rewarder.pay.t.sol b/test_old/reward/Rewarder.pay.t.sol similarity index 100% rename from test/reward/Rewarder.pay.t.sol rename to test_old/reward/Rewarder.pay.t.sol diff --git a/test/reward/Rewarder.t.sol b/test_old/reward/Rewarder.t.sol similarity index 100% rename from test/reward/Rewarder.t.sol rename to test_old/reward/Rewarder.t.sol diff --git a/test/reward/RewarderTestHelper.sol b/test_old/reward/RewarderTestHelper.sol similarity index 100% rename from test/reward/RewarderTestHelper.sol rename to test_old/reward/RewarderTestHelper.sol diff --git a/test/reward/pool/ContentPool.t.sol b/test_old/reward/pool/ContentPool.t.sol similarity index 100% rename from test/reward/pool/ContentPool.t.sol rename to test_old/reward/pool/ContentPool.t.sol diff --git a/test/tokens/FraktionTokens.t.sol b/test_old/tokens/FraktionTokens.t.sol similarity index 100% rename from test/tokens/FraktionTokens.t.sol rename to test_old/tokens/FraktionTokens.t.sol diff --git a/test/tokens/FrkToken.t.sol b/test_old/tokens/FrkToken.t.sol similarity index 100% rename from test/tokens/FrkToken.t.sol rename to test_old/tokens/FrkToken.t.sol diff --git a/test/wallets/FrakTreasuryWallet.t.sol b/test_old/wallets/FrakTreasuryWallet.t.sol similarity index 100% rename from test/wallets/FrakTreasuryWallet.t.sol rename to test_old/wallets/FrakTreasuryWallet.t.sol diff --git a/test/wallets/MultiVestingWallets.t.sol b/test_old/wallets/MultiVestingWallets.t.sol similarity index 100% rename from test/wallets/MultiVestingWallets.t.sol rename to test_old/wallets/MultiVestingWallets.t.sol From e108928442d57f2ee140bb0875149fff594488ba Mon Sep 17 00:00:00 2001 From: KONFeature Date: Tue, 5 Sep 2023 15:07:43 +0200 Subject: [PATCH 02/16] =?UTF-8?q?=F0=9F=A7=AA=20Startup=20new=20FrakToken?= =?UTF-8?q?=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/FrakTest.sol | 18 ++ test/minter/Minter.t.sol | 456 ------------------------------------ test/tokens/FrakToken.t.sol | 66 ++++++ 3 files changed, 84 insertions(+), 456 deletions(-) delete mode 100644 test/minter/Minter.t.sol create mode 100644 test/tokens/FrakToken.t.sol diff --git a/test/FrakTest.sol b/test/FrakTest.sol index e7e53cd..701c823 100644 --- a/test/FrakTest.sol +++ b/test/FrakTest.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GNU GPLv3 pragma solidity 0.8.21; +import { ContentId } from "@frak/libs/ContentId.sol"; import { FrakToken } from "@frak/tokens/FrakToken.sol"; import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; import { MultiVestingWallets } from "@frak/wallets/MultiVestingWallets.sol"; @@ -21,6 +22,10 @@ contract FrakTest is PRBTest { address deployer; address user; uint256 userPrivKey; + address contentOwner; + + // A simple minted content id + ContentId contentId; // Contracts we will tests FrakToken frakToken; @@ -37,6 +42,7 @@ contract FrakTest is PRBTest { // Create users deployer = _newUser("deployer"); foundation = _newUser("foundation"); + contentOwner = _newUser("contentOwner"); (user, userPrivKey) = _newUserWithPrivKey("user"); // Deploy every contract @@ -76,6 +82,12 @@ contract FrakTest is PRBTest { rewarder = Rewarder(_rewarder); } + /// @dev Generate the initial state for the contract + function _generateStates() private asDeployer { + // Mint a simple content + contentId = minter.addContent(contentOwner, 20, 7, 3, 1); + } + /* -------------------------------------------------------------------------- */ /* Tokens related contracts & roles */ /* -------------------------------------------------------------------------- */ @@ -239,6 +251,12 @@ contract FrakTest is PRBTest { vm.stopPrank(); } + modifier withFrk(address _user, uint256 _amount) { + vm.prank(deployer); + frakToken.mint(_user, _amount); + _; + } + function _newUser(string memory label) internal returns (address addr) { addr = address(bytes20(keccak256(abi.encode(label)))); vm.label(addr, label); diff --git a/test/minter/Minter.t.sol b/test/minter/Minter.t.sol deleted file mode 100644 index 803264c..0000000 --- a/test/minter/Minter.t.sol +++ /dev/null @@ -1,456 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { IFrakToken } from "@frak/tokens/IFrakToken.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { FraktionId } from "@frak/libs/FraktionId.sol"; -import { FrakRoles } from "@frak/roles/FrakRoles.sol"; -import { Minter } from "@frak/minter/Minter.sol"; -import { IMinter } from "@frak/minter/IMinter.sol"; -import { FrakTest } from "../FrakTest.sol"; -import { - NotAuthorized, - InvalidAddress, - ContractPaused, - BadgeTooLarge, - InvalidFraktionType -} from "@frak/utils/FrakErrors.sol"; - -/// Testing minter contract -contract MinterTest is FrakTest { - function setUp() public { - _setupTests(); - } - - /* - * ===== TEST : initialize( - address frkTokenAddr, - address fraktionTokensAddr, - address foundationAddr - ) ===== - */ - function test_fail_InitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - minter.initialize(address(0), address(0), address(0)); - } - - /* - * ===== TEST : addContent( - address contentOwnerAddress, - uint256 commonSupply, - uint256 premiumSupply, - uint256 goldSupply, - uint256 diamondSupply - ) ===== - */ - function test_addContent() public asDeployer { - minter.addContent(address(1), 1, 1, 1, 1); - } - - function test_fail_addContent_ContractPaused() public asDeployer { - minter.pause(); - vm.expectRevert(ContractPaused.selector); - minter.addContent(address(1), 1, 1, 1, 1); - } - - function test_fail_addContent_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - minter.addContent(address(1), 1, 1, 1, 1); - } - - function test_fail_addContent_InvalidAddress() public asDeployer { - vm.expectRevert(InvalidAddress.selector); - minter.addContent(address(0), 1, 1, 1, 1); - } - - function test_fail_addContent_InvalidSupply() public asDeployer { - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 0, 1, 1, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 501, 1, 1, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 1, 201, 1, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 1, 1, 51, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 1, 1, 1, 21); - } - - /* - * ===== TEST : mintFraktionForUser( - uint256 id, - address to, - uint256 amount, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) ===== - */ - bytes32 constant PERMIT_TYPEHASH = - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - - /// @dev Get permit signature for the given private key and cost - function _getSignedPermit(uint256 privateKey, uint256 cost) private view returns (uint8 v, bytes32 r, bytes32 s) { - address user = vm.addr(privateKey); - (v, r, s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - frakToken.getDomainSeperator(), - keccak256( - abi.encode( - PERMIT_TYPEHASH, user, address(minter), cost, frakToken.getNonce(user), block.timestamp - ) - ) - ) - ) - ); - } - - function test_mintFraktionForUser() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.prank(deployer); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - // Ensure the supply is good - assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); - assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); - } - - function test_fail_mintFraktionForUser_ContractPaused() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.prank(deployer); - minter.pause(); - vm.expectRevert(ContractPaused.selector); - vm.prank(deployer); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - } - - function test_fail_mintFraktionForUser_NotAuthorized() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.expectRevert(NotAuthorized.selector); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - } - - function test_fail_mintFraktionForUser_InsuficiantSupply() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 1, 0, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.premiumFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.expectRevert(FraktionTokens.InsuficiantSupply.selector); - vm.prank(deployer); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - } - - function test_fail_mintFraktionForUser_InvalidFraktionType() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.expectRevert(InvalidFraktionType.selector); - vm.prank(deployer); - minter.mintFraktionForUser(contentId.freeFraktionId(), user, block.timestamp, v, r, s); - } - - function test_fail_mintFractionForUser_InvalidSigner() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost - 1); - - // Launch the buy prcess - vm.prank(deployer); - vm.expectRevert(IFrakToken.InvalidSigner.selector); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - // Ensure the supply hasn't changed - assertEq(fraktionTokens.supplyOf(fraktionCommonId), 10); - } - - /* - * ===== TEST : mintFraktion( - uint256 id, - uint256 amount, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) ===== - */ - function test_mintFraktion() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - // Ensure the supply is good - assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); - assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); - } - - function test_fail_mintFraktion_ContractPaused() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.prank(deployer); - minter.pause(); - vm.expectRevert(ContractPaused.selector); - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - } - - function test_fail_mintFraktion_TooManyFraktion() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - vm.prank(deployer); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - vm.prank(deployer); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the first buy process - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - - // Sign the tx for the user - (v, r, s) = _getSignedPermit(privateKey, cost); - - // Launch the second buy process - vm.expectRevert(IMinter.TooManyFraktion.selector); - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - } - - /* - * ===== TEST : mintFreeFraktionForUser( - uint256 id, - address to - ) ===== - */ - function test_mintFreeFraktionForUser() public asDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); - } - - function test_fail_mintFreeFraktionForUser_ContractPaused() public asDeployer { - minter.pause(); - vm.expectRevert(ContractPaused.selector); - minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); - } - - function test_fail_mintFreeFraktionForUser_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); - } - - function test_fail_mintFreeFraktionForUser_ExpectingOnlyFreeFraktion() public asDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); - minter.mintFreeFraktionForUser(contentId.commonFraktionId(), address(1)); - } - - function test_fail_mintFreeFraktionForUser_AlreadyHaveFreeFraktion() public asDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); - vm.expectRevert(IMinter.TooManyFraktion.selector); - minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); - } - - /* - * ===== TEST : increaseSupply(uint256 id, uint256 newSupply) ===== - */ - function test_increaseSupply() public asDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); - // Increase it's diamond supply - minter.increaseSupply(contentId.diamondFraktionId(), 1); - } - - function test_fail_increaseSupply_ContractPaused() public asDeployer { - minter.pause(); - vm.expectRevert(ContractPaused.selector); - minter.increaseSupply(FraktionId.wrap(1), 1); - } - - function test_fail_increaseSupply_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - minter.increaseSupply(FraktionId.wrap(1), 1); - } - - function test_fail_increaseSupply_SupplyUpdateNotAllowed() public asDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); - // Revert cause of free fraktion - vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - minter.increaseSupply(contentId.freeFraktionId(), 1); - // Revert cause of nft id - vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - minter.increaseSupply(contentId.creatorFraktionId(), 1); - } - - function test_fail_increaseSupply_RemainingSupply() public asDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); - // Revert cause of free fraktion - vm.expectRevert(FraktionTokens.RemainingSupply.selector); - minter.increaseSupply(contentId.commonFraktionId(), 1); - } - - /* - * ===== TEST : multicall(bytes[] calldata data) ===== - */ - function test_multicall() public asDeployer { - // Build our calldata - bytes[] memory callingData = new bytes[](5); - callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[1] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[2] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[3] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[4] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - - minter.multicall(callingData); - } - - function test_fail_multicall_NotAuthorized() public { - // Build our calldata - bytes[] memory callingData = new bytes[](5); - callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[1] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[2] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[3] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[4] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - - vm.expectRevert(NotAuthorized.selector); - minter.multicall(callingData); - } -} diff --git a/test/tokens/FrakToken.t.sol b/test/tokens/FrakToken.t.sol new file mode 100644 index 0000000..cc15ccc --- /dev/null +++ b/test/tokens/FrakToken.t.sol @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized } from "contracts/utils/FrakErrors.sol"; + +/// @dev Testing custom methods on the FrkToken +contract FrakTokenTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + frakToken.initialize(); + } + + /* -------------------------------------------------------------------------- */ + /* Some global properties test */ + /* -------------------------------------------------------------------------- */ + + function test_name_ok() public { + assertEq(frakToken.name(), "Frak"); + } + + function test_decimals_ok() public { + assertEq(frakToken.decimals(), 18); + } + + function test_symbol_ok() public { + assertEq(frakToken.symbol(), "FRK"); + } + + function test_cap_ok() public { + assertEq(frakToken.cap(), 3_000_000_000 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Burn & mint's test */ + /* -------------------------------------------------------------------------- */ + + function test_mint_ok() public asDeployer { + frakToken.mint(user, 1); + assertEq(frakToken.balanceOf(user), 1); + } + + function test_burn_ok() public withFrk(user, 1) { + vm.prank(user); + frakToken.burn(1); + assertEq(frakToken.balanceOf(user), 0); + } + + function test_mint_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + frakToken.mint(user, 1); + } + + /* -------------------------------------------------------------------------- */ + /* A few invariant's test */ + /* -------------------------------------------------------------------------- */ + + function invariant_cap_lt_supply() public { + assertGt(frakToken.cap(), frakToken.totalSupply()); + } +} From 2769fd19004cf3fe61928a72e97676e621249784 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Tue, 5 Sep 2023 17:59:58 +0200 Subject: [PATCH 03/16] =?UTF-8?q?=F0=9F=A7=AA=20100%=20coverage=20on=20frk?= =?UTF-8?q?=20token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/FrakTest.sol | 16 ++++++++ test/tokens/FrakToken.t.sol | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/test/FrakTest.sol b/test/FrakTest.sol index 701c823..15c05dc 100644 --- a/test/FrakTest.sol +++ b/test/FrakTest.sol @@ -17,6 +17,9 @@ import { ERC1967Proxy } from "openzeppelin/proxy/ERC1967/ERC1967Proxy.sol"; /// Testing the frak l2 token contract FrakTest is PRBTest { + + bytes32 constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + // User accounts address foundation; address deployer; @@ -257,6 +260,19 @@ contract FrakTest is PRBTest { _; } + function _generateUserPermitSignature(address to, uint256 amount, uint256 deadline) internal view returns(uint8, bytes32, bytes32) { + return vm.sign( + userPrivKey, + keccak256( + abi.encodePacked( + "\x19\x01", + frakToken.getDomainSeperator(), + keccak256(abi.encode(PERMIT_TYPEHASH, user, to, amount, frakToken.getNonce(user), deadline)) + ) + ) + ); + } + function _newUser(string memory label) internal returns (address addr) { addr = address(bytes20(keccak256(abi.encode(label)))); vm.label(addr, label); diff --git a/test/tokens/FrakToken.t.sol b/test/tokens/FrakToken.t.sol index cc15ccc..cbbdece 100644 --- a/test/tokens/FrakToken.t.sol +++ b/test/tokens/FrakToken.t.sol @@ -3,6 +3,8 @@ pragma solidity 0.8.21; import { FrakTest } from "../FrakTest.sol"; import { NotAuthorized } from "contracts/utils/FrakErrors.sol"; +import { FrakToken } from "contracts/tokens/FrakToken.sol"; +import { IFrakToken } from "contracts/tokens/IFrakToken.sol"; /// @dev Testing custom methods on the FrkToken contract FrakTokenTest is FrakTest { @@ -10,6 +12,17 @@ contract FrakTokenTest is FrakTest { _setupTests(); } + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeWithSelector(FrakToken.initialize.selector); + address proxyAddress = _deployProxy(address(new FrakToken()), initData, "FrakTokenDeploy"); + frakToken = FrakToken(proxyAddress); + } + /// @dev Can't re-init function test_initialize_InitTwice_ko() public { vm.expectRevert("Initializable: contract is already initialized"); @@ -56,6 +69,69 @@ contract FrakTokenTest is FrakTest { frakToken.mint(user, 1); } + function test_mint_CapExceed_ko() public asDeployer { + // Single shot exceed + vm.expectRevert(IFrakToken.CapExceed.selector); + frakToken.mint(user, 3_000_000_001 ether); + + // Multiple mint then exceed + frakToken.mint(user, 1_000_000_000 ether); + frakToken.mint(user, 1_000_000_000 ether); + frakToken.mint(user, 1_000_000_000 ether); + vm.expectRevert(IFrakToken.CapExceed.selector); + frakToken.mint(user, 1); + } + + /* -------------------------------------------------------------------------- */ + /* Permit test's */ + /* -------------------------------------------------------------------------- */ + + function test_permit_ok() public { + // Generate signature + (uint8 v, bytes32 r, bytes32 s) = _generateUserPermitSignature(contentOwner, 1 ether, block.timestamp); + + // Perform the permit op & ensure it's valid + frakToken.permit(user, contentOwner, 1 ether, block.timestamp, v, r, s); + + assertEq(frakToken.allowance(user, contentOwner), 1 ether); + } + + function test_permit_DelayExpired_ko() public { + // Generate signature + (uint8 v, bytes32 r, bytes32 s) = _generateUserPermitSignature(contentOwner, 1 ether, block.timestamp - 1); + + // Perform the permit op & ensure it's valid + vm.expectRevert(IFrakToken.PermitDelayExpired.selector); + frakToken.permit(user, contentOwner, 1 ether, block.timestamp - 1, v, r, s); + } + + function test_permit_InvalidSigner_ko() public { + // Generate signature + (uint8 v, bytes32 r, bytes32 s) = _generateUserPermitSignature(contentOwner, 1 ether, block.timestamp); + + // Perform the permit op & ensure it's valid + vm.expectRevert(IFrakToken.InvalidSigner.selector); + frakToken.permit(address(1), contentOwner, 1 ether, block.timestamp, v, r, s); + } + + function test_permit_InvalidNonce_ko() public { + // Generate signature + (uint8 v, bytes32 r, bytes32 s) = vm.sign( + userPrivKey, + keccak256( + abi.encodePacked( + "\x19\x01", + frakToken.getDomainSeperator(), + keccak256(abi.encode(PERMIT_TYPEHASH, user, contentOwner, 1 ether, 12345, block.timestamp)) + ) + ) + ); + + // Perform the permit op & ensure it's valid + vm.expectRevert(IFrakToken.InvalidSigner.selector); + frakToken.permit(address(1), contentOwner, 1 ether, block.timestamp, v, r, s); + } + /* -------------------------------------------------------------------------- */ /* A few invariant's test */ /* -------------------------------------------------------------------------- */ From ef50a27b1ac8541ac310e42cf834c2da02a7835d Mon Sep 17 00:00:00 2001 From: KONFeature Date: Tue, 5 Sep 2023 18:33:11 +0200 Subject: [PATCH 04/16] =?UTF-8?q?=F0=9F=A7=AA=20Adding=20a=20few=20fraktio?= =?UTF-8?q?n=20tokens=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 176 +++-------------- contracts/fraktions/FraktionTokens.sol | 26 ++- contracts/libs/ContentId.sol | 7 + contracts/minter/Minter.sol | 6 +- test/FrakTest.sol | 17 +- test/fraktions/FraktionTokens.t.sol | 249 +++++++++++++++++++++++++ test/tokens/FrakToken.t.sol | 4 +- 7 files changed, 315 insertions(+), 170 deletions(-) create mode 100644 test/fraktions/FraktionTokens.t.sol diff --git a/.gas-snapshot b/.gas-snapshot index a23a298..ae50e24 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,148 +1,28 @@ -ContentPoolTest:test_addReward() (gas: 64405) -ContentPoolTest:test_fail_InitTwice() (gas: 15877) -ContentPoolTest:test_fail_addReward_NoReward() (gas: 26653) -ContentPoolTest:test_fail_addReward_NotAuthorized() (gas: 15486) -ContentPoolTest:test_fullProcess() (gas: 195577) -ContentPoolTest:test_transferFraktion() (gas: 852322) -ErrorGasUsageTest:testFail_RevertWithError() (gas: 5419) -ErrorGasUsageTest:testFail_RevertWithErrorAssembly() (gas: 5363) -ErrorGasUsageTest:testFail_RevertWithString() (gas: 5451) -EventGasUsageTest:test_event() (gas: 7243) -EventGasUsageTest:test_eventAssembly() (gas: 7183) -FrakTreasuryWalletTest:testFuzz_multicall(uint256,address,address) (runs: 1000, μ: 168054, ~: 168745) -FrakTreasuryWalletTest:testFuzz_transfer(address,uint96) (runs: 1000, μ: 138771, ~: 138518) -FrakTreasuryWalletTest:testFuzz_transferBatch(address,uint96) (runs: 1000, μ: 140153, ~: 139900) -FrakTreasuryWalletTest:test_fail_initialize_CantInitTwice() (gas: 15876) -FrakTreasuryWalletTest:test_fail_multicall_NotAuthorized() (gas: 18918) -FrakTreasuryWalletTest:test_fail_transferBatch_InvalidArray() (gas: 19492) -FrakTreasuryWalletTest:test_fail_transferBatch_InvalidArray_Empty() (gas: 19242) -FrakTreasuryWalletTest:test_fail_transferBatch_NoReward() (gas: 32178) -FrakTreasuryWalletTest:test_fail_transferBatch_NotEnoughTreasury() (gas: 11316347) -FrakTreasuryWalletTest:test_fail_transferBatch_NotMinter() (gas: 16505) -FrakTreasuryWalletTest:test_fail_transferBatch_RewardTooLarge() (gas: 32137) -FrakTreasuryWalletTest:test_fail_transfer_InvalidAddress() (gas: 18383) -FrakTreasuryWalletTest:test_fail_transfer_NoReward() (gas: 18433) -FrakTreasuryWalletTest:test_fail_transfer_NotEnoughTreasury() (gas: 11315342) -FrakTreasuryWalletTest:test_fail_transfer_NotMinter() (gas: 15556) -FrakTreasuryWalletTest:test_fail_transfer_RewardTooLarge() (gas: 18458) -FrakTreasuryWalletTest:test_multicall() (gas: 141742) -FrakTreasuryWalletTest:test_transfer() (gas: 136114) -FrakTreasuryWalletTest:test_transferBatch() (gas: 137456) -FraktionTokensTest:test_fail_initialize_CantInitTwice() (gas: 16030) -FraktionTokensTest:test_fail_mintNewContent_InvalidAddress() (gas: 119373) -FraktionTokensTest:test_fail_mintNewContent_NotAuthorized() (gas: 21031) -FraktionTokensTest:test_fail_mint_InvalidAddress() (gas: 18672) -FraktionTokensTest:test_fail_mint_NotAuthorized() (gas: 15570) -FraktionTokensTest:test_mint() (gas: 47510) -FraktionTokensTest:test_mintNewContent() (gas: 150436) -FraktionTokensTest:test_transfer() (gas: 110896) -FrkTokenL2Test:invariant_metadata() (runs: 256, calls: 3840, reverts: 3249) -FrkTokenL2Test:invariant_supplyCap() (runs: 256, calls: 3840, reverts: 3267) -FrkTokenL2Test:testFuzz_mint(uint256) (runs: 1000, μ: 63524, ~: 66390) -FrkTokenL2Test:testFuzz_transfer(address,uint256) (runs: 1000, μ: 71077, ~: 74421) -FrkTokenL2Test:test_approve_increase_decrease() (gas: 49277) -FrkTokenL2Test:test_balanceOf() (gas: 53882) -FrkTokenL2Test:test_decimals() (gas: 10426) -FrkTokenL2Test:test_fail_approve_InvalidAddress() (gas: 13584) -FrkTokenL2Test:test_fail_decreaseAllowance_BelowZero() (gas: 15859) -FrkTokenL2Test:test_fail_increaseAllowance_InvalidAddress() (gas: 15985) -FrkTokenL2Test:test_fail_initialize_CantInitTwice() (gas: 15803) -FrkTokenL2Test:test_fail_mint_Addr0() (gas: 20782) -FrkTokenL2Test:test_fail_mint_NotMinter() (gas: 15582) -FrkTokenL2Test:test_fail_mint_TooLarge() (gas: 20619) -FrkTokenL2Test:test_fail_permit_InvalidAddress() (gas: 44471) -FrkTokenL2Test:test_fail_permit_InvalidSigner() (gas: 44261) -FrkTokenL2Test:test_fail_permit_PermitDelayExpired() (gas: 18484) -FrkTokenL2Test:test_fail_transfer_InvalidAddress() (gas: 66386) -FrkTokenL2Test:test_fail_transfer_NotEnoughBalance() (gas: 66578) -FrkTokenL2Test:test_name() (gas: 14755) -FrkTokenL2Test:test_permit() (gas: 69802) -FrkTokenL2Test:test_symbol() (gas: 14818) -FrkTokenL2Test:test_totalSupply() (gas: 53367) -FrkTokenL2Test:test_transfer() (gas: 80641) -FrkTokenL2Test:test_transferFrom(uint256) (runs: 1000, μ: 88699, ~: 92388) -IsZeroGasUsageTest:test_isZero() (gas: 5440) -IsZeroGasUsageTest:test_isZeroAssembly() (gas: 5419) -LoopUsageTest:test() (gas: 15621) -MinterTest:test_addContent() (gas: 296808) -MinterTest:test_fail_InitTwice() (gas: 16094) -MinterTest:test_fail_addContent_InvalidAddress() (gas: 18556) -MinterTest:test_fail_addContent_InvalidSupply() (gas: 53015) -MinterTest:test_fail_addContent_NotAuthorized() (gas: 15676) -MinterTest:test_fail_increaseSupply_NotAuthorized() (gas: 15536) -MinterTest:test_fail_increaseSupply_RemainingSupply() (gas: 280511) -MinterTest:test_fail_increaseSupply_SupplyUpdateNotAllowed() (gas: 283704) -MinterTest:test_fail_mintFractionForUser_InvalidSigner() (gas: 407877) -MinterTest:test_fail_mintFraktionForUser_InsuficiantSupply() (gas: 441718) -MinterTest:test_fail_mintFraktionForUser_InvalidFraktionType() (gas: 376812) -MinterTest:test_fail_mintFraktionForUser_NotAuthorized() (gas: 372325) -MinterTest:test_fail_mintFraktion_TooManyFraktion() (gas: 473955) -MinterTest:test_fail_mintFreeFraktionForUser_AlreadyHaveFreeFraktion() (gas: 332504) -MinterTest:test_fail_mintFreeFraktionForUser_ExpectingOnlyFreeFraktion() (gas: 298538) -MinterTest:test_fail_multicall_NotAuthorized() (gas: 22797) -MinterTest:test_increaseSupply() (gas: 301725) -MinterTest:test_mintFraktion() (gas: 471137) -MinterTest:test_mintFraktionForUser() (gas: 471669) -MinterTest:test_mintFreeFraktionForUser() (gas: 329243) -MinterTest:test_multicall() (gas: 1264245) -MultiVestingWalletsTest:test_availableReserve() (gas: 86521) -MultiVestingWalletsTest:test_createVest() (gas: 208875) -MultiVestingWalletsTest:test_createVestBatch() (gas: 210260) -MultiVestingWalletsTest:test_decimals() (gas: 10436) -MultiVestingWalletsTest:test_fail_TransferAvailableReserve_NoReserve() (gas: 30521) -MultiVestingWalletsTest:test_fail_createVestBatch_ArrayInvalidLength() (gas: 81038) -MultiVestingWalletsTest:test_fail_createVestBatch_EmptyArray() (gas: 80888) -MultiVestingWalletsTest:test_fail_createVestBatch_NotEnoughReserve() (gas: 85016) -MultiVestingWalletsTest:test_fail_createVestBatch_NotManager() (gas: 80480) -MultiVestingWalletsTest:test_fail_createVest_InvalidAddress() (gas: 83968) -MultiVestingWalletsTest:test_fail_createVest_InvalidDuration() (gas: 80380) -MultiVestingWalletsTest:test_fail_createVest_InvalidReward() (gas: 84034) -MultiVestingWalletsTest:test_fail_createVest_InvalidStartDate() (gas: 80472) -MultiVestingWalletsTest:test_fail_createVest_InvalidStartDateTooFar() (gas: 80344) -MultiVestingWalletsTest:test_fail_createVest_NotEnoughReserve() (gas: 83919) -MultiVestingWalletsTest:test_fail_createVest_NotManager() (gas: 79535) -MultiVestingWalletsTest:test_fail_createVest_TooLargeReward() (gas: 84038) -MultiVestingWalletsTest:test_fail_initialize_CantInitTwice() (gas: 15921) -MultiVestingWalletsTest:test_fail_transferAvailableReserve_NotAdmin() (gas: 79166) -MultiVestingWalletsTest:test_name() (gas: 12042) -MultiVestingWalletsTest:test_symbol() (gas: 12117) -MultiVestingWalletsTest:test_transfer() (gas: 222147) -MultiVestingWalletsTest:test_transferAvailableReserve() (gas: 92607) -RewarderPayTest:testFuzz_payUser(uint16) (runs: 1000, μ: 197737, ~: 197975) -RewarderPayTest:testFuzz_payUser_WithFraktions(uint16) (runs: 1000, μ: 795713, ~: 795965) -RewarderPayTest:testFuzz_payUser_WithFraktionsAndLoadOfState(uint16) (runs: 1000, μ: 3059764, ~: 3060014) -RewarderPayTest:testFuzz_payUser_WithFraktions_ClaimRewards(uint16) (runs: 1000, μ: 853019, ~: 853265) -RewarderPayTest:test_fail_payCreatorDirectlyBatch_EmptyAmount() (gas: 83232) -RewarderPayTest:test_fail_payCreatorDirectlyBatch_InvalidArray() (gas: 81614) -RewarderPayTest:test_fail_payCreatorDirectlyBatch_InvalidRole() (gas: 82221) -RewarderPayTest:test_fail_payCreatorDirectlyBatch_TooLargeAmount() (gas: 83222) -RewarderPayTest:test_fail_payCreatorDirectlyBatch_TooLargeArray() (gas: 84957) -RewarderPayTest:test_fail_payUserDirectly_InvalidAddress() (gas: 79988) -RewarderPayTest:test_fail_payUserDirectly_InvalidReward() (gas: 80000) -RewarderPayTest:test_fail_payUserDirectly_InvalidRole() (gas: 79128) -RewarderPayTest:test_fail_payUserDirectly_NotEnoughBalance() (gas: 105642) -RewarderPayTest:test_fail_payUserDirectly_TooLargeReward() (gas: 79979) -RewarderPayTest:test_fail_payUser_ArrayNotSameSize() (gas: 81808) -RewarderPayTest:test_fail_payUser_InexistantContent() (gas: 116627) -RewarderPayTest:test_fail_payUser_NotRewarder() (gas: 82640) -RewarderPayTest:test_fail_payUser_TooLargeArray() (gas: 85173) -RewarderPayTest:test_payCreatorDirectlyBatch() (gas: 141268) -RewarderPayTest:test_payUser() (gas: 188032) -RewarderPayTest:test_payUserDirectly() (gas: 109573) -RewarderPayTest:test_payUser_ContentTypeImpactReward() (gas: 251668) -RewarderPayTest:test_payUser_LargeReward() (gas: 791337) -RewarderPayTest:test_payUser_NoReward_ContentTypeNotKnown() (gas: 120012) -RewarderTest:test_fail_InitTwice() (gas: 16240) -RewarderTest:test_fail_multicall_NotAuthorized() (gas: 166063) -RewarderTest:test_fail_updateContentBadge_BadgeCapReached() (gas: 163767) -RewarderTest:test_fail_updateContentBadge_NotAuthorized() (gas: 163378) -RewarderTest:test_fail_updateListenerBadge_BadgeCapReached() (gas: 18481) -RewarderTest:test_fail_updateListenerBadge_NotAuthorized() (gas: 15626) -RewarderTest:test_fail_updateTpu_NotAuthorized() (gas: 15445) -RewarderTest:test_multicall_emptyData() (gas: 16590) -RewarderTest:test_multicall_multipleData() (gas: 320966) -RewarderTest:test_multicall_reallyLargeData() (gas: 7057607) -RewarderTest:test_multicall_singleData() (gas: 190159) -RewarderTest:test_updateContentBadge() (gas: 188492) -RewarderTest:test_updateListenerBadge() (gas: 43231) -RewarderTest:test_updateTpu() (gas: 21344) \ No newline at end of file +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3593) +FrakTokenTest:test_burn_ok() (gas: 53287) +FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) +FrakTokenTest:test_cap_ok() (gas: 10366) +FrakTokenTest:test_decimals_ok() (gas: 10426) +FrakTokenTest:test_initialize_InitTwice_ko() (gas: 15759) +FrakTokenTest:test_mint_CapExceed_ko() (gas: 88106) +FrakTokenTest:test_mint_InvalidRole_ko() (gas: 17639) +FrakTokenTest:test_mint_ok() (gas: 68154) +FrakTokenTest:test_name_ok() (gas: 14776) +FrakTokenTest:test_permit_DelayExpired_ko() (gas: 28091) +FrakTokenTest:test_permit_InvalidNonce_ko() (gas: 50226) +FrakTokenTest:test_permit_InvalidSigner_ko() (gas: 53835) +FrakTokenTest:test_permit_ok() (gas: 77672) +FrakTokenTest:test_symbol_ok() (gas: 14797) +FraktionTokensTest:test_addContent_InvalidArray_ko() (gas: 22829) +FraktionTokensTest:test_addContent_InvalidRole_ko() (gas: 20006) +FraktionTokensTest:test_addContent_SupplyUpdateNotAllowed_ko() (gas: 73756) +FraktionTokensTest:test_addContent_ok() (gas: 553828) +FraktionTokensTest:test_batchBalance_ok() (gas: 61905) +FraktionTokensTest:test_burn_ok() (gas: 51260) +FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3412820) +FraktionTokensTest:test_initialize_InitTwice_ko() (gas: 15986) +FraktionTokensTest:test_ownerOf_ok() (gas: 16844) +FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 55458) +FraktionTokensTest:test_supply_SupplyRemaining_ko() (gas: 22701) +FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45918) +FraktionTokensTest:test_supply_ok() (gas: 90129) \ No newline at end of file diff --git a/contracts/fraktions/FraktionTokens.sol b/contracts/fraktions/FraktionTokens.sol index 12515aa..0dd11e9 100644 --- a/contracts/fraktions/FraktionTokens.sol +++ b/contracts/fraktions/FraktionTokens.sol @@ -13,6 +13,10 @@ import { InvalidArray } from "../utils/FrakErrors.sol"; /// @author @KONFeature /// @title FraktionTokens /// @notice ERC1155 for the Frak Fraktions tokens, used as ownership proof for a content, or investisment proof +/// TODO: Global overview : +/// - remove storage dependency for owner (using balanceOf and building content owner fraktion) +/// - remove storage dependency for is supply aware (every fraktion type between 3 to 6 is supply aware) +/// - mint content, Single array as param with byte shifting :|supplies|fraktionType| /// @custom:security-contact contact@frak.id contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /* -------------------------------------------------------------------------- */ @@ -69,13 +73,13 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { FraktionTransferCallback private transferCallback; /// @dev Id of content to owner of this content - mapping(uint256 => address) private owners; + mapping(uint256 id => address owner) private owners; /// @dev Available supply of each fraktion (classic, rare, epic and legendary only) by they id - mapping(uint256 => uint256) private _availableSupplies; + mapping(uint256 id => uint256 availableSupply) private _availableSupplies; /// @dev Tell us if that fraktion is supply aware or not - mapping(uint256 => bool) private _isSupplyAware; + mapping(uint256 id => bool isSupplyAware) private _isSupplyAware; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -95,7 +99,6 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /** * @dev Mint a new content, return the id of the built content - * We will store in memory -from 0x0 to 0x40 -> */ function mintNewContent( address ownerAddress, @@ -187,13 +190,8 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /** * @dev Set the supply for the given fraktion id */ - function setSupply(uint256 id, uint256 supply) external payable onlyRole(FrakRoles.MINTER) { + function setSupply(FraktionId id, uint256 supply) external payable onlyRole(FrakRoles.MINTER) { assembly { - // Ensure we got valid data - if iszero(supply) { - mstore(0x00, _INVALID_ARRAY_SELECTOR) - revert(0x1c, 0x04) - } // Ensure the supply update of this fraktion type is allowed let fraktionType := and(id, 0xF) if or(lt(fraktionType, 3), gt(fraktionType, 6)) { @@ -231,13 +229,13 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { } /// @dev Mint a new fraktion of a nft - function mint(address to, uint256 id, uint256 amount) external payable onlyRole(FrakRoles.MINTER) { - _mint(to, id, amount, ""); + function mint(address to, FraktionId id, uint256 amount) external payable onlyRole(FrakRoles.MINTER) { + _mint(to, FraktionId.unwrap(id), amount, ""); } /// @dev Burn a fraktion of a nft - function burn(uint256 id, uint256 amount) external payable { - _burn(msg.sender, id, amount); + function burn(FraktionId id, uint256 amount) external payable { + _burn(msg.sender, FraktionId.unwrap(id), amount); } /* -------------------------------------------------------------------------- */ diff --git a/contracts/libs/ContentId.sol b/contracts/libs/ContentId.sol index 41c9ac9..93a8873 100644 --- a/contracts/libs/ContentId.sol +++ b/contracts/libs/ContentId.sol @@ -40,6 +40,13 @@ library ContentIdLib { /* Helper method's */ /* -------------------------------------------------------------------------- */ + /// @dev Build a fraktion id from a content id + function toFraktionId(ContentId self, uint256 fraktionType) internal pure returns (FraktionId id) { + assembly { + id := or(shl(ID_OFFSET, self), fraktionType) + } + } + /// @dev Build the id for a creator NFT id function creatorFraktionId(ContentId self) internal pure returns (FraktionId id) { assembly { diff --git a/contracts/minter/Minter.sol b/contracts/minter/Minter.sol index b4924e0..ff75129 100644 --- a/contracts/minter/Minter.sol +++ b/contracts/minter/Minter.sol @@ -246,7 +246,7 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu */ function increaseSupply(FraktionId id, uint256 newSupply) external onlyRole(FrakRoles.MINTER) { // Update the supply - fraktionTokens.setSupply(FraktionId.unwrap(id), newSupply); + fraktionTokens.setSupply(id, newSupply); } /** @@ -294,7 +294,7 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu // Transfer the tokens address(frakToken).safeTransferFrom(to, foundationWallet, cost); // Mint his fraktion - fraktionTokens.mint(to, FraktionId.unwrap(id), 1); + fraktionTokens.mint(to, id, 1); } /** @@ -319,6 +319,6 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu } // If we are all good, mint the free fraktion to the user - fraktionTokens.mint(to, FraktionId.unwrap(id), 1); + fraktionTokens.mint(to, id, 1); } } diff --git a/test/FrakTest.sol b/test/FrakTest.sol index 15c05dc..98958bb 100644 --- a/test/FrakTest.sol +++ b/test/FrakTest.sol @@ -17,8 +17,8 @@ import { ERC1967Proxy } from "openzeppelin/proxy/ERC1967/ERC1967Proxy.sol"; /// Testing the frak l2 token contract FrakTest is PRBTest { - - bytes32 constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); // User accounts address foundation; @@ -50,6 +50,9 @@ contract FrakTest is PRBTest { // Deploy every contract _deployFrakContracts(); + + // Generate a few states + _generateStates(); } function _deployFrakContracts() internal { @@ -260,7 +263,15 @@ contract FrakTest is PRBTest { _; } - function _generateUserPermitSignature(address to, uint256 amount, uint256 deadline) internal view returns(uint8, bytes32, bytes32) { + function _generateUserPermitSignature( + address to, + uint256 amount, + uint256 deadline + ) + internal + view + returns (uint8, bytes32, bytes32) + { return vm.sign( userPrivKey, keccak256( diff --git a/test/fraktions/FraktionTokens.t.sol b/test/fraktions/FraktionTokens.t.sol new file mode 100644 index 0000000..c8edfe1 --- /dev/null +++ b/test/fraktions/FraktionTokens.t.sol @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { FraktionTokens } from "contracts/fraktions/FraktionTokens.sol"; +import { FraktionTransferCallback } from "contracts/fraktions/FraktionTransferCallback.sol"; +import { ContentId, ContentIdLib } from "contracts/libs/ContentId.sol"; +import { FraktionId } from "contracts/libs/FraktionId.sol"; + +/// @dev Testing custom methods on the FraktionTokens +contract FraktionTokensTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("https://metadata/url")); + address proxyAddress = _deployProxy(address(new FraktionTokens()), initData, "FraktionTokensDeploy"); + fraktionTokens = FraktionTokens(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + fraktionTokens.initialize("https://metadata/url"); + } + + /* -------------------------------------------------------------------------- */ + /* Content related test */ + /* -------------------------------------------------------------------------- */ + + function test_addContent_ok() public asDeployer { + (uint256[] memory types, uint256[] memory supplies) = _getMintContentParams(); + ContentId contentId = fraktionTokens.mintNewContent(contentOwner, types, supplies); + + // Ensure the content is well created, with valid supply + assertEq(fraktionTokens.ownerOf(contentId), contentOwner); + assertEq(fraktionTokens.supplyOf(contentId.commonFraktionId()), 100); + assertEq(fraktionTokens.supplyOf(contentId.premiumFraktionId()), 50); + assertEq(fraktionTokens.supplyOf(contentId.goldFraktionId()), 25); + assertEq(fraktionTokens.supplyOf(contentId.diamondFraktionId()), 10); + + // Ensure that two content id are not the same + ContentId newContentId = fraktionTokens.mintNewContent(contentOwner, types, supplies); + assertNotEq(ContentId.unwrap(contentId), ContentId.unwrap(newContentId)); + } + + function test_addContent_InvalidRole_ko() public { + (uint256[] memory types, uint256[] memory supplies) = _getMintContentParams(); + + vm.expectRevert(NotAuthorized.selector); + fraktionTokens.mintNewContent(contentOwner, types, supplies); + } + + function test_addContent_InvalidArray_ko() public asDeployer { + (uint256[] memory types,) = _getMintContentParams(); + uint256[] memory supplies = new uint256[](2); + + vm.expectRevert(InvalidArray.selector); + fraktionTokens.mintNewContent(contentOwner, types, supplies); + } + + function test_addContent_SupplyUpdateNotAllowed_ko() public asDeployer { + (uint256[] memory types, uint256[] memory supplies) = _getMintContentParams(); + + types[0] = 0; + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.mintNewContent(contentOwner, types, supplies); + + types[0] = 1; + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.mintNewContent(contentOwner, types, supplies); + + types[0] = 2; + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.mintNewContent(contentOwner, types, supplies); + + types[0] = 7; + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.mintNewContent(contentOwner, types, supplies); + } + + /* -------------------------------------------------------------------------- */ + /* Supply related test's */ + /* -------------------------------------------------------------------------- */ + + function test_supply_ok() public withEmptySupply(contentId.commonFraktionId()) asDeployer { + FraktionId commonFraktion = contentId.commonFraktionId(); + // Ensure we start with a supply at 0 + assertEq(fraktionTokens.supplyOf(commonFraktion), 0); + + // Increase it to one + fraktionTokens.setSupply(commonFraktion, 1); + assertEq(fraktionTokens.supplyOf(commonFraktion), 1); + + // Ensure the fraktion is mintable and the supplies goes back to 0 + fraktionTokens.mint(user, commonFraktion, 1); + assertEq(fraktionTokens.supplyOf(commonFraktion), 0); + } + + function test_supply_InvalidRole_ko() public withEmptySupply(contentId.commonFraktionId()) { + vm.expectRevert(NotAuthorized.selector); + fraktionTokens.setSupply(contentId.commonFraktionId(), 1); + } + + function test_supply_SupplyUpdateNotAllowed_ko() public asDeployer { + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.setSupply(contentId.toFraktionId(0), 1); + + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.setSupply(contentId.toFraktionId(1), 1); + + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.setSupply(contentId.toFraktionId(2), 1); + + vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); + fraktionTokens.setSupply(contentId.toFraktionId(7), 1); + } + + function test_supply_SupplyRemaining_ko() public asDeployer { + vm.expectRevert(FraktionTokens.RemainingSupply.selector); + fraktionTokens.setSupply(contentId.commonFraktionId(), 1); + } + + /* -------------------------------------------------------------------------- */ + /* Burn function */ + /* -------------------------------------------------------------------------- */ + + function test_burn_ok() public { + FraktionId commonFraktion = contentId.commonFraktionId(); + uint256 initialSupply = fraktionTokens.supplyOf(commonFraktion); + vm.prank(deployer); + fraktionTokens.mint(user, commonFraktion, 1); + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktion)), 1); + + // Burn it + vm.prank(user); + fraktionTokens.burn(commonFraktion, 1); + + // Assert the balance is back to 0 + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktion)), 0); + // Assert the supply is back to initial state + assertEq(fraktionTokens.supplyOf(commonFraktion), initialSupply); + } + + /* -------------------------------------------------------------------------- */ + /* Transfer callback's */ + /* -------------------------------------------------------------------------- */ + + function test_setUpTransferCallback_ok() public { + // Setup a bullshit callback + vm.prank(deployer); + fraktionTokens.registerNewCallback(address(1)); + + // Ensure it's locking the payed fraktion transfer (since callback can't be called) + vm.expectRevert(); + vm.prank(deployer); + fraktionTokens.mint(user, contentId.commonFraktionId(), 1); + + // Ensure it's ok for non supply aware fraktion + vm.prank(deployer); + fraktionTokens.mint(user, contentId.freeFraktionId(), 1); + + // Update to a more valid callback + TestFraktionTransferCallback callback = new TestFraktionTransferCallback(); + vm.prank(deployer); + fraktionTokens.registerNewCallback(address(callback)); + + // Ensure it's ok for payed fraktion + vm.prank(deployer); + fraktionTokens.mint(user, contentId.commonFraktionId(), 1); + assertEq(callback.invocationCount(), 1); + + // Ensure it's ok for non payed fraktion, but it doesn't invoke the callback + vm.prank(deployer); + fraktionTokens.mint(user, contentId.freeFraktionId(), 1); + assertEq(callback.invocationCount(), 1); + } + + /* -------------------------------------------------------------------------- */ + /* Test view function */ + /* -------------------------------------------------------------------------- */ + + function test_batchBalance_ok() public { + FraktionId commonFraktion = contentId.commonFraktionId(); + + // Mint a fraktion to our user + vm.prank(deployer); + fraktionTokens.mint(user, commonFraktion, 1); + + // Get the balance directly + uint256 directBalance = fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktion)); + + // Get the balance via a batch fetch + FraktionId[] memory idsToQuery = new FraktionId[](1); + idsToQuery[0] = commonFraktion; + + // Get the balances + uint256[] memory balances = fraktionTokens.balanceOfIdsBatch(user, idsToQuery); + assertEq(balances[0], directBalance); + } + + function test_ownerOf_ok() public { + assertEq(fraktionTokens.ownerOf(contentId), contentOwner); + } + + /* -------------------------------------------------------------------------- */ + /* Some helper's */ + /* -------------------------------------------------------------------------- */ + + function _getMintContentParams() internal pure returns (uint256[] memory types, uint256[] memory supplies) { + // Build the array of types (payable fraktion type) + types = new uint256[](4); + types[0] = ContentIdLib.FRAKTION_TYPE_COMMON; + types[1] = ContentIdLib.FRAKTION_TYPE_PREMIUM; + types[2] = ContentIdLib.FRAKTION_TYPE_GOLD; + types[3] = ContentIdLib.FRAKTION_TYPE_DIAMOND; + + // Build the array of supplies + supplies = new uint256[](4); + supplies[0] = 100; + supplies[1] = 50; + supplies[2] = 25; + supplies[3] = 10; + } + + modifier withEmptySupply(FraktionId fraktionId) { + uint256 fraktionSupply = fraktionTokens.supplyOf(fraktionId); + if (fraktionSupply > 0) { + vm.prank(deployer); + fraktionTokens.mint(address(1), fraktionId, fraktionSupply); + } + _; + } +} + +contract TestFraktionTransferCallback is FraktionTransferCallback { + uint256 public invocationCount; + + function onFraktionsTransferred(address, address, FraktionId[] memory, uint256[] memory) external payable { + invocationCount++; + } +} diff --git a/test/tokens/FrakToken.t.sol b/test/tokens/FrakToken.t.sol index cbbdece..8328f82 100644 --- a/test/tokens/FrakToken.t.sol +++ b/test/tokens/FrakToken.t.sol @@ -6,7 +6,7 @@ import { NotAuthorized } from "contracts/utils/FrakErrors.sol"; import { FrakToken } from "contracts/tokens/FrakToken.sol"; import { IFrakToken } from "contracts/tokens/IFrakToken.sol"; -/// @dev Testing custom methods on the FrkToken +/// @dev Testing custom methods on the FrakToken contract FrakTokenTest is FrakTest { function setUp() public { _setupTests(); @@ -122,7 +122,7 @@ contract FrakTokenTest is FrakTest { abi.encodePacked( "\x19\x01", frakToken.getDomainSeperator(), - keccak256(abi.encode(PERMIT_TYPEHASH, user, contentOwner, 1 ether, 12345, block.timestamp)) + keccak256(abi.encode(PERMIT_TYPEHASH, user, contentOwner, 1 ether, 12_345, block.timestamp)) ) ) ); From 6c9f8ac1e14656248295c480bb36bfccd9882d6e Mon Sep 17 00:00:00 2001 From: KONFeature Date: Wed, 6 Sep 2023 12:38:22 +0200 Subject: [PATCH 05/16] =?UTF-8?q?=F0=9F=A7=AA=20Adding=20test=20arround=20?= =?UTF-8?q?the=20minter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 30 ++- contracts/libs/FraktionId.sol | 8 + .../minter/badges/FraktionCostBadges.sol | 5 + test/FrakTest.sol | 10 + test/fraktions/FraktionTokens.t.sol | 9 - test/minter/FraktionCostBadges.t.sol | 78 +++++++ test/minter/Minter.t.sol | 204 ++++++++++++++++++ 7 files changed, 330 insertions(+), 14 deletions(-) create mode 100644 test/minter/FraktionCostBadges.t.sol create mode 100644 test/minter/Minter.t.sol diff --git a/.gas-snapshot b/.gas-snapshot index ae50e24..0ee69d4 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,4 +1,4 @@ -FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3593) +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3637) FrakTokenTest:test_burn_ok() (gas: 53287) FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) FrakTokenTest:test_cap_ok() (gas: 10366) @@ -13,16 +13,36 @@ FrakTokenTest:test_permit_InvalidNonce_ko() (gas: 50226) FrakTokenTest:test_permit_InvalidSigner_ko() (gas: 53835) FrakTokenTest:test_permit_ok() (gas: 77672) FrakTokenTest:test_symbol_ok() (gas: 14797) +FraktionCostBadgesTest:test_defaultPrice_InvalidFraktionType_ko() (gas: 43272) +FraktionCostBadgesTest:test_defaultPrice_ok() (gas: 26214) +FraktionCostBadgesTest:test_updatePrice_InvalidFraktionType_ko() (gas: 46174) +FraktionCostBadgesTest:test_updatePrice_InvalidRole_ko() (gas: 17638) +FraktionCostBadgesTest:test_updatePrice_ok() (gas: 126474) FraktionTokensTest:test_addContent_InvalidArray_ko() (gas: 22829) FraktionTokensTest:test_addContent_InvalidRole_ko() (gas: 20006) FraktionTokensTest:test_addContent_SupplyUpdateNotAllowed_ko() (gas: 73756) FraktionTokensTest:test_addContent_ok() (gas: 553828) FraktionTokensTest:test_batchBalance_ok() (gas: 61905) -FraktionTokensTest:test_burn_ok() (gas: 51260) +FraktionTokensTest:test_burn_ok() (gas: 51278) FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3412820) FraktionTokensTest:test_initialize_InitTwice_ko() (gas: 15986) FraktionTokensTest:test_ownerOf_ok() (gas: 16844) -FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 55458) +FraktionTokensTest:test_setUpTransferCallback_ok() (gas: 373467) +FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 55503) FraktionTokensTest:test_supply_SupplyRemaining_ko() (gas: 22701) -FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45918) -FraktionTokensTest:test_supply_ok() (gas: 90129) \ No newline at end of file +FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45940) +FraktionTokensTest:test_supply_ok() (gas: 90151) +MinterTest:test_addContent_InvalidRole_ko() (gas: 17762) +MinterTest:test_addContent_InvalidSupply_ko() (gas: 55555) +MinterTest:test_addContent_ok() (gas: 306343) +MinterTest:test_canBeDeployedAndInit_ok() (gas: 2171857) +MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 64497) +MinterTest:test_increaseSupply_ok() (gas: 78196) +MinterTest:test_initialize_InitTwice_ko() (gas: 22364) +MinterTest:test_mintFraktionForUser_ok() (gas: 214830) +MinterTest:test_mintFraktion_TooManyFraktion_ko() (gas: 218309) +MinterTest:test_mintFraktion_ok() (gas: 212267) +MinterTest:test_mintFreeFraktionForUser_ok() (gas: 62267) +MinterTest:test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() (gas: 40161) +MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 63135) +MinterTest:test_mintFreeFraktion_ok() (gas: 64993) \ No newline at end of file diff --git a/contracts/libs/FraktionId.sol b/contracts/libs/FraktionId.sol index 37f7c60..ff6e4de 100644 --- a/contracts/libs/FraktionId.sol +++ b/contracts/libs/FraktionId.sol @@ -17,6 +17,14 @@ library FraktionIdLib { /// @dev The mask we use to store the fraktion type in the fraktion id uint256 internal constant TYPE_MASK = 0xF; + /// @dev Get the `contentId` from the `self` fraktion id + function isNotPayable(FraktionId self) internal pure returns (bool notPayable) { + assembly { + let fType := and(self, TYPE_MASK) + notPayable := or(lt(fType, 3), gt(fType, 6)) + } + } + /// @dev Get the `contentId` from the `self` fraktion id function getContentId(FraktionId self) internal pure returns (uint256 contentId) { assembly { diff --git a/contracts/minter/badges/FraktionCostBadges.sol b/contracts/minter/badges/FraktionCostBadges.sol index 2306c97..8a80368 100644 --- a/contracts/minter/badges/FraktionCostBadges.sol +++ b/contracts/minter/badges/FraktionCostBadges.sol @@ -60,6 +60,11 @@ abstract contract FraktionCostBadges { * @param badge The new badge cost of the fraktionId in wei. */ function _updateCostBadge(FraktionId fraktionId, uint96 badge) internal { + // Revert if the fraktion id is not a payable one + if (fraktionId.isNotPayable()) { + revert InvalidFraktionType(); + } + fraktionBadges[fraktionId] = badge; emit FraktionCostBadgeUpdated(FraktionId.unwrap(fraktionId), badge); } diff --git a/test/FrakTest.sol b/test/FrakTest.sol index 98958bb..8387bf4 100644 --- a/test/FrakTest.sol +++ b/test/FrakTest.sol @@ -2,6 +2,7 @@ pragma solidity 0.8.21; import { ContentId } from "@frak/libs/ContentId.sol"; +import { FraktionId } from "@frak/libs/FraktionId.sol"; import { FrakToken } from "@frak/tokens/FrakToken.sol"; import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; import { MultiVestingWallets } from "@frak/wallets/MultiVestingWallets.sol"; @@ -263,6 +264,15 @@ contract FrakTest is PRBTest { _; } + modifier withEmptySupply(FraktionId fraktionId) { + uint256 fraktionSupply = fraktionTokens.supplyOf(fraktionId); + if (fraktionSupply > 0) { + vm.prank(deployer); + fraktionTokens.mint(address(1), fraktionId, fraktionSupply); + } + _; + } + function _generateUserPermitSignature( address to, uint256 amount, diff --git a/test/fraktions/FraktionTokens.t.sol b/test/fraktions/FraktionTokens.t.sol index c8edfe1..313b87b 100644 --- a/test/fraktions/FraktionTokens.t.sol +++ b/test/fraktions/FraktionTokens.t.sol @@ -229,15 +229,6 @@ contract FraktionTokensTest is FrakTest { supplies[2] = 25; supplies[3] = 10; } - - modifier withEmptySupply(FraktionId fraktionId) { - uint256 fraktionSupply = fraktionTokens.supplyOf(fraktionId); - if (fraktionSupply > 0) { - vm.prank(deployer); - fraktionTokens.mint(address(1), fraktionId, fraktionSupply); - } - _; - } } contract TestFraktionTransferCallback is FraktionTransferCallback { diff --git a/test/minter/FraktionCostBadges.t.sol b/test/minter/FraktionCostBadges.t.sol new file mode 100644 index 0000000..3f37edc --- /dev/null +++ b/test/minter/FraktionCostBadges.t.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { InvalidFraktionType, NotAuthorized } from "contracts/utils/FrakErrors.sol"; +import { ContentId, ContentIdLib } from "contracts/libs/ContentId.sol"; +import { FraktionId } from "contracts/libs/FraktionId.sol"; + +/// @dev Testing methods on the FraktionCostBadges +contract FraktionCostBadgesTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Default prices test */ + /* -------------------------------------------------------------------------- */ + + function test_defaultPrice_ok() public { + assertEq(minter.getCostBadge(contentId.commonFraktionId()), 90 ether); + assertEq(minter.getCostBadge(contentId.premiumFraktionId()), 500 ether); + assertEq(minter.getCostBadge(contentId.goldFraktionId()), 1200 ether); + assertEq(minter.getCostBadge(contentId.diamondFraktionId()), 3000 ether); + } + + function test_defaultPrice_InvalidFraktionType_ko() public { + vm.expectRevert(InvalidFraktionType.selector); + minter.getCostBadge(contentId.freeFraktionId()); + + vm.expectRevert(InvalidFraktionType.selector); + minter.getCostBadge(contentId.creatorFraktionId()); + + vm.expectRevert(InvalidFraktionType.selector); + minter.getCostBadge(contentId.toFraktionId(0)); + + vm.expectRevert(InvalidFraktionType.selector); + minter.getCostBadge(contentId.toFraktionId(7)); + } + + /* -------------------------------------------------------------------------- */ + /* Price update */ + /* -------------------------------------------------------------------------- */ + + function test_updatePrice_ok() public { + // Update the badge cost of the specified fraktionId + vm.startPrank(deployer); + minter.updateCostBadge(contentId.commonFraktionId(), 100 ether); + minter.updateCostBadge(contentId.premiumFraktionId(), 600 ether); + minter.updateCostBadge(contentId.goldFraktionId(), 1300 ether); + minter.updateCostBadge(contentId.diamondFraktionId(), 3100 ether); + vm.stopPrank(); + + // Ensure, the badge cost are ok + assertEq(minter.getCostBadge(contentId.commonFraktionId()), 100 ether); + assertEq(minter.getCostBadge(contentId.premiumFraktionId()), 600 ether); + assertEq(minter.getCostBadge(contentId.goldFraktionId()), 1300 ether); + assertEq(minter.getCostBadge(contentId.diamondFraktionId()), 3100 ether); + } + + function test_updatePrice_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + minter.updateCostBadge(contentId.commonFraktionId(), 100 ether); + } + + function test_updatePrice_InvalidFraktionType_ko() public asDeployer { + vm.expectRevert(InvalidFraktionType.selector); + minter.updateCostBadge(contentId.freeFraktionId(), 1); + + vm.expectRevert(InvalidFraktionType.selector); + minter.updateCostBadge(contentId.creatorFraktionId(), 1); + + vm.expectRevert(InvalidFraktionType.selector); + minter.updateCostBadge(contentId.toFraktionId(0), 1); + + vm.expectRevert(InvalidFraktionType.selector); + minter.updateCostBadge(contentId.toFraktionId(7), 1); + } +} diff --git a/test/minter/Minter.t.sol b/test/minter/Minter.t.sol new file mode 100644 index 0000000..8ccc99a --- /dev/null +++ b/test/minter/Minter.t.sol @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { FraktionTokens } from "contracts/fraktions/FraktionTokens.sol"; +import { Minter } from "contracts/minter/Minter.sol"; +import { IMinter } from "contracts/minter/IMinter.sol"; +import { ContentId, ContentIdLib } from "contracts/libs/ContentId.sol"; +import { FraktionId } from "contracts/libs/FraktionId.sol"; + +/// @dev Testing methods on the Minter +contract MinterTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = + abi.encodeCall(Minter.initialize, (address(frakToken), address(fraktionTokens), foundation)); + address proxyAddress = _deployProxy(address(new Minter()), initData, "MinterDeploy"); + minter = Minter(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + minter.initialize(address(frakToken), address(fraktionTokens), foundation); + } + + /* -------------------------------------------------------------------------- */ + /* Add content test's */ + /* -------------------------------------------------------------------------- */ + + function test_addContent_ok() public { + // Can add a new content + vm.prank(deployer); + ContentId newContentId = minter.addContent(contentOwner, 20, 7, 3, 1); + + // Ensure, the content supply are ok + assertEq(fraktionTokens.supplyOf(newContentId.commonFraktionId()), 20); + assertEq(fraktionTokens.supplyOf(newContentId.premiumFraktionId()), 7); + assertEq(fraktionTokens.supplyOf(newContentId.goldFraktionId()), 3); + assertEq(fraktionTokens.supplyOf(newContentId.diamondFraktionId()), 1); + } + + function test_addContent_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + minter.addContent(contentOwner, 20, 7, 3, 1); + } + + function test_addContent_InvalidSupply_ko() public asDeployer { + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(contentOwner, 0, 7, 3, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(contentOwner, 501, 7, 3, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(contentOwner, 20, 201, 3, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(contentOwner, 20, 7, 51, 1); + + vm.expectRevert(IMinter.InvalidSupply.selector); + minter.addContent(contentOwner, 20, 7, 3, 21); + } + + /* -------------------------------------------------------------------------- */ + /* Free fraktion mint */ + /* -------------------------------------------------------------------------- */ + + function test_mintFreeFraktion_ok() public { + FraktionId freeFraktionId = contentId.freeFraktionId(); + + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(freeFraktionId)), 0); + vm.prank(user); + minter.mintFreeFraktion(freeFraktionId); + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(freeFraktionId)), 1); + } + + function test_mintFreeFraktionForUser_ok() public { + FraktionId freeFraktionId = contentId.freeFraktionId(); + + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(freeFraktionId)), 0); + minter.mintFreeFraktionForUser(freeFraktionId, user); + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(freeFraktionId)), 1); + } + + function test_mintFreeFraktion_TooManyFraktion_ko() public { + // Mint initial fraktion + FraktionId freeFraktionId = contentId.freeFraktionId(); + vm.prank(user); + minter.mintFreeFraktion(freeFraktionId); + + vm.expectRevert(IMinter.TooManyFraktion.selector); + vm.prank(user); + minter.mintFreeFraktion(freeFraktionId); + } + + function test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() public { + vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); + minter.mintFreeFraktion(contentId.creatorFraktionId()); + + vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); + minter.mintFreeFraktion(contentId.commonFraktionId()); + + vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); + minter.mintFreeFraktion(contentId.goldFraktionId()); + + vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); + minter.mintFreeFraktion(contentId.premiumFraktionId()); + + vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); + minter.mintFreeFraktion(contentId.diamondFraktionId()); + } + + /* -------------------------------------------------------------------------- */ + /* Payed fraktion mint */ + /* -------------------------------------------------------------------------- */ + + function test_mintFraktion_ok() public withFrk(user, 100 ether) { + FraktionId commonFraktionId = contentId.commonFraktionId(); + // Assert the balance is 0 + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 0); + + // Get the price of the fraktion + uint256 price = minter.getCostBadge(commonFraktionId); + + // Generate the signature + (uint8 v, bytes32 r, bytes32 s) = _generateUserPermitSignature(address(minter), price, block.timestamp); + + // Perform the mint process + vm.prank(user); + minter.mintFraktion(commonFraktionId, block.timestamp, v, r, s); + + // Assert the fraktion was minted to the user + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 1); + } + + function test_mintFraktion_TooManyFraktion_ko() public withFrk(user, 100 ether) { + FraktionId commonFraktionId = contentId.commonFraktionId(); + + // Mint first fraktion + uint256 price = minter.getCostBadge(commonFraktionId); + (uint8 v, bytes32 r, bytes32 s) = _generateUserPermitSignature(address(minter), price, block.timestamp); + vm.prank(user); + minter.mintFraktion(commonFraktionId, block.timestamp, v, r, s); + + // Assert the second mint will fail + (v, r, s) = _generateUserPermitSignature(address(minter), price, block.timestamp); + vm.expectRevert(IMinter.TooManyFraktion.selector); + vm.prank(user); + minter.mintFraktion(commonFraktionId, block.timestamp, v, r, s); + + // Assert the fraktion was minted to the user + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 1); + } + + function test_mintFraktionForUser_ok() public withFrk(user, 100 ether) { + FraktionId commonFraktionId = contentId.commonFraktionId(); + // Assert the balance is 0 + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 0); + + // Get the price of the fraktion + uint256 price = minter.getCostBadge(commonFraktionId); + + // Generate the signature + (uint8 v, bytes32 r, bytes32 s) = _generateUserPermitSignature(address(minter), price, block.timestamp); + + // Perform the mint process + vm.prank(deployer); + minter.mintFraktionForUser(commonFraktionId, user, block.timestamp, v, r, s); + + // Assert the fraktion was minted to the user + assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(commonFraktionId)), 1); + } + + /* -------------------------------------------------------------------------- */ + /* Supply method's */ + /* -------------------------------------------------------------------------- */ + + function test_increaseSupply_ok() public withEmptySupply(contentId.commonFraktionId()) { + // Increase the supply of the common fraktion + FraktionId commonFraktionId = contentId.commonFraktionId(); + vm.prank(deployer); + minter.increaseSupply(commonFraktionId, 1); + + // Assert the supply was increased + assertEq(fraktionTokens.supplyOf(commonFraktionId), 1); + } + + function test_increaseSupply_InvalidRole_ko() public withEmptySupply(contentId.commonFraktionId()) { + // Increase the supply of the common fraktion + FraktionId commonFraktionId = contentId.commonFraktionId(); + vm.expectRevert(NotAuthorized.selector); + minter.increaseSupply(commonFraktionId, 1); + } +} From 4247befbbb223f0b4979d75ac05b1d352559b591 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Wed, 6 Sep 2023 13:59:02 +0200 Subject: [PATCH 06/16] =?UTF-8?q?=F0=9F=94=A8=20Add=20better=20coverage=20?= =?UTF-8?q?viewer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + package.json | 5 ++++- pnpm-lock.yaml | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index dc6a65c..9aebf0c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ mcore_*/ # Coverage report coverage/ coverage.json +lcov.info # Generic contracts exclusions .openzeppelin/unknwon-*.json diff --git a/package.json b/package.json index cab3aab..c34c245 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,14 @@ "test": "pnpm test:forge && pnpm test:storage", "test:forge": "forge test", "test:storage": "npx @openzeppelin/upgrades-core validate out/build-info", - "coverage": "forge coverage --report lcov", + "coverage:report": "forge coverage --report lcov", + "coverage:html": "lcov-viewer lcov -o ./coverage ./lcov.info", + "coverage": "pnpm coverage:report && pnpm coverage:html && open ./coverage/index.html", "generate": "wagmi generate", "generate:react": "wagmi generate -c ./wagmi-react.config.ts" }, "devDependencies": { + "@lcov-viewer/cli": "^1.3.0", "@openzeppelin/upgrades-core": "^1.28.0", "@wagmi/cli": "^1.4.1", "ts-node": "^10.9.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51d814d..4c5dcb7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false devDependencies: + '@lcov-viewer/cli': + specifier: ^1.3.0 + version: 1.3.0 '@openzeppelin/upgrades-core': specifier: ^1.28.0 version: 1.28.0 @@ -245,6 +248,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true + /@lcov-viewer/cli@1.3.0: + resolution: {integrity: sha512-A9altXh2ZyeuagYZsJqVja6WMlgGJGcV+SHOOgIZB+CA2bfk78vgOqrPJrWg+IflFpoEzo1QeqwH4WbKSM4d9A==} + hasBin: true + dependencies: + commander: 9.5.0 + dev: true + /@noble/curves@1.0.0: resolution: {integrity: sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==} dependencies: @@ -733,6 +743,11 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + /compare-versions@6.1.0: resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} dev: true From 1a10c0555763f788667d39d73c186b4a1d5dbdc0 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Wed, 6 Sep 2023 14:52:50 +0200 Subject: [PATCH 07/16] =?UTF-8?q?=F0=9F=A7=AA=20Base=20building=20blocks?= =?UTF-8?q?=20for=20the=20remaining=20contracts=20to=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 28 ++++- script/utils/DeployAllScript.s.sol | 4 +- test/FrakTest.sol | 4 +- test/reward/Rewarder.t.sol | 35 ++++++ test/reward/pools/ContentPool.t.sol | 30 +++++ test/reward/pools/ReferralPool.t.sol | 30 +++++ test/wallets/FrakTeasuryWallet.t.sol | 153 ++++++++++++++++++++++++ test/wallets/MultiVestingWallets.t.sol | 30 +++++ test/wallets/VestingWalletFactory.t.sol | 30 +++++ 9 files changed, 336 insertions(+), 8 deletions(-) create mode 100644 test/reward/Rewarder.t.sol create mode 100644 test/reward/pools/ContentPool.t.sol create mode 100644 test/reward/pools/ReferralPool.t.sol create mode 100644 test/wallets/FrakTeasuryWallet.t.sol create mode 100644 test/wallets/MultiVestingWallets.t.sol create mode 100644 test/wallets/VestingWalletFactory.t.sol diff --git a/.gas-snapshot b/.gas-snapshot index 0ee69d4..c968a0f 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,4 +1,20 @@ -FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3637) +ContentPoolTest:test_canBeDeployedAndInit_ok() (gas: 2820906) +ContentPoolTest:test_initialize_InitTwice_ko() (gas: 17926) +FrakTeasuryWalletTest:test_canBeDeployedAndInit_ok() (gas: 1773426) +FrakTeasuryWalletTest:test_initialize_InitTwice_ko() (gas: 17937) +FrakTeasuryWalletTest:test_transferBatch_InvalidArray_ko() (gas: 28753) +FrakTeasuryWalletTest:test_transferBatch_NoReward_ko() (gas: 34416) +FrakTeasuryWalletTest:test_transferBatch_NotEnoughTreasury_ko() (gas: 11305534) +FrakTeasuryWalletTest:test_transferBatch_NotMinter_ko() (gas: 18928) +FrakTeasuryWalletTest:test_transferBatch_RewardTooLarge_ko() (gas: 34431) +FrakTeasuryWalletTest:test_transferBatch_ok() (gas: 137823) +FrakTeasuryWalletTest:test_transfer_InvalidAddress_ko() (gas: 18375) +FrakTeasuryWalletTest:test_transfer_NoReward_ko() (gas: 20508) +FrakTeasuryWalletTest:test_transfer_NotEnoughTreasury_ko() (gas: 11304244) +FrakTeasuryWalletTest:test_transfer_NotMinter_ko() (gas: 17684) +FrakTeasuryWalletTest:test_transfer_RewardTooLarge_ko() (gas: 20534) +FrakTeasuryWalletTest:test_transfer_ok() (gas: 136061) +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3625) FrakTokenTest:test_burn_ok() (gas: 53287) FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) FrakTokenTest:test_cap_ok() (gas: 10366) @@ -45,4 +61,12 @@ MinterTest:test_mintFraktion_ok() (gas: 212267) MinterTest:test_mintFreeFraktionForUser_ok() (gas: 62267) MinterTest:test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() (gas: 40161) MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 63135) -MinterTest:test_mintFreeFraktion_ok() (gas: 64993) \ No newline at end of file +MinterTest:test_mintFreeFraktion_ok() (gas: 64993) +MultiVestingWalletsTest:test_canBeDeployedAndInit_ok() (gas: 2805268) +MultiVestingWalletsTest:test_initialize_InitTwice_ko() (gas: 17948) +ReferralPoolTest:test_canBeDeployedAndInit_ok() (gas: 1692225) +ReferralPoolTest:test_initialize_InitTwice_ko() (gas: 17881) +RewarderTest:test_canBeDeployedAndInit_ok() (gas: 2600249) +RewarderTest:test_initialize_InitTwice_ko() (gas: 26762) +VestingWalletFactoryTest:test_canBeDeployedAndInit_ok() (gas: 2093328) +VestingWalletFactoryTest:test_initialize_InitTwice_ko() (gas: 17926) \ No newline at end of file diff --git a/script/utils/DeployAllScript.s.sol b/script/utils/DeployAllScript.s.sol index ea101b3..90d4200 100644 --- a/script/utils/DeployAllScript.s.sol +++ b/script/utils/DeployAllScript.s.sol @@ -117,9 +117,7 @@ contract DeployAllScript is UpgradeScript { /// @dev Grand the required roles to the multi vesting wallet function _grantTreasuryWalletWalletRoles(address proxyAddress, address frkToken) private deployerBroadcast { - // Get the contract - FrakTreasuryWallet implementation = FrakTreasuryWallet(proxyAddress); - implementation.grantRole(FrakRoles.MINTER, frkToken); + FrakToken(frkToken).grantRole(FrakRoles.MINTER, proxyAddress); } /* -------------------------------------------------------------------------- */ diff --git a/test/FrakTest.sol b/test/FrakTest.sol index 8387bf4..63f6637 100644 --- a/test/FrakTest.sol +++ b/test/FrakTest.sol @@ -148,9 +148,7 @@ contract FrakTest is PRBTest { /// @dev Grand the required roles to the multi vesting wallet function _grantTreasuryWalletWalletRoles(address _proxyAddress, address _frkToken) private asDeployer { - // Get the contract - FrakTreasuryWallet implementation = FrakTreasuryWallet(_proxyAddress); - implementation.grantRole(FrakRoles.MINTER, _frkToken); + FrakToken(_frkToken).grantRole(FrakRoles.MINTER, _proxyAddress); } /* -------------------------------------------------------------------------- */ diff --git a/test/reward/Rewarder.t.sol b/test/reward/Rewarder.t.sol new file mode 100644 index 0000000..d1a3544 --- /dev/null +++ b/test/reward/Rewarder.t.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { Rewarder } from "contracts/reward/Rewarder.sol"; + +/// @dev Testing methods on the Rewarder +contract RewarderTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall( + Rewarder.initialize, + (address(frakToken), address(fraktionTokens), address(contentPool), address(referralPool), foundation) + ); + address proxyAddress = _deployProxy(address(new Rewarder()), initData, "RewarderDeploy"); + rewarder = Rewarder(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + rewarder.initialize( + address(frakToken), address(fraktionTokens), address(contentPool), address(referralPool), foundation + ); + } +} diff --git a/test/reward/pools/ContentPool.t.sol b/test/reward/pools/ContentPool.t.sol new file mode 100644 index 0000000..fcd7508 --- /dev/null +++ b/test/reward/pools/ContentPool.t.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { ContentPool } from "contracts/reward/contentPool/ContentPool.sol"; + +/// @dev Testing methods on the ContentPool +contract ContentPoolTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall(ContentPool.initialize, (address(frakToken))); + address proxyAddress = _deployProxy(address(new ContentPool()), initData, "ContentPoolDeploy"); + contentPool = ContentPool(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + contentPool.initialize(address(frakToken)); + } +} diff --git a/test/reward/pools/ReferralPool.t.sol b/test/reward/pools/ReferralPool.t.sol new file mode 100644 index 0000000..12d988c --- /dev/null +++ b/test/reward/pools/ReferralPool.t.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { ReferralPool } from "contracts/reward/referralPool/ReferralPool.sol"; + +/// @dev Testing methods on the ReferralPool +contract ReferralPoolTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall(ReferralPool.initialize, (address(frakToken))); + address proxyAddress = _deployProxy(address(new ReferralPool()), initData, "ReferralPoolDeploy"); + referralPool = ReferralPool(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + referralPool.initialize(address(frakToken)); + } +} diff --git a/test/wallets/FrakTeasuryWallet.t.sol b/test/wallets/FrakTeasuryWallet.t.sol new file mode 100644 index 0000000..71730c9 --- /dev/null +++ b/test/wallets/FrakTeasuryWallet.t.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { FrakTreasuryWallet, NotEnoughTreasury } from "contracts/wallets/FrakTreasuryWallet.sol"; + +/// @dev Testing methods on the FrakTeasuryWallet +contract FrakTeasuryWalletTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall(FrakTreasuryWallet.initialize, (address(frakToken))); + address proxyAddress = _deployProxy(address(new FrakTreasuryWallet()), initData, "FrakTreasuryWalletDeploy"); + treasuryWallet = FrakTreasuryWallet(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + treasuryWallet.initialize(address(frakToken)); + } + + /* -------------------------------------------------------------------------- */ + /* Transfer test */ + /* -------------------------------------------------------------------------- */ + function test_transfer_ok() public { + vm.prank(deployer); + treasuryWallet.transfer(user, 1 ether); + + assertEq(frakToken.balanceOf(user), 1 ether); + assertEq(frakToken.balanceOf(address(treasuryWallet)) > 0, true); + } + + function test_transfer_NotMinter_ko() public { + vm.expectRevert(NotAuthorized.selector); + treasuryWallet.transfer(user, 1 ether); + } + + function test_transfer_InvalidAddress_ko() public asDeployer { + vm.expectRevert(InvalidAddress.selector); + treasuryWallet.transfer(address(0), 1 ether); + } + + function test_transfer_NoReward_ko() public asDeployer { + vm.expectRevert(NoReward.selector); + treasuryWallet.transfer(user, 0); + } + + function test_transfer_RewardTooLarge_ko() public asDeployer { + vm.expectRevert(RewardTooLarge.selector); + treasuryWallet.transfer(user, 500_001 ether); + } + + function test_transfer_NotEnoughTreasury_ko() public asDeployer { + uint256 totalToTransfer = 330_000_000 ether; + uint256 iteration = 500_000 ether; + + do { + treasuryWallet.transfer(user, iteration); + totalToTransfer -= iteration; + } while (totalToTransfer > 0); + + vm.expectRevert(NotEnoughTreasury.selector); + treasuryWallet.transfer(user, iteration); + } + + /* -------------------------------------------------------------------------- */ + /* Transfer batch */ + /* -------------------------------------------------------------------------- */ + + function test_transferBatch_ok() public { + (address[] memory addrs, uint256[] memory amounts) = _baseBatchTransferParam(1 ether); + vm.prank(deployer); + treasuryWallet.transferBatch(addrs, amounts); + + assertEq(frakToken.balanceOf(user), 1 ether); + assertEq(frakToken.balanceOf(address(treasuryWallet)) > 0, true); + } + + function test_transferBatch_NotMinter_ko() public { + vm.expectRevert(NotAuthorized.selector); + (address[] memory addrs, uint256[] memory amounts) = _baseBatchTransferParam(1 ether); + treasuryWallet.transferBatch(addrs, amounts); + } + + function test_transferBatch_NoReward_ko() public asDeployer { + (address[] memory addrs, uint256[] memory amounts) = _baseBatchTransferParam(0); + vm.expectRevert(NoReward.selector); + treasuryWallet.transferBatch(addrs, amounts); + } + + function test_transferBatch_RewardTooLarge_ko() public asDeployer { + (address[] memory addrs, uint256[] memory amounts) = _baseBatchTransferParam(500_001 ether); + vm.expectRevert(RewardTooLarge.selector); + treasuryWallet.transferBatch(addrs, amounts); + } + + function test_transferBatch_InvalidArray_ko() public asDeployer { + uint256[] memory amounts = new uint256[](1); + address[] memory addrs = new address[](2); + + vm.expectRevert(InvalidArray.selector); + treasuryWallet.transferBatch(addrs, amounts); + + addrs = new address[](0); + vm.expectRevert(InvalidArray.selector); + treasuryWallet.transferBatch(addrs, amounts); + } + + function test_transferBatch_NotEnoughTreasury_ko() public asDeployer { + uint256 totalToTransfer = 330_000_000 ether; + uint256 iteration = 500_000 ether; + + do { + treasuryWallet.transfer(user, iteration); + totalToTransfer -= iteration; + } while (totalToTransfer > 0); + + (address[] memory addrs, uint256[] memory amounts) = _baseBatchTransferParam(iteration); + vm.expectRevert(NotEnoughTreasury.selector); + treasuryWallet.transferBatch(addrs, amounts); + } + + /* -------------------------------------------------------------------------- */ + /* Helper's */ + /* -------------------------------------------------------------------------- */ + function _baseBatchTransferParam(uint256 amount) private view returns (address[] memory, uint256[] memory) { + return _baseBatchTransferParam(user, amount); + } + + function _baseBatchTransferParam( + address addr, + uint256 amount + ) + private + pure + returns (address[] memory addresses, uint256[] memory amounts) + { + addresses = new address[](1); + addresses[0] = addr; + + amounts = new uint256[](1); + amounts[0] = amount; + } +} diff --git a/test/wallets/MultiVestingWallets.t.sol b/test/wallets/MultiVestingWallets.t.sol new file mode 100644 index 0000000..b298481 --- /dev/null +++ b/test/wallets/MultiVestingWallets.t.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { MultiVestingWallets } from "contracts/wallets/MultiVestingWallets.sol"; + +/// @dev Testing methods on the MultiVestingWallets +contract MultiVestingWalletsTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall(MultiVestingWallets.initialize, (address(frakToken))); + address proxyAddress = _deployProxy(address(new MultiVestingWallets()), initData, "MultiVestingWalletsDeploy"); + multiVestingWallet = MultiVestingWallets(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + multiVestingWallet.initialize(address(frakToken)); + } +} diff --git a/test/wallets/VestingWalletFactory.t.sol b/test/wallets/VestingWalletFactory.t.sol new file mode 100644 index 0000000..b5813c0 --- /dev/null +++ b/test/wallets/VestingWalletFactory.t.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { VestingWalletFactory } from "contracts/wallets/VestingWalletFactory.sol"; + +/// @dev Testing methods on the VestingWalletFactory +contract VestingWalletFactoryTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall(VestingWalletFactory.initialize, (address(multiVestingWallet))); + address proxyAddress = _deployProxy(address(new VestingWalletFactory()), initData, "VestingWalletFactoryDeploy"); + vestingWalletFactory = VestingWalletFactory(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + vestingWalletFactory.initialize(address(multiVestingWallet)); + } +} From 6352614b3864e5f9212a692a7cc11bcb23f6d559 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Wed, 6 Sep 2023 17:50:25 +0200 Subject: [PATCH 08/16] =?UTF-8?q?=F0=9F=A7=AA=20Adding=20rewarder=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 63 ++++- contracts/wallets/MultiVestingWallets.sol | 63 +++-- test/reward/Rewarder.t.sol | 35 --- test/reward/RewarderConfig.t.sol | 112 +++++++++ test/reward/RewarderDirectPay.t.sol | 109 +++++++++ test/reward/RewarderPayment.t.sol | 231 ++++++++++++++++++ test/wallets/MultiVestingWallets.t.sol | 272 +++++++++++++++++++++- 7 files changed, 806 insertions(+), 79 deletions(-) delete mode 100644 test/reward/Rewarder.t.sol create mode 100644 test/reward/RewarderConfig.t.sol create mode 100644 test/reward/RewarderDirectPay.t.sol create mode 100644 test/reward/RewarderPayment.t.sol diff --git a/.gas-snapshot b/.gas-snapshot index c968a0f..612b2e1 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -14,7 +14,7 @@ FrakTeasuryWalletTest:test_transfer_NotEnoughTreasury_ko() (gas: 11304244) FrakTeasuryWalletTest:test_transfer_NotMinter_ko() (gas: 17684) FrakTeasuryWalletTest:test_transfer_RewardTooLarge_ko() (gas: 20534) FrakTeasuryWalletTest:test_transfer_ok() (gas: 136061) -FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3625) +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3613) FrakTokenTest:test_burn_ok() (gas: 53287) FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) FrakTokenTest:test_cap_ok() (gas: 10366) @@ -62,11 +62,64 @@ MinterTest:test_mintFreeFraktionForUser_ok() (gas: 62267) MinterTest:test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() (gas: 40161) MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 63135) MinterTest:test_mintFreeFraktion_ok() (gas: 64993) -MultiVestingWalletsTest:test_canBeDeployedAndInit_ok() (gas: 2805268) -MultiVestingWalletsTest:test_initialize_InitTwice_ko() (gas: 17948) +MultiVestingWalletsTest:test_canBeDeployedAndInit_ok() (gas: 2667336) +MultiVestingWalletsTest:test_createVestBatch() (gas: 210722) +MultiVestingWalletsTest:test_createVestBatch_ArrayInvalidLength_ko() (gas: 79027) +MultiVestingWalletsTest:test_createVestBatch_EmptyArray_ko() (gas: 78827) +MultiVestingWalletsTest:test_createVestBatch_NotEnoughReserve_ko() (gas: 85446) +MultiVestingWalletsTest:test_createVestBatch_NotManager_ko() (gas: 80864) +MultiVestingWalletsTest:test_createVest_InvalidAddress_ko() (gas: 81908) +MultiVestingWalletsTest:test_createVest_InvalidDuration_ko() (gas: 80450) +MultiVestingWalletsTest:test_createVest_InvalidReward_ko() (gas: 81932) +MultiVestingWalletsTest:test_createVest_InvalidStartDateTooFar_ko() (gas: 80459) +MultiVestingWalletsTest:test_createVest_InvalidStartDate_ko() (gas: 80499) +MultiVestingWalletsTest:test_createVest_NotEnoughReserve_ko() (gas: 84011) +MultiVestingWalletsTest:test_createVest_NotManager_ko() (gas: 79610) +MultiVestingWalletsTest:test_createVest_TooLargeReward_ko() (gas: 82001) +MultiVestingWalletsTest:test_createVest_ok() (gas: 209042) +MultiVestingWalletsTest:test_decimals_ok() (gas: 10391) +MultiVestingWalletsTest:test_initialize_InitTwice_ko() (gas: 17982) +MultiVestingWalletsTest:test_name_ok() (gas: 12085) +MultiVestingWalletsTest:test_releaseAllForUser_ok() (gas: 232525) +MultiVestingWalletsTest:test_releaseAll_ok() (gas: 228343) +MultiVestingWalletsTest:test_release_ok() (gas: 237783) +MultiVestingWalletsTest:test_symbol_ok() (gas: 12073) +MultiVestingWalletsTest:test_transferReserve_ok() (gas: 103722) +MultiVestingWalletsTest:test_transfer_InvalidAddress_ko() (gas: 211179) +MultiVestingWalletsTest:test_transfer_InvalidUser_ko() (gas: 209436) +MultiVestingWalletsTest:test_transfer_ok() (gas: 226494) ReferralPoolTest:test_canBeDeployedAndInit_ok() (gas: 1692225) ReferralPoolTest:test_initialize_InitTwice_ko() (gas: 17881) -RewarderTest:test_canBeDeployedAndInit_ok() (gas: 2600249) -RewarderTest:test_initialize_InitTwice_ko() (gas: 26762) +RewarderConfigTest:test_canBeDeployedAndInit_ok() (gas: 2600249) +RewarderConfigTest:test_initialize_InitTwice_ko() (gas: 26774) +RewarderConfigTest:test_updateContentBadge_BadgeTooLarge_ko() (gas: 20191) +RewarderConfigTest:test_updateContentBadge_InvalidRole_ko() (gas: 17630) +RewarderConfigTest:test_updateContentBadge_ok() (gas: 46435) +RewarderConfigTest:test_updateListenerBadge_BadgeTooLarge_ko() (gas: 20196) +RewarderConfigTest:test_updateListenerBadge_InvalidRole_ko() (gas: 17711) +RewarderConfigTest:test_updateListenerBadge_ok() (gas: 46543) +RewarderConfigTest:test_updateTpu_InvalidRole_ko() (gas: 15412) +RewarderConfigTest:test_updateTpu_ok() (gas: 23775) +RewarderDirectPaymentTest:test_payCreatorDirectlyBatch() (gas: 139334) +RewarderDirectPaymentTest:test_payCreatorDirectlyBatch_EmptyAmount_ko() (gas: 81286) +RewarderDirectPaymentTest:test_payCreatorDirectlyBatch_InvalidArray_ko() (gas: 79510) +RewarderDirectPaymentTest:test_payCreatorDirectlyBatch_InvalidRole_ko() (gas: 80397) +RewarderDirectPaymentTest:test_payCreatorDirectlyBatch_TooLargeAmount_ko() (gas: 81344) +RewarderDirectPaymentTest:test_payCreatorDirectlyBatch_TooLargeArray_ko() (gas: 82833) +RewarderDirectPaymentTest:test_payUserDirectly() (gas: 111195) +RewarderDirectPaymentTest:test_payUserDirectly_InvalidAddress_ko() (gas: 77885) +RewarderDirectPaymentTest:test_payUserDirectly_InvalidReward_ko() (gas: 88533) +RewarderDirectPaymentTest:test_payUserDirectly_InvalidRole_ko() (gas: 79215) +RewarderDirectPaymentTest:test_payUserDirectly_NotEnoughBalance_ko() (gas: 105700) +RewarderTest:test_pay_ContentTypeImpact_ok() (gas: 212408) +RewarderTest:test_pay_FreeFraktion_ok() (gas: 191901) +RewarderTest:test_pay_InvalidAddress_ko() (gas: 21620) +RewarderTest:test_pay_InvalidArray_ko() (gas: 38041) +RewarderTest:test_pay_InvalidContent_ko() (gas: 56805) +RewarderTest:test_pay_InvalidRoles_ko() (gas: 21259) +RewarderTest:test_pay_PayedFraktions_LargeListenCounts_ok() (gas: 375683) +RewarderTest:test_pay_PayedFraktions_TooMuchListenCounts_ko() (gas: 175619) +RewarderTest:test_pay_PayedFraktions_ok() (gas: 413549) +RewarderTest:test_pay_TooLargeReward_ko() (gas: 239180) VestingWalletFactoryTest:test_canBeDeployedAndInit_ok() (gas: 2093328) VestingWalletFactoryTest:test_initialize_InitTwice_ko() (gas: 17926) \ No newline at end of file diff --git a/contracts/wallets/MultiVestingWallets.sol b/contracts/wallets/MultiVestingWallets.sol index 1d7ca94..463dd08 100644 --- a/contracts/wallets/MultiVestingWallets.sol +++ b/contracts/wallets/MultiVestingWallets.sol @@ -127,14 +127,9 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { return token.balanceOf(address(this)) - totalSupply; } - /** - * @notice Free the reserve up - */ - function transferAvailableReserve(address receiver) external onlyRole(FrakRoles.ADMIN) { - uint256 available = availableReserve(); - if (available == 0) revert NoReward(); - token.safeTransfer(receiver, available); - } + /* -------------------------------------------------------------------------- */ + /* Create vesting's */ + /* -------------------------------------------------------------------------- */ /** * @notice Create a new vesting. @@ -224,6 +219,23 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { emit VestingTransfered(vestingId, address(0), beneficiary); } + /* -------------------------------------------------------------------------- */ + /* Global managment */ + /* -------------------------------------------------------------------------- */ + + /** + * @notice Free the reserve up + */ + function transferAvailableReserve(address receiver) external onlyRole(FrakRoles.ADMIN) { + uint256 available = availableReserve(); + if (available == 0) revert NoReward(); + token.safeTransfer(receiver, available); + } + + /* -------------------------------------------------------------------------- */ + /* Vesting managment */ + /* -------------------------------------------------------------------------- */ + /** * @notice Transfer a vesting to another person. */ @@ -264,7 +276,7 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { /** * @notice Release the tokens of a all of beneficiary's vesting. */ - function releaseAllFor(address beneficiary) external onlyRole(FrakRoles.VESTING_MANAGER) returns (uint256) { + function releaseAllFor(address beneficiary) external returns (uint256) { return _releaseAll(beneficiary); } @@ -273,7 +285,7 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { */ function _release(Vesting storage vesting) internal returns (uint256 released) { released = _doRelease(vesting); - _checkAmount(released); + if (released == 0) revert NoReward(); } /** @@ -293,7 +305,7 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { } } - _checkAmount(released); + if (released == 0) revert NoReward(); } /** @@ -315,12 +327,9 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { } } - /** - * @dev Revert the transaction if the value is zero. - */ - function _checkAmount(uint256 released) internal pure { - if (released == 0) revert NoReward(); - } + /* -------------------------------------------------------------------------- */ + /* View method's */ + /* -------------------------------------------------------------------------- */ /** * @notice Get the releasable amount of tokens. @@ -457,24 +466,4 @@ contract MultiVestingWallets is FrakAccessControlUpgradeable { function _addOwnership(address account, uint24 vestingId) internal { owned[account].add(vestingId); } - - /** - * @dev Update a vesting start date - */ - function fixVestingDate(uint24[] calldata vestingIds) external onlyRole(FrakRoles.VESTING_MANAGER) { - for (uint256 index = 0; index < vestingIds.length; index++) { - // Get the vesting - uint24 vestingId = vestingIds[index]; - Vesting memory vesting = _getVesting(vestingId); - - // Check is date on update it if needed - if (vesting.startDate > MAX_TIMESTAMP) { - uint48 newDate = vesting.startDate / 1000; - // If that's good, update the date - if (newDate > block.timestamp && newDate < MAX_TIMESTAMP) { - vestings[vestingId].startDate = newDate; - } - } - } - } } diff --git a/test/reward/Rewarder.t.sol b/test/reward/Rewarder.t.sol deleted file mode 100644 index d1a3544..0000000 --- a/test/reward/Rewarder.t.sol +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { FrakTest } from "../FrakTest.sol"; -import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; -import { Rewarder } from "contracts/reward/Rewarder.sol"; - -/// @dev Testing methods on the Rewarder -contract RewarderTest is FrakTest { - function setUp() public { - _setupTests(); - } - - /* -------------------------------------------------------------------------- */ - /* Init test's */ - /* -------------------------------------------------------------------------- */ - - function test_canBeDeployedAndInit_ok() public { - // Deploy our contract via proxy and set the proxy address - bytes memory initData = abi.encodeCall( - Rewarder.initialize, - (address(frakToken), address(fraktionTokens), address(contentPool), address(referralPool), foundation) - ); - address proxyAddress = _deployProxy(address(new Rewarder()), initData, "RewarderDeploy"); - rewarder = Rewarder(proxyAddress); - } - - /// @dev Can't re-init - function test_initialize_InitTwice_ko() public { - vm.expectRevert("Initializable: contract is already initialized"); - rewarder.initialize( - address(frakToken), address(fraktionTokens), address(contentPool), address(referralPool), foundation - ); - } -} diff --git a/test/reward/RewarderConfig.t.sol b/test/reward/RewarderConfig.t.sol new file mode 100644 index 0000000..8d03c78 --- /dev/null +++ b/test/reward/RewarderConfig.t.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { + NotAuthorized, + InvalidAddress, + NoReward, + RewardTooLarge, + InvalidArray, + BadgeTooLarge +} from "contracts/utils/FrakErrors.sol"; +import { Rewarder } from "contracts/reward/Rewarder.sol"; +import { IRewarder } from "contracts/reward/IRewarder.sol"; +import { ContentId } from "contracts/libs/ContentId.sol"; + +/// @dev Testing the config methods on the Rewarder +contract RewarderConfigTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* Init test's */ + /* -------------------------------------------------------------------------- */ + + function test_canBeDeployedAndInit_ok() public { + // Deploy our contract via proxy and set the proxy address + bytes memory initData = abi.encodeCall( + Rewarder.initialize, + (address(frakToken), address(fraktionTokens), address(contentPool), address(referralPool), foundation) + ); + address proxyAddress = _deployProxy(address(new Rewarder()), initData, "RewarderDeploy"); + rewarder = Rewarder(proxyAddress); + } + + /// @dev Can't re-init + function test_initialize_InitTwice_ko() public { + vm.expectRevert("Initializable: contract is already initialized"); + rewarder.initialize( + address(frakToken), address(fraktionTokens), address(contentPool), address(referralPool), foundation + ); + } + + /* -------------------------------------------------------------------------- */ + /* Tpu */ + /* -------------------------------------------------------------------------- */ + + function test_updateTpu_ok() public { + vm.prank(deployer); + rewarder.updateTpu(2 ether); + + assertEq(rewarder.getTpu(), 2 ether); + } + + function test_updateTpu_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + rewarder.updateTpu(2 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Content badges */ + /* -------------------------------------------------------------------------- */ + + function test_updateContentBadge_ok() public { + // Test initial value + assertEq(rewarder.getContentBadge(contentId), 1 ether); + + // Update the badge + vm.prank(deployer); + rewarder.updateContentBadge(contentId, 2 ether); + + assertEq(rewarder.getContentBadge(contentId), 2 ether); + } + + function test_updateContentBadge_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + rewarder.updateContentBadge(contentId, 2 ether); + } + + function test_updateContentBadge_BadgeTooLarge_ko() public { + vm.expectRevert(BadgeTooLarge.selector); + vm.prank(deployer); + rewarder.updateContentBadge(contentId, 1001 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Listener badges */ + /* -------------------------------------------------------------------------- */ + + function test_updateListenerBadge_ok() public { + // Test initial value + assertEq(rewarder.getListenerBadge(user), 1 ether); + + // Update the badge + vm.prank(deployer); + rewarder.updateListenerBadge(user, 2 ether); + + assertEq(rewarder.getListenerBadge(user), 2 ether); + } + + function test_updateListenerBadge_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + rewarder.updateListenerBadge(user, 2 ether); + } + + function test_updateListenerBadge_BadgeTooLarge_ko() public { + vm.expectRevert(BadgeTooLarge.selector); + vm.prank(deployer); + rewarder.updateListenerBadge(user, 1001 ether); + } +} diff --git a/test/reward/RewarderDirectPay.t.sol b/test/reward/RewarderDirectPay.t.sol new file mode 100644 index 0000000..869148f --- /dev/null +++ b/test/reward/RewarderDirectPay.t.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { Rewarder } from "contracts/reward/Rewarder.sol"; +import { IRewarder } from "contracts/reward/IRewarder.sol"; +import { ContentId } from "contracts/libs/ContentId.sol"; + +/// @dev Testing the direct payment methods on the Rewarder +contract RewarderDirectPaymentTest is FrakTest { + function setUp() public { + _setupTests(); + } + + /* -------------------------------------------------------------------------- */ + /* User direct payment's */ + /* -------------------------------------------------------------------------- */ + + function test_payUserDirectly() public withFrk(address(rewarder), 10 ether) asDeployer { + rewarder.payUserDirectly(user, 10 ether); + assertEq(frakToken.balanceOf(user), 10 ether); + } + + function test_payUserDirectly_InvalidRole_ko() public withFrk(address(rewarder), 10 ether) { + vm.expectRevert(NotAuthorized.selector); + rewarder.payUserDirectly(user, 10 ether); + } + + function test_payUserDirectly_InvalidAddress_ko() public withFrk(address(rewarder), 10 ether) asDeployer { + vm.expectRevert(InvalidAddress.selector); + rewarder.payUserDirectly(address(0), 10 ether); + } + + function test_payUserDirectly_InvalidReward_ko() public withFrk(address(rewarder), 10 ether) asDeployer { + vm.expectRevert(IRewarder.InvalidReward.selector); + rewarder.payUserDirectly(user, 0); + + vm.expectRevert(IRewarder.InvalidReward.selector); + rewarder.payUserDirectly(user, 1_000_001 ether); + } + + function test_payUserDirectly_NotEnoughBalance_ko() public withFrk(address(rewarder), 10 ether) asDeployer { + vm.expectRevert(); + rewarder.payUserDirectly(user, 11 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Creator's direct payment */ + /* -------------------------------------------------------------------------- */ + + function test_payCreatorDirectlyBatch() public withFrk(address(rewarder), 10 ether) asDeployer { + ContentId[] memory contentIds = new ContentId[](1); + contentIds[0] = contentId; + uint256[] memory amountsIds = new uint256[](1); + amountsIds[0] = 10 ether; + + rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); + } + + function test_payCreatorDirectlyBatch_InvalidRole_ko() public withFrk(address(rewarder), 10 ether) { + ContentId[] memory contentIds = new ContentId[](1); + contentIds[0] = contentId; + uint256[] memory amountsIds = new uint256[](1); + amountsIds[0] = 10 ether; + + vm.expectRevert(NotAuthorized.selector); + rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); + } + + function test_payCreatorDirectlyBatch_InvalidArray_ko() public withFrk(address(rewarder), 10 ether) asDeployer { + ContentId[] memory contentIds = new ContentId[](3); + uint256[] memory amountsIds = new uint256[](4); + + vm.expectRevert(InvalidArray.selector); + rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); + } + + function test_payCreatorDirectlyBatch_TooLargeArray_ko() public withFrk(address(rewarder), 10 ether) asDeployer { + ContentId[] memory contentIds = new ContentId[](21); + uint256[] memory amountsIds = new uint256[](21); + + vm.expectRevert(InvalidArray.selector); + rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); + } + + function test_payCreatorDirectlyBatch_EmptyAmount_ko() public withFrk(address(rewarder), 10 ether) asDeployer { + ContentId[] memory contentIds = new ContentId[](1); + contentIds[0] = contentId; + uint256[] memory amountsIds = new uint256[](1); + + vm.expectRevert(IRewarder.InvalidReward.selector); + rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); + } + + function test_payCreatorDirectlyBatch_TooLargeAmount_ko() + public + withFrk(address(rewarder), 2_000_000 ether) + asDeployer + { + ContentId[] memory contentIds = new ContentId[](1); + contentIds[0] = contentId; + uint256[] memory amountsIds = new uint256[](1); + amountsIds[0] = 1_000_001 ether; + + vm.expectRevert(IRewarder.InvalidReward.selector); + rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); + } +} diff --git a/test/reward/RewarderPayment.t.sol b/test/reward/RewarderPayment.t.sol new file mode 100644 index 0000000..ab12b36 --- /dev/null +++ b/test/reward/RewarderPayment.t.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GNU GPLv3 +pragma solidity 0.8.21; + +import { FrakTest } from "../FrakTest.sol"; +import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { Rewarder } from "contracts/reward/Rewarder.sol"; +import { IRewarder } from "contracts/reward/IRewarder.sol"; +import { ContentId } from "contracts/libs/ContentId.sol"; +import { FraktionId } from "contracts/libs/FraktionId.sol"; + +/// @dev Testing methods on the Rewarder +contract RewarderTest is FrakTest { + function setUp() public { + _setupTests(); + + // Add some frk to the rewarder + vm.prank(deployer); + frakToken.mint(address(rewarder), 1_500_000 ether); + } + + function test_pay_FreeFraktion_ok() public { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + + // Assert that the user got some rewards + uint256 availableBalance = rewarder.getAvailableFounds(user); + assertGt(availableBalance, 0); + assertEq(availableBalance, 0.007 ether); + // Assert that the owner got some rewards + assertGt(rewarder.getAvailableFounds(contentOwner), 0); + // Assert that the content pool received no reward + assertEq(frakToken.balanceOf(address(contentPool)), 0); + + // Claim the founds + vm.prank(user); + rewarder.withdrawFounds(); + + // Ensure the founds is withdraw with 2% fees + assertEq(frakToken.balanceOf(user), availableBalance * 98 / 100); + assertEq(rewarder.getAvailableFounds(user), 0); + } + + function test_pay_PayedFraktions_ok() public userWithFraktion { + uint256 initialFrkMinted = rewarder.getFrkMinted(); + + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + + // Assert that the user got some rewards + uint256 availableBalance = rewarder.getAvailableFounds(user); + assertGt(availableBalance, 0); + assertEq(availableBalance, 2.527 ether); + // Ensure the frk minted amount has decreased + assertGt(rewarder.getFrkMinted(), initialFrkMinted); + // Assert that the owner got some rewards + assertGt(rewarder.getAvailableFounds(contentOwner), 0); + // Assert that the content pool received some reward + assertGt(frakToken.balanceOf(address(contentPool)), 0); + + // Claim the founds + rewarder.withdrawFounds(user); + + // Ensure the founds is withdraw with 2% fees + assertEq(frakToken.balanceOf(user), availableBalance * 98 / 100); + assertEq(rewarder.getAvailableFounds(user), 0); + } + + function test_pay_PayedFraktions_LargeListenCounts_ok() public userWithFraktion { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(100); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + + // Assert that the user got some rewards + assertGt(rewarder.getAvailableFounds(user), 0); + assertEq(rewarder.getAvailableFounds(user), 252.7 ether); + // Assert that the owner got some rewards + assertGt(rewarder.getAvailableFounds(contentOwner), 0); + // Assert that the content pool received some reward + assertGt(frakToken.balanceOf(address(contentPool)), 0); + } + + function test_pay_PayedFraktions_TooMuchListenCounts_ko() public userWithFraktion { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(301); + vm.expectRevert(IRewarder.InvalidReward.selector); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + } + + function test_pay_InvalidRoles_ko() public { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + vm.expectRevert(NotAuthorized.selector); + rewarder.payUser(user, 1, cIds, listens); + // 2_100_000 + } + + function test_pay_InvalidAddress_ko() public { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + vm.expectRevert(InvalidAddress.selector); + vm.prank(deployer); + rewarder.payUser(address(0), 1, cIds, listens); + } + + function test_pay_InvalidArray_ko() public { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + + listens = new uint256[](3); + vm.expectRevert(InvalidArray.selector); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + + listens = new uint256[](21); + cIds = new ContentId[](21); + vm.expectRevert(InvalidArray.selector); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + } + + function test_pay_InvalidContent_ko() public { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + cIds[0] = ContentId.wrap(13); + + vm.expectRevert(InvalidAddress.selector); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + } + + function test_pay_TooLargeReward_ko() public userWithFraktion { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(300); + vm.prank(deployer); + rewarder.updateListenerBadge(user, 1000 ether); + vm.prank(deployer); + rewarder.updateContentBadge(contentId, 1000 ether); + + vm.expectRevert(RewardTooLarge.selector); + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + } + + function test_pay_ContentTypeImpact_ok() public { + (uint256[] memory listens, ContentId[] memory cIds) = _payParameters(); + + // Initial claim balance + uint256 claimableBalance = rewarder.getAvailableFounds(user); + uint256 newClaimableBalance = rewarder.getAvailableFounds(user); + + // Ensure it hasn't changes with content type 0 (inexistant) + vm.prank(deployer); + rewarder.payUser(user, 0, cIds, listens); + newClaimableBalance = rewarder.getAvailableFounds(user); + assertEq(newClaimableBalance - claimableBalance, 0); + claimableBalance = newClaimableBalance; + + // Ensure the content type 1 has an impact + vm.prank(deployer); + rewarder.payUser(user, 1, cIds, listens); + newClaimableBalance = rewarder.getAvailableFounds(user); + assertGt(newClaimableBalance - claimableBalance, 0); + claimableBalance = newClaimableBalance; + + // Ensure the content type 2 has an impact + vm.prank(deployer); + rewarder.payUser(user, 2, cIds, listens); + newClaimableBalance = rewarder.getAvailableFounds(user); + assertGt(newClaimableBalance - claimableBalance, 0); + claimableBalance = newClaimableBalance; + + // Ensure the content type 3 has an impact + vm.prank(deployer); + rewarder.payUser(user, 3, cIds, listens); + newClaimableBalance = rewarder.getAvailableFounds(user); + assertGt(newClaimableBalance - claimableBalance, 0); + claimableBalance = newClaimableBalance; + + // Ensure the content type 4 has an impact + vm.prank(deployer); + rewarder.payUser(user, 4, cIds, listens); + newClaimableBalance = rewarder.getAvailableFounds(user); + assertGt(newClaimableBalance - claimableBalance, 0); + claimableBalance = newClaimableBalance; + + // Ensure the content type 5 has no impact + vm.prank(deployer); + rewarder.payUser(user, 5, cIds, listens); + newClaimableBalance = rewarder.getAvailableFounds(user); + assertEq(newClaimableBalance - claimableBalance, 0); + } + + /* -------------------------------------------------------------------------- */ + /* Utils */ + /* -------------------------------------------------------------------------- */ + + modifier userWithFraktion() { + // Build the param for our new content mint, and mint it + uint256[] memory fTypeArray = new uint256[](4); + fTypeArray[0] = 3; + fTypeArray[1] = 4; + fTypeArray[2] = 5; + fTypeArray[3] = 6; + + uint256[] memory amounts = new uint256[](fTypeArray.length); + for (uint256 i = 0; i < fTypeArray.length; i++) { + amounts[i] = 1; + } + + FraktionId[] memory fIds = contentId.payableFraktionIds(); + for (uint256 i = 0; i < fIds.length; i++) { + vm.prank(deployer); + fraktionTokens.mint(user, fIds[i], 1); + } + + _; + } + + function _payParameters() internal view returns (uint256[] memory, ContentId[] memory) { + return _payParameters(1); + } + + function _payParameters(uint256 listenCount) + internal + view + returns (uint256[] memory listens, ContentId[] memory cIds) + { + listens = new uint256[](1); + listens[0] = listenCount; + + cIds = new ContentId[](1); + cIds[0] = contentId; + } +} diff --git a/test/wallets/MultiVestingWallets.t.sol b/test/wallets/MultiVestingWallets.t.sol index b298481..8e15abd 100644 --- a/test/wallets/MultiVestingWallets.t.sol +++ b/test/wallets/MultiVestingWallets.t.sol @@ -2,8 +2,13 @@ pragma solidity 0.8.21; import { FrakTest } from "../FrakTest.sol"; -import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; -import { MultiVestingWallets } from "contracts/wallets/MultiVestingWallets.sol"; +import { NotAuthorized, InvalidArray, InvalidAddress, NoReward, RewardTooLarge } from "contracts/utils/FrakErrors.sol"; +import { + MultiVestingWallets, + NotEnoughFounds, + InvalidDuration, + InvalidDate +} from "contracts/wallets/MultiVestingWallets.sol"; /// @dev Testing methods on the MultiVestingWallets contract MultiVestingWalletsTest is FrakTest { @@ -27,4 +32,267 @@ contract MultiVestingWalletsTest is FrakTest { vm.expectRevert("Initializable: contract is already initialized"); multiVestingWallet.initialize(address(frakToken)); } + + /* -------------------------------------------------------------------------- */ + /* Some global properties test */ + /* -------------------------------------------------------------------------- */ + + function test_name_ok() public { + assertEq(multiVestingWallet.name(), "Vested FRK Token"); + } + + function test_decimals_ok() public { + assertEq(multiVestingWallet.decimals(), 18); + } + + function test_symbol_ok() public { + assertEq(multiVestingWallet.symbol(), "vFRK"); + } + + /* -------------------------------------------------------------------------- */ + /* Vesting creation */ + /* -------------------------------------------------------------------------- */ + + function test_createVest_ok() public withFrk(address(multiVestingWallet), 10 ether) { + // Ask to transfer the available reserve + vm.prank(deployer); + multiVestingWallet.createVest(user, 10, 10, uint48(block.timestamp + 1)); + assertEq(multiVestingWallet.balanceOf(user), 10); + } + + function test_createVest_NotManager_ko() public withFrk(address(multiVestingWallet), 10 ether) { + vm.expectRevert(NotAuthorized.selector); + multiVestingWallet.createVest(user, 10, 10, uint48(block.timestamp + 1)); + } + + function test_createVest_InvalidDuration_ko() public withFrk(address(multiVestingWallet), 10 ether) asDeployer { + vm.expectRevert(InvalidDuration.selector); + multiVestingWallet.createVest(user, 10, 0, uint48(block.timestamp + 1)); + } + + function test_createVest_InvalidStartDate_ko() public withFrk(address(multiVestingWallet), 10 ether) asDeployer { + vm.expectRevert(InvalidDate.selector); + multiVestingWallet.createVest(user, 10, 10, uint48(block.timestamp - 1)); + } + + function test_createVest_InvalidStartDateTooFar_ko() + public + withFrk(address(multiVestingWallet), 10 ether) + asDeployer + { + vm.expectRevert(InvalidDate.selector); + multiVestingWallet.createVest(user, 10, 10, 2_525_644_801); + } + + function test_createVest_NotEnoughReserve_ko() public withFrk(address(multiVestingWallet), 10 ether) asDeployer { + vm.expectRevert(NotEnoughFounds.selector); + multiVestingWallet.createVest(user, 11 ether, 10, uint48(block.timestamp + 1)); + } + + function test_createVest_InvalidAddress_ko() public withFrk(address(multiVestingWallet), 10 ether) asDeployer { + vm.expectRevert(InvalidAddress.selector); + multiVestingWallet.createVest(address(0), 10, 10, uint48(block.timestamp + 1)); + } + + function test_createVest_InvalidReward_ko() public withFrk(address(multiVestingWallet), 10 ether) asDeployer { + vm.expectRevert(NoReward.selector); + multiVestingWallet.createVest(address(10), 0, 10, uint48(block.timestamp + 1)); + } + + function test_createVest_TooLargeReward_ko() + public + withFrk(address(multiVestingWallet), 300_000_000 ether) + asDeployer + { + vm.expectRevert(RewardTooLarge.selector); + multiVestingWallet.createVest(address(10), 200_000_001 ether, 10, uint48(block.timestamp + 1)); + } + + function test_createVestBatch() public withFrk(address(multiVestingWallet), 10 ether) { + uint256[] memory amounts = new uint256[](1); + amounts[0] = 10; + address[] memory addresses = new address[](1); + addresses[0] = user; + + // Ask to transfer the available reserve + vm.prank(deployer); + multiVestingWallet.createVestBatch(addresses, amounts, 10, uint48(block.timestamp + 1)); + assertEq(multiVestingWallet.balanceOf(user), 10); + } + + function test_createVestBatch_NotManager_ko() public withFrk(address(multiVestingWallet), 10 ether) { + uint256[] memory amounts = new uint256[](1); + amounts[0] = 10; + address[] memory addresses = new address[](1); + addresses[0] = user; + + vm.expectRevert(NotAuthorized.selector); + multiVestingWallet.createVestBatch(addresses, amounts, 10, uint48(block.timestamp + 1)); + } + + function test_createVestBatch_NotEnoughReserve_ko() + public + withFrk(address(multiVestingWallet), 10 ether) + asDeployer + { + uint256[] memory amounts = new uint256[](1); + amounts[0] = 11 ether; + address[] memory addresses = new address[](1); + addresses[0] = user; + + vm.expectRevert(NotEnoughFounds.selector); + multiVestingWallet.createVestBatch(addresses, amounts, 10, uint48(block.timestamp + 1)); + } + + function test_createVestBatch_EmptyArray_ko() public withFrk(address(multiVestingWallet), 10 ether) { + address[] memory addresses = new address[](0); + uint256[] memory amounts = new uint256[](0); + + vm.prank(deployer); + vm.expectRevert(InvalidArray.selector); + multiVestingWallet.createVestBatch(addresses, amounts, 10, uint48(block.timestamp + 1)); + } + + function test_createVestBatch_ArrayInvalidLength_ko() public withFrk(address(multiVestingWallet), 10 ether) { + uint256[] memory amounts = new uint256[](1); + address[] memory addresses = new address[](0); + + vm.prank(deployer); + vm.expectRevert(InvalidArray.selector); + multiVestingWallet.createVestBatch(addresses, amounts, 10, uint48(block.timestamp + 1)); + } + + /* -------------------------------------------------------------------------- */ + /* Test veting lifecycle */ + /* -------------------------------------------------------------------------- */ + + function test_transfer_ok() public withUserVesting { + address targetUser = _newUser("transferTargetUser"); + assertEq(multiVestingWallet.balanceOf(user), 10 ether); + + vm.prank(user); + multiVestingWallet.transfer(targetUser, 0); + + assertEq(multiVestingWallet.balanceOf(targetUser), 10 ether); + } + + function test_transfer_InvalidUser_ko() public withUserVesting { + address targetUser = _newUser("transferTargetUser"); + + vm.expectRevert(NotAuthorized.selector); + multiVestingWallet.transfer(targetUser, 0); + } + + function test_transfer_InvalidAddress_ko() public withUserVesting { + vm.prank(user); + vm.expectRevert(InvalidAddress.selector); + multiVestingWallet.transfer(address(0), 0); + + vm.prank(user); + vm.expectRevert(InvalidAddress.selector); + multiVestingWallet.transfer(user, 0); + } + + function test_release_ok() public withUserVesting { + // Nothing to release just after the creation + assertEq(multiVestingWallet.releasableAmount(0), 0); + assertEq(multiVestingWallet.vestedAmount(0), 0); + assertEq(multiVestingWallet.balanceOfVesting(0), 10 ether); + assertEq(multiVestingWallet.ownedCount(user), 1); + + // Jump in the futur + vm.warp(block.timestamp + 1000); + + // Assert all is releasable + assertEq(multiVestingWallet.releasableAmount(0), 10 ether); + assertEq(multiVestingWallet.vestedAmount(0), 10 ether); + + // Release all + vm.prank(user); + multiVestingWallet.release(0); + + // ASsert the balance has increase + assertEq(frakToken.balanceOf(user), 10 ether); + assertEq(multiVestingWallet.releasableAmount(0), 0); + assertEq(multiVestingWallet.balanceOfVesting(0), 0); + assertEq(multiVestingWallet.vestedAmount(0), 10 ether); + } + + function test_releaseAll_ok() public withUserVesting { + // Jump in the futur + vm.warp(block.timestamp + 1000); + + // Assert all is releasable + assertEq(multiVestingWallet.releasableAmount(0), 10 ether); + assertEq(multiVestingWallet.vestedAmount(0), 10 ether); + + // Release all + vm.prank(user); + multiVestingWallet.releaseAll(); + + // ASsert the balance has increase + assertEq(frakToken.balanceOf(user), 10 ether); + assertEq(multiVestingWallet.releasableAmount(0), 0); + assertEq(multiVestingWallet.vestedAmount(0), 10 ether); + } + + function test_releaseAllForUser_ok() public withUserVesting { + vm.prank(user); + vm.expectRevert(NoReward.selector); + multiVestingWallet.releaseAllFor(user); + + // Jump in the futur + vm.warp(block.timestamp + 1000); + + // Assert all is releasable + assertEq(multiVestingWallet.releasableAmount(0), 10 ether); + assertEq(multiVestingWallet.vestedAmount(0), 10 ether); + + // Release all + multiVestingWallet.releaseAllFor(user); + + // ASsert the balance has increase + assertEq(frakToken.balanceOf(user), 10 ether); + assertEq(multiVestingWallet.releasableAmount(0), 0); + assertEq(multiVestingWallet.vestedAmount(0), 10 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Reserve managment */ + /* -------------------------------------------------------------------------- */ + + function test_transferReserve_ok() public { + assertEq(multiVestingWallet.availableReserve(), 0); + + vm.prank(deployer); + vm.expectRevert(NoReward.selector); + multiVestingWallet.transferAvailableReserve(user); + + // Mint some token to our vesting wallet + vm.prank(deployer); + frakToken.mint(address(multiVestingWallet), 10 ether); + + assertEq(multiVestingWallet.availableReserve(), 10 ether); + + // Try to transfer them + vm.prank(deployer); + multiVestingWallet.transferAvailableReserve(user); + + assertEq(multiVestingWallet.availableReserve(), 0); + assertEq(frakToken.balanceOf(user), 10 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Test helper's */ + /* -------------------------------------------------------------------------- */ + + modifier withUserVesting() { + // Mint some token to our vesting wallet + vm.prank(deployer); + frakToken.mint(address(multiVestingWallet), 10 ether); + // Create a vesting for our user + vm.prank(deployer); + multiVestingWallet.createVest(user, 10 ether, 10, uint48(block.timestamp + 1)); + _; + } } From 449f1c833868592af02de09ef3ce0fcf96310b71 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Wed, 6 Sep 2023 18:15:42 +0200 Subject: [PATCH 09/16] =?UTF-8?q?=F0=9F=9A=A7=F0=9F=A7=AA=20Startup=20cont?= =?UTF-8?q?ent=20pool=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/reward/pools/ContentPool.t.sol | 80 +++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/test/reward/pools/ContentPool.t.sol b/test/reward/pools/ContentPool.t.sol index fcd7508..f6d8184 100644 --- a/test/reward/pools/ContentPool.t.sol +++ b/test/reward/pools/ContentPool.t.sol @@ -3,12 +3,25 @@ pragma solidity 0.8.21; import { FrakTest } from "../../FrakTest.sol"; import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; +import { FrakRoles } from "contracts/roles/FrakRoles.sol"; import { ContentPool } from "contracts/reward/contentPool/ContentPool.sol"; /// @dev Testing methods on the ContentPool contract ContentPoolTest is FrakTest { function setUp() public { _setupTests(); + + // Mint some frk to the content pool + vm.prank(deployer); + frakToken.mint(address(contentPool), 1000 ether); + + // Link content pool to the fraktions tokens + vm.prank(deployer); + fraktionTokens.registerNewCallback(address(contentPool)); + + // Register deployer as rewarder + vm.prank(deployer); + contentPool.grantRole(FrakRoles.REWARDER, deployer); } /* -------------------------------------------------------------------------- */ @@ -27,4 +40,71 @@ contract ContentPoolTest is FrakTest { vm.expectRevert("Initializable: contract is already initialized"); contentPool.initialize(address(frakToken)); } + + /* -------------------------------------------------------------------------- */ + /* Adding reward test */ + /* -------------------------------------------------------------------------- */ + + function test_addReward_ok() public { + vm.prank(deployer); + contentPool.addReward(contentId, 1 ether); + } + + function test_addReward_InvalidRole_ko() public { + vm.expectRevert(NotAuthorized.selector); + contentPool.addReward(contentId, 1 ether); + } + + function test_addReward_InvalidReward_ko() public { + vm.expectRevert(NoReward.selector); + vm.prank(deployer); + contentPool.addReward(contentId, 0); + + vm.expectRevert(NoReward.selector); + vm.prank(deployer); + contentPool.addReward(contentId, 100_001 ether); + } + + /* -------------------------------------------------------------------------- */ + /* Updating pool & user state */ + /* -------------------------------------------------------------------------- */ + + function test_updatePool_ok() public { + // Simulate fraktion mint by a user + _mintFraktionByUser(); + _addPoolReward(); + + // Compute user rewards & withdraw + contentPool.computeAllPoolsBalance(user); + contentPool.withdrawFounds(user); + // Assert the user received something + uint256 userBalance = frakToken.balanceOf(user); + assertGt(userBalance, 0); + + // Add a few more rewards and repeat the process + _addPoolReward(); + contentPool.withdrawFounds(user); + assertGt(frakToken.balanceOf(user), userBalance); + userBalance = frakToken.balanceOf(user); + + // Add a few more rewards and repeat the process + _addPoolReward(); + vm.prank(user); + contentPool.withdrawFounds(); + assertGt(frakToken.balanceOf(user), userBalance); + } + + /* -------------------------------------------------------------------------- */ + /* Test helper's */ + /* -------------------------------------------------------------------------- */ + + function _mintFraktionByUser() private { + vm.prank(deployer); + fraktionTokens.mint(user, contentId.commonFraktionId(), 1); + } + + function _addPoolReward() private { + vm.prank(deployer); + contentPool.addReward(contentId, 1 ether); + } } From 08f51ad06e5aac6a9e7f8d3e4ebd829579aa2c5e Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 12:39:49 +0200 Subject: [PATCH 10/16] =?UTF-8?q?=F0=9F=A7=AA=20Add=20a=20few=20more=20con?= =?UTF-8?q?tent=20pool=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 13 +- test/reward/pools/ContentPool.t.sol | 186 +++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 6 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 612b2e1..142e9c5 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,5 +1,14 @@ -ContentPoolTest:test_canBeDeployedAndInit_ok() (gas: 2820906) -ContentPoolTest:test_initialize_InitTwice_ko() (gas: 17926) +ContentPoolTest:test_addReward_InvalidReward_ko() (gas: 28972) +ContentPoolTest:test_addReward_InvalidRole_ko() (gas: 17618) +ContentPoolTest:test_addReward_ok() (gas: 66202) +ContentPoolTest:test_canBeDeployedAndInit_ok() (gas: 2820950) +ContentPoolTest:test_getRewardStates_ok() (gas: 225688) +ContentPoolTest:test_initialize_InitTwice_ko() (gas: 17982) +ContentPoolTest:test_participantStates_ok() (gas: 222845) +ContentPoolTest:test_updateUserAndPool_WithRewardBeforeState_ok() (gas: 432814) +ContentPoolTest:test_updateUserAndPool_ok() (gas: 327157) +ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 720313) +ContentPoolTest:test_updateUser_ok() (gas: 402295) FrakTeasuryWalletTest:test_canBeDeployedAndInit_ok() (gas: 1773426) FrakTeasuryWalletTest:test_initialize_InitTwice_ko() (gas: 17937) FrakTeasuryWalletTest:test_transferBatch_InvalidArray_ko() (gas: 28753) diff --git a/test/reward/pools/ContentPool.t.sol b/test/reward/pools/ContentPool.t.sol index f6d8184..a7bbe8b 100644 --- a/test/reward/pools/ContentPool.t.sol +++ b/test/reward/pools/ContentPool.t.sol @@ -4,7 +4,10 @@ pragma solidity 0.8.21; import { FrakTest } from "../../FrakTest.sol"; import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "contracts/utils/FrakErrors.sol"; import { FrakRoles } from "contracts/roles/FrakRoles.sol"; +import { FraktionId } from "contracts/libs/FraktionId.sol"; +import { ContentId } from "contracts/libs/ContentId.sol"; import { ContentPool } from "contracts/reward/contentPool/ContentPool.sol"; +import { IContentPool } from "contracts/reward/contentPool/IContentPool.sol"; /// @dev Testing methods on the ContentPool contract ContentPoolTest is FrakTest { @@ -69,9 +72,9 @@ contract ContentPoolTest is FrakTest { /* Updating pool & user state */ /* -------------------------------------------------------------------------- */ - function test_updatePool_ok() public { + function test_updateUserAndPool_ok() public { // Simulate fraktion mint by a user - _mintFraktionByUser(); + _mintCommonForUser(); _addPoolReward(); // Compute user rewards & withdraw @@ -87,24 +90,199 @@ contract ContentPoolTest is FrakTest { assertGt(frakToken.balanceOf(user), userBalance); userBalance = frakToken.balanceOf(user); + // Handle the case of a fraktion burn + vm.prank(user); + fraktionTokens.burn(contentId.commonFraktionId(), 1); + + // Add a few more rewards but ensure the user hasn't got any share remaining + _addPoolReward(); + vm.prank(user); + contentPool.withdrawFounds(); + assertEq(frakToken.balanceOf(user), userBalance); + } + + function test_updateUserAndPool_WithRewardBeforeState_ok() public { + // Simulate fraktion mint by a user + _addPoolReward(); + _mintCommonForUser(); + + // Compute user rewards & withdraw + contentPool.computeAllPoolsBalance(user); + contentPool.withdrawFounds(user); + // Assert the user received something + uint256 userBalance = frakToken.balanceOf(user); + assertGt(userBalance, 0); + + // Add a few more rewards and repeat the process + _addPoolReward(); + _mintPremiumForUser(); + contentPool.withdrawFounds(user); + assertGt(frakToken.balanceOf(user), userBalance); + userBalance = frakToken.balanceOf(user); + // Add a few more rewards and repeat the process _addPoolReward(); + vm.prank(user); + fraktionTokens.burn(contentId.commonFraktionId(), 1); + vm.prank(user); contentPool.withdrawFounds(); assertGt(frakToken.balanceOf(user), userBalance); } + /* -------------------------------------------------------------------------- */ + /* Updating user state */ + /* -------------------------------------------------------------------------- */ + + function test_updateUser_ok() public { + // Simulate fraktion mint by a user + _mintCommonForUser(); + _addPoolReward(); + + address targetUser = _newUser("contentPoolTargetUser"); + + // Compute user rewards & withdraw + contentPool.computeAllPoolsBalance(user); + contentPool.withdrawFounds(user); + // Assert the user received something + uint256 userBalance = frakToken.balanceOf(user); + assertGt(userBalance, 0); + + // Transfer the user fraktion to the target user + vm.prank(user); + fraktionTokens.safeTransferFrom(user, targetUser, FraktionId.unwrap(contentId.commonFraktionId()), 1, ""); + + // Add a few more rewards and repeat the process + _addPoolReward(); + contentPool.withdrawFounds(user); + contentPool.withdrawFounds(targetUser); + assertEq(frakToken.balanceOf(user), userBalance); + assertGt(frakToken.balanceOf(targetUser), 0); + assertEq(frakToken.balanceOf(targetUser), userBalance); + } + + function test_updateUser_WithRewardBeforeStateChange_ok() public { + // Simulate fraktion mint by a user + _mintCommonForUser(); + _addPoolReward(); + + address targetUser = _newUser("contentPoolTargetUser"); + + // Compute user rewards & withdraw + contentPool.computeAllPoolsBalance(user); + contentPool.withdrawFounds(user); + // Assert the user received something + uint256 userBalance = frakToken.balanceOf(user); + uint256 targetUserBalance = frakToken.balanceOf(targetUser); + assertGt(userBalance, 0); + assertEq(targetUserBalance, 0); + + // Transfer the user fraktion to the target user + _addPoolReward(); + vm.prank(user); + fraktionTokens.safeTransferFrom(user, targetUser, FraktionId.unwrap(contentId.commonFraktionId()), 1, ""); + _addPoolReward(); + + // Add a few more rewards and repeat the process + contentPool.withdrawFounds(user); + contentPool.withdrawFounds(targetUser); + assertGt(frakToken.balanceOf(user), userBalance); + assertGt(frakToken.balanceOf(targetUser), targetUserBalance); + assertEq(frakToken.balanceOf(targetUser), userBalance); + userBalance = frakToken.balanceOf(user); + targetUserBalance = frakToken.balanceOf(targetUser); + + // Ensure we can can mint some other fraktion and the user will receive more + _mintPremiumForUser(); + _mintGoldForUser(); + _mintDiamondForUser(); + _addPoolReward(); + + // So user has 50 + 100 + 200 = 350 shares + // And target user a only 10 + // So the ratio of the reward should be 35:1 + // Total shares is 360 + // So the user should receive 350/360 * 100 = 97.22 + // And the target user 10/360 * 100 = 2.77 + + // Withdraw the founds for both user + contentPool.withdrawFounds(user); + contentPool.withdrawFounds(targetUser); + + // Ensure the balance changes + uint256 userBalanceChange = frakToken.balanceOf(user) - userBalance; + uint256 targetUserBalanceChange = frakToken.balanceOf(targetUser) - targetUserBalance; + assertGt(userBalanceChange, 0); + assertGt(targetUserBalanceChange, 0); + assertGt(userBalanceChange, targetUserBalanceChange); + assertEq(userBalanceChange / targetUserBalanceChange, 35); + // Ensure amount received + assertAlmostEq(userBalanceChange + targetUserBalanceChange, 100 ether, 1); + // Get the participant share and ensure it's valid + IContentPool.Participant memory userParticipant = + contentPool.getParticipantForContent(ContentId.unwrap(contentId), user); + IContentPool.Participant memory targetUserParticipant = + contentPool.getParticipantForContent(ContentId.unwrap(contentId), targetUser); + // Ensure the ratio is correct + assertEq(userParticipant.shares, 350); + assertEq(targetUserParticipant.shares, 10); + } + + /* -------------------------------------------------------------------------- */ + /* Test view function */ + /* -------------------------------------------------------------------------- */ + + function test_participantStates_ok() public { + _mintCommonForUser(); + IContentPool.ParticipantInPoolState[] memory participantStates = contentPool.getParticipantStates(user); + + assertEq(participantStates.length, 1); + assertEq(participantStates[0].poolId, ContentId.unwrap(contentId)); + assertEq(participantStates[0].totalShares, 10); + assertEq(participantStates[0].poolState, 0); + assertEq(participantStates[0].shares, 10); + assertEq(participantStates[0].lastStateClaimed, 0); + assertEq(participantStates[0].lastStateIndex, 0); + } + + function test_getRewardStates_ok() public { + _addPoolReward(); + _mintCommonForUser(); + + IContentPool.RewardState[] memory rewardStates = contentPool.getAllRewardStates(ContentId.unwrap(contentId)); + + assertEq(rewardStates.length, 1); + assertEq(rewardStates[0].totalShares, 10); + assertEq(rewardStates[0].currentPoolReward, 100 ether); + assertEq(rewardStates[0].open, true); + } + /* -------------------------------------------------------------------------- */ /* Test helper's */ /* -------------------------------------------------------------------------- */ - function _mintFraktionByUser() private { + function _mintCommonForUser() private { vm.prank(deployer); fraktionTokens.mint(user, contentId.commonFraktionId(), 1); } + function _mintPremiumForUser() private { + vm.prank(deployer); + fraktionTokens.mint(user, contentId.premiumFraktionId(), 1); + } + + function _mintGoldForUser() private { + vm.prank(deployer); + fraktionTokens.mint(user, contentId.goldFraktionId(), 1); + } + + function _mintDiamondForUser() private { + vm.prank(deployer); + fraktionTokens.mint(user, contentId.diamondFraktionId(), 1); + } + function _addPoolReward() private { vm.prank(deployer); - contentPool.addReward(contentId, 1 ether); + contentPool.addReward(contentId, 100 ether); } } From 39e39878b7e6345b2a500c5151b0b71ec62784a7 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 14:57:44 +0200 Subject: [PATCH 11/16] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Remove=20the=20use?= =?UTF-8?q?=20of=20the=20supplyAware=20storage=20slot=20on=20fraktion=20to?= =?UTF-8?q?kens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 54 +++++++++---------- contracts/fraktions/FraktionTokens.sol | 35 ++++-------- contracts/reward/Rewarder.sol | 2 - contracts/reward/contentPool/ContentPool.sol | 2 +- contracts/reward/contentPool/IContentPool.sol | 3 +- 5 files changed, 38 insertions(+), 58 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 142e9c5..6483101 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -2,13 +2,13 @@ ContentPoolTest:test_addReward_InvalidReward_ko() (gas: 28972) ContentPoolTest:test_addReward_InvalidRole_ko() (gas: 17618) ContentPoolTest:test_addReward_ok() (gas: 66202) ContentPoolTest:test_canBeDeployedAndInit_ok() (gas: 2820950) -ContentPoolTest:test_getRewardStates_ok() (gas: 225688) +ContentPoolTest:test_getRewardStates_ok() (gas: 223570) ContentPoolTest:test_initialize_InitTwice_ko() (gas: 17982) -ContentPoolTest:test_participantStates_ok() (gas: 222845) -ContentPoolTest:test_updateUserAndPool_WithRewardBeforeState_ok() (gas: 432814) -ContentPoolTest:test_updateUserAndPool_ok() (gas: 327157) -ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 720313) -ContentPoolTest:test_updateUser_ok() (gas: 402295) +ContentPoolTest:test_participantStates_ok() (gas: 220727) +ContentPoolTest:test_updateUserAndPool_WithRewardBeforeState_ok() (gas: 428460) +ContentPoolTest:test_updateUserAndPool_ok() (gas: 325368) +ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 713441) +ContentPoolTest:test_updateUser_ok() (gas: 400506) FrakTeasuryWalletTest:test_canBeDeployedAndInit_ok() (gas: 1773426) FrakTeasuryWalletTest:test_initialize_InitTwice_ko() (gas: 17937) FrakTeasuryWalletTest:test_transferBatch_InvalidArray_ko() (gas: 28753) @@ -23,7 +23,7 @@ FrakTeasuryWalletTest:test_transfer_NotEnoughTreasury_ko() (gas: 11304244) FrakTeasuryWalletTest:test_transfer_NotMinter_ko() (gas: 17684) FrakTeasuryWalletTest:test_transfer_RewardTooLarge_ko() (gas: 20534) FrakTeasuryWalletTest:test_transfer_ok() (gas: 136061) -FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3613) +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3610) FrakTokenTest:test_burn_ok() (gas: 53287) FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) FrakTokenTest:test_cap_ok() (gas: 10366) @@ -46,31 +46,31 @@ FraktionCostBadgesTest:test_updatePrice_ok() (gas: 126474) FraktionTokensTest:test_addContent_InvalidArray_ko() (gas: 22829) FraktionTokensTest:test_addContent_InvalidRole_ko() (gas: 20006) FraktionTokensTest:test_addContent_SupplyUpdateNotAllowed_ko() (gas: 73756) -FraktionTokensTest:test_addContent_ok() (gas: 553828) -FraktionTokensTest:test_batchBalance_ok() (gas: 61905) -FraktionTokensTest:test_burn_ok() (gas: 51278) -FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3412820) +FraktionTokensTest:test_addContent_ok() (gas: 331992) +FraktionTokensTest:test_batchBalance_ok() (gas: 59787) +FraktionTokensTest:test_burn_ok() (gas: 49489) +FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3404604) FraktionTokensTest:test_initialize_InitTwice_ko() (gas: 15986) FraktionTokensTest:test_ownerOf_ok() (gas: 16844) -FraktionTokensTest:test_setUpTransferCallback_ok() (gas: 373467) -FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 55503) +FraktionTokensTest:test_setUpTransferCallback_ok() (gas: 366987) +FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 53385) FraktionTokensTest:test_supply_SupplyRemaining_ko() (gas: 22701) FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45940) -FraktionTokensTest:test_supply_ok() (gas: 90151) +FraktionTokensTest:test_supply_ok() (gas: 87746) MinterTest:test_addContent_InvalidRole_ko() (gas: 17762) MinterTest:test_addContent_InvalidSupply_ko() (gas: 55555) -MinterTest:test_addContent_ok() (gas: 306343) +MinterTest:test_addContent_ok() (gas: 195425) MinterTest:test_canBeDeployedAndInit_ok() (gas: 2171857) -MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 64497) -MinterTest:test_increaseSupply_ok() (gas: 78196) +MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 62379) +MinterTest:test_increaseSupply_ok() (gas: 75909) MinterTest:test_initialize_InitTwice_ko() (gas: 22364) -MinterTest:test_mintFraktionForUser_ok() (gas: 214830) -MinterTest:test_mintFraktion_TooManyFraktion_ko() (gas: 218309) -MinterTest:test_mintFraktion_ok() (gas: 212267) -MinterTest:test_mintFreeFraktionForUser_ok() (gas: 62267) +MinterTest:test_mintFraktionForUser_ok() (gas: 212712) +MinterTest:test_mintFraktion_TooManyFraktion_ko() (gas: 216191) +MinterTest:test_mintFraktion_ok() (gas: 210149) +MinterTest:test_mintFreeFraktionForUser_ok() (gas: 60145) MinterTest:test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() (gas: 40161) -MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 63135) -MinterTest:test_mintFreeFraktion_ok() (gas: 64993) +MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 61013) +MinterTest:test_mintFreeFraktion_ok() (gas: 62871) MultiVestingWalletsTest:test_canBeDeployedAndInit_ok() (gas: 2667336) MultiVestingWalletsTest:test_createVestBatch() (gas: 210722) MultiVestingWalletsTest:test_createVestBatch_ArrayInvalidLength_ko() (gas: 79027) @@ -126,9 +126,9 @@ RewarderTest:test_pay_InvalidAddress_ko() (gas: 21620) RewarderTest:test_pay_InvalidArray_ko() (gas: 38041) RewarderTest:test_pay_InvalidContent_ko() (gas: 56805) RewarderTest:test_pay_InvalidRoles_ko() (gas: 21259) -RewarderTest:test_pay_PayedFraktions_LargeListenCounts_ok() (gas: 375683) -RewarderTest:test_pay_PayedFraktions_TooMuchListenCounts_ko() (gas: 175619) -RewarderTest:test_pay_PayedFraktions_ok() (gas: 413549) -RewarderTest:test_pay_TooLargeReward_ko() (gas: 239180) +RewarderTest:test_pay_PayedFraktions_LargeListenCounts_ok() (gas: 367211) +RewarderTest:test_pay_PayedFraktions_TooMuchListenCounts_ko() (gas: 167147) +RewarderTest:test_pay_PayedFraktions_ok() (gas: 405077) +RewarderTest:test_pay_TooLargeReward_ko() (gas: 230708) VestingWalletFactoryTest:test_canBeDeployedAndInit_ok() (gas: 2093328) VestingWalletFactoryTest:test_initialize_InitTwice_ko() (gas: 17926) \ No newline at end of file diff --git a/contracts/fraktions/FraktionTokens.sol b/contracts/fraktions/FraktionTokens.sol index 0dd11e9..e401fa5 100644 --- a/contracts/fraktions/FraktionTokens.sol +++ b/contracts/fraktions/FraktionTokens.sol @@ -14,8 +14,6 @@ import { InvalidArray } from "../utils/FrakErrors.sol"; /// @title FraktionTokens /// @notice ERC1155 for the Frak Fraktions tokens, used as ownership proof for a content, or investisment proof /// TODO: Global overview : -/// - remove storage dependency for owner (using balanceOf and building content owner fraktion) -/// - remove storage dependency for is supply aware (every fraktion type between 3 to 6 is supply aware) /// - mint content, Single array as param with byte shifting :|supplies|fraktionType| /// @custom:security-contact contact@frak.id contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { @@ -73,13 +71,15 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { FraktionTransferCallback private transferCallback; /// @dev Id of content to owner of this content + /// @notice This is unused now, since we rely on the balanceOf m mapping(uint256 id => address owner) private owners; /// @dev Available supply of each fraktion (classic, rare, epic and legendary only) by they id mapping(uint256 id => uint256 availableSupply) private _availableSupplies; /// @dev Tell us if that fraktion is supply aware or not - mapping(uint256 id => bool isSupplyAware) private _isSupplyAware; + /// @notice unused now since we rely on the fraktion type to know if it's supply aware or not + mapping(uint256 => bool) private _unused1; /// @custom:oz-upgrades-unsafe-allow constructor constructor() { @@ -148,15 +148,9 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { // Get the supply let supply := calldataload(add(supplies.offset, currentOffset)) - // Get the slot to know if it's supply aware, and store true there - // Kecak (id, _isSupplyAware.slot) - mstore(0, fraktionId) - mstore(0x20, _isSupplyAware.slot) - sstore(keccak256(0, 0x40), true) - // Get the supply slot and update it // Kecak (id, _availableSupplies.slot) - // `mstore(0, fraktionId)` -> Not needed since alreaded store on the 0 slot before + mstore(0, fraktionId) mstore(0x20, _availableSupplies.slot) sstore(keccak256(0, 0x40), supply) // Emit the supply updated event @@ -171,11 +165,8 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { // Update creator supply now creatorTokenId := or(shiftedId, 1) - // Get the slot to know if it's supply aware, and store true there - mstore(0, creatorTokenId) - mstore(0x20, _isSupplyAware.slot) - sstore(keccak256(0, 0x40), true) // Then store the available supply of 1 (since only one creator nft is possible) + mstore(0, creatorTokenId) mstore(0x20, _availableSupplies.slot) sstore(keccak256(0, 0x40), 1) } @@ -210,11 +201,6 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { revert(0x1c, 0x04) } - // Get the slot to know if it's supply aware, and store true there - // Kecak (id, _isSupplyAware.slot) - mstore(0, id) - mstore(0x20, _isSupplyAware.slot) - sstore(keccak256(0, 0x40), true) // Get the supply slot and update it sstore(supplySlot, supply) // Emit the supply updated event @@ -267,16 +253,13 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { let id := mload(add(ids, currOffset)) let amount := mload(add(amounts, currOffset)) - // Get the slot to know if it's supply aware - // Kecak (id, _isSupplyAware.slot) - mstore(0, id) - mstore(0x20, _isSupplyAware.slot) - // Supply aware code block - if sload(keccak256(0, 0x40)) { + // If fraktion type == 1 (creator) or fraktion type > 2 & < 7 (payed fraktion) + let fraktionType := and(id, 0xF) + if or(eq(fraktionType, 1), and(gt(fraktionType, 2), lt(fraktionType, 7))) { // Get the supply slot // Kecak (id, _availableSupplies.slot) - // mstore(0, id) -> Don't needed since we already stored the id before in this mem space + mstore(0, id) mstore(0x20, _availableSupplies.slot) let availableSupplySlot := keccak256(0, 0x40) let availableSupply := sload(availableSupplySlot) diff --git a/contracts/reward/Rewarder.sol b/contracts/reward/Rewarder.sol index 897e34d..9fa18f7 100644 --- a/contracts/reward/Rewarder.sol +++ b/contracts/reward/Rewarder.sol @@ -201,8 +201,6 @@ contract Rewarder is // Then, for each content contentIds for (uint256 i; i < contentIds.length;) { - // TODO : Do that in assembly (all the for loops) - // TODO : copy calldata to memory for iteration ? calldatacopy(...) uint256 amount = amounts[i]; assembly { // Ensure the reward is valid diff --git a/contracts/reward/contentPool/ContentPool.sol b/contracts/reward/contentPool/ContentPool.sol index b56ff30..ba5002f 100644 --- a/contracts/reward/contentPool/ContentPool.sol +++ b/contracts/reward/contentPool/ContentPool.sol @@ -59,7 +59,7 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa /* -------------------------------------------------------------------------- */ /// @dev The index of the current state index per content - /// TODO : This is unused now since we use the array length (more effecient since we perform a first sload on the + /// This is unused now since we use the array length (more effecient since we perform a first sload on the /// mapping, and we need to do it anyway) mapping(uint256 => uint256) private currentStateIndex; diff --git a/contracts/reward/contentPool/IContentPool.sol b/contracts/reward/contentPool/IContentPool.sol index f756767..f5ced9f 100644 --- a/contracts/reward/contentPool/IContentPool.sol +++ b/contracts/reward/contentPool/IContentPool.sol @@ -55,8 +55,7 @@ interface IContentPool is FraktionTransferCallback { uint120 shares; // Number of shares in the content pool, pos : 0x0 <-> 0x0F uint96 lastStateClaim; // The last state amount claimed, pos : 0x0F + 0x0C -> 0x0F <-> 0x1B // Second storage slot - uint256 lastStateIndex; // What was the last state index he claimed in the pool ? -> TODO : 0x20 or Ox1B -> - // (0x0F + 0x0C) + uint256 lastStateIndex; // What was the last state index he claimed in the pool ? } /** From 432fae34c16622604fb23d23fe898ec1a3b12f79 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 15:52:00 +0200 Subject: [PATCH 12/16] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Switch=20to=20single?= =?UTF-8?q?=20array=20for=20new=20content=20minting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 68 +++++++++++++------------- contracts/fraktions/FraktionTokens.sol | 45 +++++++---------- contracts/minter/Minter.sol | 28 ++++------- test/fraktions/FraktionTokens.t.sol | 55 ++++++++------------- test/reward/pools/ContentPool.t.sol | 33 +++++++++++++ 5 files changed, 114 insertions(+), 115 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 6483101..adf4c2a 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,14 +1,15 @@ ContentPoolTest:test_addReward_InvalidReward_ko() (gas: 28972) -ContentPoolTest:test_addReward_InvalidRole_ko() (gas: 17618) +ContentPoolTest:test_addReward_InvalidRole_ko() (gas: 17640) ContentPoolTest:test_addReward_ok() (gas: 66202) -ContentPoolTest:test_canBeDeployedAndInit_ok() (gas: 2820950) -ContentPoolTest:test_getRewardStates_ok() (gas: 223570) +ContentPoolTest:test_canBeDeployedAndInit_ok() (gas: 2820972) +ContentPoolTest:test_getRewardStates_ok() (gas: 223640) ContentPoolTest:test_initialize_InitTwice_ko() (gas: 17982) -ContentPoolTest:test_participantStates_ok() (gas: 220727) -ContentPoolTest:test_updateUserAndPool_WithRewardBeforeState_ok() (gas: 428460) -ContentPoolTest:test_updateUserAndPool_ok() (gas: 325368) -ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 713441) -ContentPoolTest:test_updateUser_ok() (gas: 400506) +ContentPoolTest:test_participantStates_ok() (gas: 220730) +ContentPoolTest:test_updateUserAndPool_WithRewardBeforeState_ok() (gas: 428687) +ContentPoolTest:test_updateUserAndPool_ok() (gas: 325512) +ContentPoolTest:test_updateUser_MultiTokenTransfer_ok() (gas: 539456) +ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 713201) +ContentPoolTest:test_updateUser_ok() (gas: 400231) FrakTeasuryWalletTest:test_canBeDeployedAndInit_ok() (gas: 1773426) FrakTeasuryWalletTest:test_initialize_InitTwice_ko() (gas: 17937) FrakTeasuryWalletTest:test_transferBatch_InvalidArray_ko() (gas: 28753) @@ -23,7 +24,7 @@ FrakTeasuryWalletTest:test_transfer_NotEnoughTreasury_ko() (gas: 11304244) FrakTeasuryWalletTest:test_transfer_NotMinter_ko() (gas: 17684) FrakTeasuryWalletTest:test_transfer_RewardTooLarge_ko() (gas: 20534) FrakTeasuryWalletTest:test_transfer_ok() (gas: 136061) -FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3610) +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3601) FrakTokenTest:test_burn_ok() (gas: 53287) FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) FrakTokenTest:test_cap_ok() (gas: 10366) @@ -43,34 +44,33 @@ FraktionCostBadgesTest:test_defaultPrice_ok() (gas: 26214) FraktionCostBadgesTest:test_updatePrice_InvalidFraktionType_ko() (gas: 46174) FraktionCostBadgesTest:test_updatePrice_InvalidRole_ko() (gas: 17638) FraktionCostBadgesTest:test_updatePrice_ok() (gas: 126474) -FraktionTokensTest:test_addContent_InvalidArray_ko() (gas: 22829) -FraktionTokensTest:test_addContent_InvalidRole_ko() (gas: 20006) -FraktionTokensTest:test_addContent_SupplyUpdateNotAllowed_ko() (gas: 73756) -FraktionTokensTest:test_addContent_ok() (gas: 331992) -FraktionTokensTest:test_batchBalance_ok() (gas: 59787) -FraktionTokensTest:test_burn_ok() (gas: 49489) -FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3404604) +FraktionTokensTest:test_addContent_InvalidRole_ko() (gas: 18772) +FraktionTokensTest:test_addContent_SupplyUpdateNotAllowed_ko() (gas: 69957) +FraktionTokensTest:test_addContent_ok() (gas: 329982) +FraktionTokensTest:test_batchBalance_ok() (gas: 59813) +FraktionTokensTest:test_burn_ok() (gas: 49562) +FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3386823) FraktionTokensTest:test_initialize_InitTwice_ko() (gas: 15986) FraktionTokensTest:test_ownerOf_ok() (gas: 16844) -FraktionTokensTest:test_setUpTransferCallback_ok() (gas: 366987) -FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 53385) +FraktionTokensTest:test_setUpTransferCallback_ok() (gas: 367201) +FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 53366) FraktionTokensTest:test_supply_SupplyRemaining_ko() (gas: 22701) -FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45940) -FraktionTokensTest:test_supply_ok() (gas: 87746) +FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45918) +FraktionTokensTest:test_supply_ok() (gas: 87732) MinterTest:test_addContent_InvalidRole_ko() (gas: 17762) MinterTest:test_addContent_InvalidSupply_ko() (gas: 55555) -MinterTest:test_addContent_ok() (gas: 195425) -MinterTest:test_canBeDeployedAndInit_ok() (gas: 2171857) -MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 62379) -MinterTest:test_increaseSupply_ok() (gas: 75909) +MinterTest:test_addContent_ok() (gas: 194470) +MinterTest:test_canBeDeployedAndInit_ok() (gas: 2160631) +MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 62405) +MinterTest:test_increaseSupply_ok() (gas: 75913) MinterTest:test_initialize_InitTwice_ko() (gas: 22364) -MinterTest:test_mintFraktionForUser_ok() (gas: 212712) -MinterTest:test_mintFraktion_TooManyFraktion_ko() (gas: 216191) -MinterTest:test_mintFraktion_ok() (gas: 210149) -MinterTest:test_mintFreeFraktionForUser_ok() (gas: 60145) +MinterTest:test_mintFraktionForUser_ok() (gas: 212760) +MinterTest:test_mintFraktion_TooManyFraktion_ko() (gas: 216239) +MinterTest:test_mintFraktion_ok() (gas: 210197) +MinterTest:test_mintFreeFraktionForUser_ok() (gas: 60193) MinterTest:test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() (gas: 40161) -MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 61013) -MinterTest:test_mintFreeFraktion_ok() (gas: 62871) +MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 61061) +MinterTest:test_mintFreeFraktion_ok() (gas: 62919) MultiVestingWalletsTest:test_canBeDeployedAndInit_ok() (gas: 2667336) MultiVestingWalletsTest:test_createVestBatch() (gas: 210722) MultiVestingWalletsTest:test_createVestBatch_ArrayInvalidLength_ko() (gas: 79027) @@ -126,9 +126,9 @@ RewarderTest:test_pay_InvalidAddress_ko() (gas: 21620) RewarderTest:test_pay_InvalidArray_ko() (gas: 38041) RewarderTest:test_pay_InvalidContent_ko() (gas: 56805) RewarderTest:test_pay_InvalidRoles_ko() (gas: 21259) -RewarderTest:test_pay_PayedFraktions_LargeListenCounts_ok() (gas: 367211) -RewarderTest:test_pay_PayedFraktions_TooMuchListenCounts_ko() (gas: 167147) -RewarderTest:test_pay_PayedFraktions_ok() (gas: 405077) -RewarderTest:test_pay_TooLargeReward_ko() (gas: 230708) +RewarderTest:test_pay_PayedFraktions_LargeListenCounts_ok() (gas: 367403) +RewarderTest:test_pay_PayedFraktions_TooMuchListenCounts_ko() (gas: 167339) +RewarderTest:test_pay_PayedFraktions_ok() (gas: 405269) +RewarderTest:test_pay_TooLargeReward_ko() (gas: 230900) VestingWalletFactoryTest:test_canBeDeployedAndInit_ok() (gas: 2093328) VestingWalletFactoryTest:test_initialize_InitTwice_ko() (gas: 17926) \ No newline at end of file diff --git a/contracts/fraktions/FraktionTokens.sol b/contracts/fraktions/FraktionTokens.sol index e401fa5..3f0991d 100644 --- a/contracts/fraktions/FraktionTokens.sol +++ b/contracts/fraktions/FraktionTokens.sol @@ -13,8 +13,6 @@ import { InvalidArray } from "../utils/FrakErrors.sol"; /// @author @KONFeature /// @title FraktionTokens /// @notice ERC1155 for the Frak Fraktions tokens, used as ownership proof for a content, or investisment proof -/// TODO: Global overview : -/// - mint content, Single array as param with byte shifting :|supplies|fraktionType| /// @custom:security-contact contact@frak.id contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /* -------------------------------------------------------------------------- */ @@ -97,13 +95,13 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /* External write function's */ /* -------------------------------------------------------------------------- */ - /** - * @dev Mint a new content, return the id of the built content - */ + /// @dev Mint a new content, return the id of the built content + /// @param ownerAddress The address of the content owner + /// @param suppliesToType The supplies to type array, each element of the array is a tuple on a byte [supply, type], + /// type on 0xf, supply on all the remaining bytes function mintNewContent( address ownerAddress, - uint256[] calldata fraktionTypes, - uint256[] calldata supplies + uint256[] calldata suppliesToType ) external payable @@ -112,12 +110,6 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { { uint256 creatorTokenId; assembly { - // Ensure we got valid data - if or(iszero(fraktionTypes.length), iszero(eq(fraktionTypes.length, supplies.length))) { - mstore(0x00, _INVALID_ARRAY_SELECTOR) - revert(0x1c, 0x04) - } - // Get the next content id and increment the current content id id := add(sload(_currentContentId.slot), 1) sstore(_currentContentId.slot, id) @@ -127,13 +119,14 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { // Iterate over each fraktion type, build their id, and set their supply // Get where our offset end - let offsetEnd := shl(5, fraktionTypes.length) + let offsetEnd := shl(5, suppliesToType.length) // Current iterator offset let currentOffset := 0 // Infinite loop for { } 1 { } { // Get the current id - let fraktionType := calldataload(add(fraktionTypes.offset, currentOffset)) + let currentItem := calldataload(add(suppliesToType.offset, currentOffset)) + let fraktionType := and(currentItem, 0xF) // Ensure the supply update of this fraktion type is allowed if or(lt(fraktionType, 3), gt(fraktionType, 6)) { @@ -146,7 +139,7 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { let fraktionId := or(shiftedId, fraktionType) // Get the supply - let supply := calldataload(add(supplies.offset, currentOffset)) + let supply := shr(4, currentItem) // Get the supply slot and update it // Kecak (id, _availableSupplies.slot) @@ -178,9 +171,7 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { return id; } - /** - * @dev Set the supply for the given fraktion id - */ + /// @dev Set the supply for the given fraktion id function setSupply(FraktionId id, uint256 supply) external payable onlyRole(FrakRoles.MINTER) { assembly { // Ensure the supply update of this fraktion type is allowed @@ -228,9 +219,7 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /* Internal callback function's */ /* -------------------------------------------------------------------------- */ - /** - * @dev Handle the transfer token (so update the content investor, change the owner of some content etc) - */ + /// @dev Handle the transfer token (so update the content investor, change the owner of some content etc) function _beforeTokenTransfer( address, address from, @@ -242,6 +231,10 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { internal override { + // Directly exit if we are not concerned by a mint or burn + if (from != address(0) && to != address(0)) return; + + // Assembly block to check supply and decrease it if needed assembly { // Base offset to access array element's let currOffset := 0x20 @@ -283,9 +276,7 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { } } - /** - * @dev Handle the transfer token (so update the content investor, change the owner of some content etc) - */ + /// @dev Handle the transfer token (so update the content investor, change the owner of some content etc) function _afterTokenTransfer( address, address from, @@ -347,9 +338,7 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /* Public view function's */ /* -------------------------------------------------------------------------- */ - /** - * @dev Batch balance of for single address - */ + /// @dev Batch balance of for single address function balanceOfIdsBatch( address account, FraktionId[] calldata ids diff --git a/contracts/minter/Minter.sol b/contracts/minter/Minter.sol index ff75129..ee907d5 100644 --- a/contracts/minter/Minter.sol +++ b/contracts/minter/Minter.sol @@ -145,30 +145,22 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu } } // Then set the supply for each fraktion types - uint256[] memory fraktionTypes; - uint256[] memory supplies; + uint256[] memory suppliesToType; assembly { // Init our array's - fraktionTypes := mload(0x40) - supplies := add(fraktionTypes, 0x100) // 0x100 Since -> 0 length, then 4 * 32 bytes for each uint256 - // Init our array's length - mstore(fraktionTypes, 4) - mstore(supplies, 4) + suppliesToType := mload(0x40) // Update our free mem pointer - mstore(0x40, add(supplies, 0x100)) + mstore(0x40, add(suppliesToType, 0x100)) + // Init our array's length + mstore(suppliesToType, 4) // Store the fraktionTypes - mstore(add(fraktionTypes, 0x20), 3) - mstore(add(fraktionTypes, 0x40), 4) - mstore(add(fraktionTypes, 0x60), 5) - mstore(add(fraktionTypes, 0x80), 6) - // Store the supplies - mstore(add(supplies, 0x20), commonSupply) - mstore(add(supplies, 0x40), premiumSupply) - mstore(add(supplies, 0x60), goldSupply) - mstore(add(supplies, 0x80), diamondSupply) + mstore(add(suppliesToType, 0x20), or(shl(4, commonSupply), 3)) + mstore(add(suppliesToType, 0x40), or(shl(4, premiumSupply), 4)) + mstore(add(suppliesToType, 0x60), or(shl(4, goldSupply), 5)) + mstore(add(suppliesToType, 0x80), or(shl(4, diamondSupply), 6)) } // Try to mint the new content - contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fraktionTypes, supplies); + contentId = fraktionTokens.mintNewContent(contentOwnerAddress, suppliesToType); assembly { // Emit the content minted event mstore(0, contentId) diff --git a/test/fraktions/FraktionTokens.t.sol b/test/fraktions/FraktionTokens.t.sol index 313b87b..9c0cbdd 100644 --- a/test/fraktions/FraktionTokens.t.sol +++ b/test/fraktions/FraktionTokens.t.sol @@ -36,8 +36,8 @@ contract FraktionTokensTest is FrakTest { /* -------------------------------------------------------------------------- */ function test_addContent_ok() public asDeployer { - (uint256[] memory types, uint256[] memory supplies) = _getMintContentParams(); - ContentId contentId = fraktionTokens.mintNewContent(contentOwner, types, supplies); + uint256[] memory suppliesToType = _getMintContentParams(); + ContentId contentId = fraktionTokens.mintNewContent(contentOwner, suppliesToType); // Ensure the content is well created, with valid supply assertEq(fraktionTokens.ownerOf(contentId), contentOwner); @@ -47,43 +47,35 @@ contract FraktionTokensTest is FrakTest { assertEq(fraktionTokens.supplyOf(contentId.diamondFraktionId()), 10); // Ensure that two content id are not the same - ContentId newContentId = fraktionTokens.mintNewContent(contentOwner, types, supplies); + ContentId newContentId = fraktionTokens.mintNewContent(contentOwner, suppliesToType); assertNotEq(ContentId.unwrap(contentId), ContentId.unwrap(newContentId)); } function test_addContent_InvalidRole_ko() public { - (uint256[] memory types, uint256[] memory supplies) = _getMintContentParams(); + uint256[] memory suppliesToType = _getMintContentParams(); vm.expectRevert(NotAuthorized.selector); - fraktionTokens.mintNewContent(contentOwner, types, supplies); - } - - function test_addContent_InvalidArray_ko() public asDeployer { - (uint256[] memory types,) = _getMintContentParams(); - uint256[] memory supplies = new uint256[](2); - - vm.expectRevert(InvalidArray.selector); - fraktionTokens.mintNewContent(contentOwner, types, supplies); + fraktionTokens.mintNewContent(contentOwner, suppliesToType); } function test_addContent_SupplyUpdateNotAllowed_ko() public asDeployer { - (uint256[] memory types, uint256[] memory supplies) = _getMintContentParams(); + uint256[] memory suppliesToType = _getMintContentParams(); - types[0] = 0; + suppliesToType[0] = 0; vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.mintNewContent(contentOwner, types, supplies); + fraktionTokens.mintNewContent(contentOwner, suppliesToType); - types[0] = 1; + suppliesToType[0] = 1; vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.mintNewContent(contentOwner, types, supplies); + fraktionTokens.mintNewContent(contentOwner, suppliesToType); - types[0] = 2; + suppliesToType[0] = 2; vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.mintNewContent(contentOwner, types, supplies); + fraktionTokens.mintNewContent(contentOwner, suppliesToType); - types[0] = 7; + suppliesToType[0] = 7; vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.mintNewContent(contentOwner, types, supplies); + fraktionTokens.mintNewContent(contentOwner, suppliesToType); } /* -------------------------------------------------------------------------- */ @@ -214,20 +206,13 @@ contract FraktionTokensTest is FrakTest { /* Some helper's */ /* -------------------------------------------------------------------------- */ - function _getMintContentParams() internal pure returns (uint256[] memory types, uint256[] memory supplies) { + function _getMintContentParams() internal pure returns (uint256[] memory suppliesToType) { // Build the array of types (payable fraktion type) - types = new uint256[](4); - types[0] = ContentIdLib.FRAKTION_TYPE_COMMON; - types[1] = ContentIdLib.FRAKTION_TYPE_PREMIUM; - types[2] = ContentIdLib.FRAKTION_TYPE_GOLD; - types[3] = ContentIdLib.FRAKTION_TYPE_DIAMOND; - - // Build the array of supplies - supplies = new uint256[](4); - supplies[0] = 100; - supplies[1] = 50; - supplies[2] = 25; - supplies[3] = 10; + suppliesToType = new uint256[](4); + suppliesToType[0] = 100 << 4 | ContentIdLib.FRAKTION_TYPE_COMMON; + suppliesToType[1] = 50 << 4 | ContentIdLib.FRAKTION_TYPE_PREMIUM; + suppliesToType[2] = 25 << 4 | ContentIdLib.FRAKTION_TYPE_GOLD; + suppliesToType[3] = 10 << 4 | ContentIdLib.FRAKTION_TYPE_DIAMOND; } } diff --git a/test/reward/pools/ContentPool.t.sol b/test/reward/pools/ContentPool.t.sol index a7bbe8b..a426ed5 100644 --- a/test/reward/pools/ContentPool.t.sol +++ b/test/reward/pools/ContentPool.t.sol @@ -228,6 +228,39 @@ contract ContentPoolTest is FrakTest { assertEq(targetUserParticipant.shares, 10); } + function test_updateUser_MultiTokenTransfer_ok() public { + // Simulate fraktion mint by a user + _mintCommonForUser(); + _mintGoldForUser(); + _mintDiamondForUser(); + _addPoolReward(); + + address targetUser = _newUser("contentPoolTargetUser"); + + // Compute user rewards & withdraw + contentPool.computeAllPoolsBalance(user); + contentPool.withdrawFounds(user); + // Assert the user received something + assertGt(frakToken.balanceOf(user), 0); + + // Transfer the user fraktion to the target user + uint256[] memory idsToTransfer = new uint256[](2); + idsToTransfer[0] = FraktionId.unwrap(contentId.commonFraktionId()); + idsToTransfer[1] = FraktionId.unwrap(contentId.diamondFraktionId()); + uint256[] memory amountsToTransfer = new uint256[](2); + amountsToTransfer[0] = 1; + amountsToTransfer[1] = 1; + + vm.prank(user); + fraktionTokens.safeBatchTransferFrom(user, targetUser, idsToTransfer, amountsToTransfer, ""); + + // Add a few more rewards and repeat the process + _addPoolReward(); + contentPool.withdrawFounds(targetUser); + assertGt(frakToken.balanceOf(user), 0); + assertGt(frakToken.balanceOf(targetUser), 0); + } + /* -------------------------------------------------------------------------- */ /* Test view function */ /* -------------------------------------------------------------------------- */ From a0a3f82df42555b73223dc269468b6494ff54a14 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 16:20:56 +0200 Subject: [PATCH 13/16] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20Fix=20content=20pool?= =?UTF-8?q?=20typos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/reward/contentPool/ContentPool.sol | 22 ++++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/contracts/reward/contentPool/ContentPool.sol b/contracts/reward/contentPool/ContentPool.sol index ba5002f..6b199a2 100644 --- a/contracts/reward/contentPool/ContentPool.sol +++ b/contracts/reward/contentPool/ContentPool.sol @@ -101,7 +101,7 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa } } // Get the current state - RewardState storage currentState = lastContentState(ContentId.unwrap(contentId)); + RewardState storage currentState = _lastContentState(ContentId.unwrap(contentId)); if (!currentState.open) revert PoolStateClosed(); // Increase the reward @@ -132,7 +132,7 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa if (from != address(0) && to != address(0)) { // Handle share transfer between participant, with no update on the total pool rewards for (uint256 index; index < ids.length;) { - updateParticipants(accounter, ids[index], amount[index]); + _updateParticipants(accounter, ids[index], amount[index]); unchecked { ++index; } @@ -140,7 +140,7 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa } else { // Otherwise (in case of mined or burned token), also update the pool for (uint256 index; index < ids.length;) { - updateParticipantAndPool(accounter, ids[index], amount[index]); + _updateParticipantAndPool(accounter, ids[index], amount[index]); unchecked { ++index; } @@ -182,7 +182,7 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa /// @param accounter The accounter to use to update the participants /// @param fraktionId The fraktion id that was transfered /// @param amountMoved The amount of fraktion that was transfered - function updateParticipants( + function _updateParticipants( FraktionTransferAccounter memory accounter, FraktionId fraktionId, uint256 amountMoved @@ -231,7 +231,7 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa /// @param accounter The accounter to use to update the participants /// @param fraktionId The fraktion id that was transfered /// @param amountMoved The amount of fraktion that was transfered - function updateParticipantAndPool( + function _updateParticipantAndPool( FraktionTransferAccounter memory accounter, FraktionId fraktionId, uint256 amountMoved @@ -447,19 +447,19 @@ contract ContentPool is IContentPool, FrakAccessControlUpgradeable, PushPullRewa /// @dev Reset a participant state to the last reward state function _resetParticipantState(RewardState[] storage contentStates, Participant storage participant) private { // Get the last content state index - uint256 lastContentStateIndex = contentStates.length - 1; + uint256 _lastContentStateIndex = contentStates.length - 1; // Reset the participant state - participant.lastStateIndex = lastContentStateIndex; - participant.lastStateClaim = uint96(computeUserReward(contentStates[lastContentStateIndex], participant)); + participant.lastStateIndex = _lastContentStateIndex; + participant.lastStateClaim = uint96(computeUserReward(contentStates[_lastContentStateIndex], participant)); } /// @dev Get the latest content `state` for the given `contentId` - function lastContentState(uint256 contentId) private returns (RewardState storage state) { - (state,) = lastContentStateWithIndex(contentId); + function _lastContentState(uint256 contentId) private returns (RewardState storage state) { + (state,) = _lastContentStateWithIndex(contentId); } /// @dev Get the latest content `state` and `index` for the given `contentId` - function lastContentStateWithIndex(uint256 contentId) + function _lastContentStateWithIndex(uint256 contentId) private returns (RewardState storage state, uint256 rewardIndex) { From 909cf618131c82827cabc5e8ad16656d66cb142d Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 17:04:00 +0200 Subject: [PATCH 14/16] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Add=20direct=20mint?= =?UTF-8?q?=20method's?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contracts/minter/IMinter.sol | 6 +++ contracts/minter/Minter.sol | 72 ++++++++++++++++++++++++++++++++++++ test/minter/Minter.t.sol | 34 +++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/contracts/minter/IMinter.sol b/contracts/minter/IMinter.sol index b65bb8e..62c8060 100644 --- a/contracts/minter/IMinter.sol +++ b/contracts/minter/IMinter.sol @@ -54,6 +54,12 @@ interface IMinter { payable returns (ContentId contentId); + /// @dev Add a new auto minted content in our system + function addAutoMintedContent(address autoMintHolder) external payable returns (ContentId contentId); + + /// @dev Add a content when a creator asked for it + function addContentForCreator(address contentOwnerAddress) external payable returns (ContentId contentId); + /** * @notice Mint a new fraktion for the given amount and user * @dev Will compute the fraktion price, ensure the user have enough Frk to buy it, if try, perform the transfer diff --git a/contracts/minter/Minter.sol b/contracts/minter/Minter.sol index ee907d5..3d15bcd 100644 --- a/contracts/minter/Minter.sol +++ b/contracts/minter/Minter.sol @@ -168,6 +168,78 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu } } + /// @dev Add an autominted content holder + function addAutoMintedContent(address autoMintHolder) + external + payable + override + onlyRole(FrakRoles.MINTER) + returns (ContentId contentId) + { + // Each typplies to types array + uint256[] memory suppliesToType; + assembly { + // Check owner address + if iszero(autoMintHolder) { + mstore(0x00, _INVALID_ADDRESS_SELECTOR) + revert(0x1c, 0x04) + } + // Init our array's + suppliesToType := mload(0x40) + // Update our free mem pointer + mstore(0x40, add(suppliesToType, 0x40)) + // Init our array's length + mstore(suppliesToType, 1) + // Store the fraktionTypes (only 1 supply of common fraktion) + mstore(add(suppliesToType, 0x20), or(shl(4, 1), 3)) + } + // Try to mint the new content + contentId = fraktionTokens.mintNewContent(autoMintHolder, suppliesToType); + assembly { + // Emit the content minted event + mstore(0, contentId) + log2(0, 0x20, _CONTENT_MINTED_EVENT_SELECTOR, autoMintHolder) + } + } + + /// @dev Add a content for a creator + function addContentForCreator(address contentOwnerAddress) + external + payable + override + onlyRole(FrakRoles.MINTER) + returns (ContentId contentId) + { + // Each typplies to types array + uint256[] memory suppliesToType; + assembly { + // Check owner address + if iszero(contentOwnerAddress) { + mstore(0x00, _INVALID_ADDRESS_SELECTOR) + revert(0x1c, 0x04) + } + // Init our array's + suppliesToType := mload(0x40) + // Update our free mem pointer + mstore(0x40, add(suppliesToType, 0x100)) + // Init our array's length + mstore(suppliesToType, 4) + // Store the fraktionTypes + // We can keep shifting since it will be replaced by constant by the compiler + mstore(add(suppliesToType, 0x20), or(shl(4, 20), 3)) + mstore(add(suppliesToType, 0x40), or(shl(4, 7), 4)) + mstore(add(suppliesToType, 0x60), or(shl(4, 3), 5)) + mstore(add(suppliesToType, 0x80), or(shl(4, 1), 6)) + } + // Try to mint the new content + contentId = fraktionTokens.mintNewContent(contentOwnerAddress, suppliesToType); + assembly { + // Emit the content minted event + mstore(0, contentId) + log2(0, 0x20, _CONTENT_MINTED_EVENT_SELECTOR, contentOwnerAddress) + } + } + /** * @notice Mint a new fraktion for the given amount and user * @dev Will compute the fraktion price, ensure the user have enough Frk to buy it, if try, perform the transfer diff --git a/test/minter/Minter.t.sol b/test/minter/Minter.t.sol index 8ccc99a..650b916 100644 --- a/test/minter/Minter.t.sol +++ b/test/minter/Minter.t.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GNU GPLv3 pragma solidity 0.8.21; +import "forge-std/console.sol"; import { FrakTest } from "../FrakTest.sol"; import { NotAuthorized, InvalidArray } from "contracts/utils/FrakErrors.sol"; import { FraktionTokens } from "contracts/fraktions/FraktionTokens.sol"; @@ -71,6 +72,39 @@ contract MinterTest is FrakTest { minter.addContent(contentOwner, 20, 7, 3, 21); } + /// @dev Different mint method's benchmark + function test_benchmarkAddContent_ok() public asDeployer { + // Warm up storage + minter.addAutoMintedContent(contentOwner); + minter.addContent(contentOwner, 1, 0, 0, 0); + + uint256 gasLeft = gasleft(); + minter.addAutoMintedContent(contentOwner); + uint256 gasUsed = gasLeft - gasleft(); + + console.log("- Automint"); + console.log("-- Automint method used: %d", gasUsed); + + // Build supply for 1 common only + gasLeft = gasleft(); + minter.addContent(contentOwner, 1, 0, 0, 0); + gasUsed = gasLeft - gasleft(); + console.log("-- Classic mint method : %d", gasUsed); + + // Creator mint test + console.log("- Creator"); + gasLeft = gasleft(); + minter.addContentForCreator(contentOwner); + gasUsed = gasLeft - gasleft(); + console.log("-- Creator method used: %d", gasUsed); + + // Build supply for 20, 7, 3, 1 + gasLeft = gasleft(); + minter.addContent(contentOwner, 20, 7, 3, 1); + gasUsed = gasLeft - gasleft(); + console.log("-- Classic mint method : %d", gasUsed); + } + /* -------------------------------------------------------------------------- */ /* Free fraktion mint */ /* -------------------------------------------------------------------------- */ From 80fa316cb3cc98fec906fd4507a113109c7399cc Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 18:41:33 +0200 Subject: [PATCH 15/16] =?UTF-8?q?=F0=9F=90=9B=20Remove=20remaining=20suppl?= =?UTF-8?q?y=20check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gas-snapshot | 44 +++++++++++++------------- contracts/fraktions/FraktionTokens.sol | 17 ++-------- contracts/minter/Minter.sol | 2 +- test/fraktions/FraktionTokens.t.sol | 17 ++++------ test_old/minter/Minter.t.sol | 8 ----- 5 files changed, 31 insertions(+), 57 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index adf4c2a..7262583 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -8,8 +8,8 @@ ContentPoolTest:test_participantStates_ok() (gas: 220730) ContentPoolTest:test_updateUserAndPool_WithRewardBeforeState_ok() (gas: 428687) ContentPoolTest:test_updateUserAndPool_ok() (gas: 325512) ContentPoolTest:test_updateUser_MultiTokenTransfer_ok() (gas: 539456) -ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 713201) -ContentPoolTest:test_updateUser_ok() (gas: 400231) +ContentPoolTest:test_updateUser_WithRewardBeforeStateChange_ok() (gas: 713219) +ContentPoolTest:test_updateUser_ok() (gas: 400248) FrakTeasuryWalletTest:test_canBeDeployedAndInit_ok() (gas: 1773426) FrakTeasuryWalletTest:test_initialize_InitTwice_ko() (gas: 17937) FrakTeasuryWalletTest:test_transferBatch_InvalidArray_ko() (gas: 28753) @@ -24,7 +24,7 @@ FrakTeasuryWalletTest:test_transfer_NotEnoughTreasury_ko() (gas: 11304244) FrakTeasuryWalletTest:test_transfer_NotMinter_ko() (gas: 17684) FrakTeasuryWalletTest:test_transfer_RewardTooLarge_ko() (gas: 20534) FrakTeasuryWalletTest:test_transfer_ok() (gas: 136061) -FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3601) +FrakTokenTest:invariant_cap_lt_supply() (runs: 256, calls: 3840, reverts: 3633) FrakTokenTest:test_burn_ok() (gas: 53287) FrakTokenTest:test_canBeDeployedAndInit_ok() (gas: 2502575) FrakTokenTest:test_cap_ok() (gas: 10366) @@ -41,36 +41,36 @@ FrakTokenTest:test_permit_ok() (gas: 77672) FrakTokenTest:test_symbol_ok() (gas: 14797) FraktionCostBadgesTest:test_defaultPrice_InvalidFraktionType_ko() (gas: 43272) FraktionCostBadgesTest:test_defaultPrice_ok() (gas: 26214) -FraktionCostBadgesTest:test_updatePrice_InvalidFraktionType_ko() (gas: 46174) -FraktionCostBadgesTest:test_updatePrice_InvalidRole_ko() (gas: 17638) -FraktionCostBadgesTest:test_updatePrice_ok() (gas: 126474) +FraktionCostBadgesTest:test_updatePrice_InvalidFraktionType_ko() (gas: 46266) +FraktionCostBadgesTest:test_updatePrice_InvalidRole_ko() (gas: 17661) +FraktionCostBadgesTest:test_updatePrice_ok() (gas: 126566) FraktionTokensTest:test_addContent_InvalidRole_ko() (gas: 18772) FraktionTokensTest:test_addContent_SupplyUpdateNotAllowed_ko() (gas: 69957) FraktionTokensTest:test_addContent_ok() (gas: 329982) FraktionTokensTest:test_batchBalance_ok() (gas: 59813) FraktionTokensTest:test_burn_ok() (gas: 49562) -FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3386823) -FraktionTokensTest:test_initialize_InitTwice_ko() (gas: 15986) +FraktionTokensTest:test_canBeDeployedAndInit_ok() (gas: 3382823) +FraktionTokensTest:test_initialize_InitTwice_ko() (gas: 16008) FraktionTokensTest:test_ownerOf_ok() (gas: 16844) FraktionTokensTest:test_setUpTransferCallback_ok() (gas: 367201) -FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 53366) -FraktionTokensTest:test_supply_SupplyRemaining_ko() (gas: 22701) -FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45918) -FraktionTokensTest:test_supply_ok() (gas: 87732) -MinterTest:test_addContent_InvalidRole_ko() (gas: 17762) -MinterTest:test_addContent_InvalidSupply_ko() (gas: 55555) -MinterTest:test_addContent_ok() (gas: 194470) -MinterTest:test_canBeDeployedAndInit_ok() (gas: 2160631) -MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 62405) -MinterTest:test_increaseSupply_ok() (gas: 75913) -MinterTest:test_initialize_InitTwice_ko() (gas: 22364) -MinterTest:test_mintFraktionForUser_ok() (gas: 212760) +FraktionTokensTest:test_supply_InvalidRole_ko() (gas: 53345) +FraktionTokensTest:test_supply_SupplyUpdateNotAllowed_ko() (gas: 45822) +FraktionTokensTest:test_supply_ok() (gas: 87692) +MinterTest:test_addContent_InvalidRole_ko() (gas: 17808) +MinterTest:test_addContent_InvalidSupply_ko() (gas: 55648) +MinterTest:test_addContent_ok() (gas: 194493) +MinterTest:test_benchmarkAddContent_ok() (gas: 695249) +MinterTest:test_canBeDeployedAndInit_ok() (gas: 2276712) +MinterTest:test_increaseSupply_InvalidRole_ko() (gas: 62383) +MinterTest:test_increaseSupply_ok() (gas: 75939) +MinterTest:test_initialize_InitTwice_ko() (gas: 22408) +MinterTest:test_mintFraktionForUser_ok() (gas: 212716) MinterTest:test_mintFraktion_TooManyFraktion_ko() (gas: 216239) -MinterTest:test_mintFraktion_ok() (gas: 210197) +MinterTest:test_mintFraktion_ok() (gas: 210175) MinterTest:test_mintFreeFraktionForUser_ok() (gas: 60193) MinterTest:test_mintFreeFraktion_ExpectingOnlyFreeFraktion_ko() (gas: 40161) MinterTest:test_mintFreeFraktion_TooManyFraktion_ko() (gas: 61061) -MinterTest:test_mintFreeFraktion_ok() (gas: 62919) +MinterTest:test_mintFreeFraktion_ok() (gas: 62897) MultiVestingWalletsTest:test_canBeDeployedAndInit_ok() (gas: 2667336) MultiVestingWalletsTest:test_createVestBatch() (gas: 210722) MultiVestingWalletsTest:test_createVestBatch_ArrayInvalidLength_ko() (gas: 79027) diff --git a/contracts/fraktions/FraktionTokens.sol b/contracts/fraktions/FraktionTokens.sol index 3f0991d..55f3421 100644 --- a/contracts/fraktions/FraktionTokens.sol +++ b/contracts/fraktions/FraktionTokens.sol @@ -25,9 +25,6 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /// @dev Error throwned when we try to update the supply of a non supply aware token error SupplyUpdateNotAllowed(); - /// @dev Error emitted when it remain some fraktion supply when wanting to increase it - error RemainingSupply(); - /// @dev 'bytes4(keccak256("InsuficiantSupply()"))' uint256 private constant _INSUFICIENT_SUPPLY_SELECTOR = 0xa24b545a; @@ -37,9 +34,6 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { /// @dev 'bytes4(keccak256("SupplyUpdateNotAllowed()"))' uint256 private constant _SUPPLY_UPDATE_NOT_ALLOWED_SELECTOR = 0x48385ebd; - /// @dev 'bytes4(keccak256("RemainingSupply()"))' - uint256 private constant _REMAINING_SUPPLY_SELECTOR = 0x0180e6b4; - /* -------------------------------------------------------------------------- */ /* Event's */ /* -------------------------------------------------------------------------- */ @@ -172,7 +166,7 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { } /// @dev Set the supply for the given fraktion id - function setSupply(FraktionId id, uint256 supply) external payable onlyRole(FrakRoles.MINTER) { + function addSupply(FraktionId id, uint256 supply) external payable onlyRole(FrakRoles.MINTER) { assembly { // Ensure the supply update of this fraktion type is allowed let fraktionType := and(id, 0xF) @@ -185,15 +179,8 @@ contract FraktionTokens is FrakAccessControlUpgradeable, ERC1155Upgradeable { mstore(0, id) mstore(0x20, _availableSupplies.slot) let supplySlot := keccak256(0, 0x40) - // Ensure all the supply has been sold - let currentSupply := sload(supplySlot) - if currentSupply { - mstore(0x00, _REMAINING_SUPPLY_SELECTOR) - revert(0x1c, 0x04) - } - // Get the supply slot and update it - sstore(supplySlot, supply) + sstore(supplySlot, add(sload(supplySlot), supply)) // Emit the supply updated event mstore(0, supply) log2(0, 0x20, _SUPPLY_UPDATED_EVENT_SELECTOR, id) diff --git a/contracts/minter/Minter.sol b/contracts/minter/Minter.sol index 3d15bcd..53e271b 100644 --- a/contracts/minter/Minter.sol +++ b/contracts/minter/Minter.sol @@ -310,7 +310,7 @@ contract Minter is IMinter, FrakAccessControlUpgradeable, FraktionCostBadges, Mu */ function increaseSupply(FraktionId id, uint256 newSupply) external onlyRole(FrakRoles.MINTER) { // Update the supply - fraktionTokens.setSupply(id, newSupply); + fraktionTokens.addSupply(id, newSupply); } /** diff --git a/test/fraktions/FraktionTokens.t.sol b/test/fraktions/FraktionTokens.t.sol index 9c0cbdd..f523e4a 100644 --- a/test/fraktions/FraktionTokens.t.sol +++ b/test/fraktions/FraktionTokens.t.sol @@ -88,7 +88,7 @@ contract FraktionTokensTest is FrakTest { assertEq(fraktionTokens.supplyOf(commonFraktion), 0); // Increase it to one - fraktionTokens.setSupply(commonFraktion, 1); + fraktionTokens.addSupply(commonFraktion, 1); assertEq(fraktionTokens.supplyOf(commonFraktion), 1); // Ensure the fraktion is mintable and the supplies goes back to 0 @@ -98,26 +98,21 @@ contract FraktionTokensTest is FrakTest { function test_supply_InvalidRole_ko() public withEmptySupply(contentId.commonFraktionId()) { vm.expectRevert(NotAuthorized.selector); - fraktionTokens.setSupply(contentId.commonFraktionId(), 1); + fraktionTokens.addSupply(contentId.commonFraktionId(), 1); } function test_supply_SupplyUpdateNotAllowed_ko() public asDeployer { vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.setSupply(contentId.toFraktionId(0), 1); + fraktionTokens.addSupply(contentId.toFraktionId(0), 1); vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.setSupply(contentId.toFraktionId(1), 1); + fraktionTokens.addSupply(contentId.toFraktionId(1), 1); vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.setSupply(contentId.toFraktionId(2), 1); + fraktionTokens.addSupply(contentId.toFraktionId(2), 1); vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - fraktionTokens.setSupply(contentId.toFraktionId(7), 1); - } - - function test_supply_SupplyRemaining_ko() public asDeployer { - vm.expectRevert(FraktionTokens.RemainingSupply.selector); - fraktionTokens.setSupply(contentId.commonFraktionId(), 1); + fraktionTokens.addSupply(contentId.toFraktionId(7), 1); } /* -------------------------------------------------------------------------- */ diff --git a/test_old/minter/Minter.t.sol b/test_old/minter/Minter.t.sol index 2b931d9..02bc57b 100644 --- a/test_old/minter/Minter.t.sol +++ b/test_old/minter/Minter.t.sol @@ -439,14 +439,6 @@ contract MinterTest is FrkTokenTestHelper { minter.increaseSupply(contentId.creatorFraktionId(), 1); } - function test_fail_increaseSupply_RemainingSupply() public prankExecAsDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); - // Revert cause of free fraktion - vm.expectRevert(FraktionTokens.RemainingSupply.selector); - minter.increaseSupply(contentId.commonFraktionId(), 1); - } - /* * ===== TEST : multicall(bytes[] calldata data) ===== */ From 41430525de5172b7547f7cc89ec4bc6cf54754de Mon Sep 17 00:00:00 2001 From: KONFeature Date: Thu, 7 Sep 2023 18:42:12 +0200 Subject: [PATCH 16/16] =?UTF-8?q?=E2=9A=B0=EF=B8=8F=20Remove=20previous=20?= =?UTF-8?q?test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test_old/FrkTokenTestHelper.sol | 33 -- test_old/README.md | 29 -- test_old/UUPSTestHelper.sol | 36 -- test_old/gas-usage/ErrorGasUsageTest.sol | 65 --- test_old/gas-usage/EventGasUsageTest.sol | 48 --- test_old/gas-usage/IsZeroGasUsageTest.sol | 43 -- test_old/gas-usage/LoopGasUsageTest.sol | 92 ---- test_old/minter/Minter.t.sol | 469 --------------------- test_old/reward/Rewarder.pay.t.sol | 325 -------------- test_old/reward/Rewarder.t.sol | 157 ------- test_old/reward/RewarderTestHelper.sol | 88 ---- test_old/reward/pool/ContentPool.t.sol | 161 ------- test_old/tokens/FraktionTokens.t.sol | 96 ----- test_old/tokens/FrkToken.t.sol | 307 -------------- test_old/wallets/FrakTreasuryWallet.t.sol | 224 ---------- test_old/wallets/MultiVestingWallets.t.sol | 208 --------- 16 files changed, 2381 deletions(-) delete mode 100644 test_old/FrkTokenTestHelper.sol delete mode 100644 test_old/README.md delete mode 100644 test_old/UUPSTestHelper.sol delete mode 100644 test_old/gas-usage/ErrorGasUsageTest.sol delete mode 100644 test_old/gas-usage/EventGasUsageTest.sol delete mode 100644 test_old/gas-usage/IsZeroGasUsageTest.sol delete mode 100644 test_old/gas-usage/LoopGasUsageTest.sol delete mode 100644 test_old/minter/Minter.t.sol delete mode 100644 test_old/reward/Rewarder.pay.t.sol delete mode 100644 test_old/reward/Rewarder.t.sol delete mode 100644 test_old/reward/RewarderTestHelper.sol delete mode 100644 test_old/reward/pool/ContentPool.t.sol delete mode 100644 test_old/tokens/FraktionTokens.t.sol delete mode 100644 test_old/tokens/FrkToken.t.sol delete mode 100644 test_old/wallets/FrakTreasuryWallet.t.sol delete mode 100644 test_old/wallets/MultiVestingWallets.t.sol diff --git a/test_old/FrkTokenTestHelper.sol b/test_old/FrkTokenTestHelper.sol deleted file mode 100644 index 2b452fe..0000000 --- a/test_old/FrkTokenTestHelper.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { UUPSTestHelper } from "./UUPSTestHelper.sol"; - -/// Testing the frak l2 token -contract FrkTokenTestHelper is UUPSTestHelper { - FrakToken frakToken; - - function _setupFrkToken() internal { - // Deploy frak token - bytes memory initData = abi.encodeCall(FrakToken.initialize, ()); - address frkProxyAddr = deployContract(address(new FrakToken()), initData); - frakToken = FrakToken(frkProxyAddr); - } - - /* - * ===== UTILS===== - */ - - modifier withFrkToken(address target) { - prankDeployer(); - frakToken.mint(address(target), 10); - _; - } - - modifier withLotFrkToken(address target) { - prankDeployer(); - frakToken.mint(address(target), 500_000_000 ether); - _; - } -} diff --git a/test_old/README.md b/test_old/README.md deleted file mode 100644 index 91005c4..0000000 --- a/test_old/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Test - -To have a gas fee estimation when running the unit test, be sure to have the **gasReporter** enabled in the **hardhat.config.ts** - -## Run all the unit test locally - -```shell -forge test -vv -``` - -## Setup EC2 for tools testing - -```shell -sudo yum update -y -sudo yum install docker -y -curl --silent --location https://rpm.nodesource.com/setup_16.x | sudo bash - -sudo yum install -y nodejs -sudo service docker start -sudo usermod -a -G docker ec2-user -sudo yum install git -mkdir frak -cd frak/ -git clone https://**PersonalGitAccessToken**@github.com/frak-id/frak-id-blockchain.git -cd frak-id-blockchain/ -git status -git pull -npm i -nohup sh tools/run-all-nohup.sh -``` diff --git a/test_old/UUPSTestHelper.sol b/test_old/UUPSTestHelper.sol deleted file mode 100644 index aff88f6..0000000 --- a/test_old/UUPSTestHelper.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { ERC1967Proxy } from "openzeppelin/proxy/ERC1967/ERC1967Proxy.sol"; -import { PRBTest } from "@prb/test/PRBTest.sol"; - -/// Testing the frak l2 token -contract UUPSTestHelper is PRBTest { - address internal deployer = vm.addr(100); - - /** - * @dev Deploy the given contract in an uups proxy - * @return The deployed proxy address - */ - function deployContract(address logic, bytes memory init) internal returns (address) { - vm.prank(deployer); - ERC1967Proxy proxyTemp = new ERC1967Proxy(logic, init); - return address(proxyTemp); - } - - /** - * @dev Modifier that prank all this execution as the deployer - */ - modifier prankExecAsDeployer() { - vm.startPrank(deployer); - _; - vm.stopPrank(); - } - - /** - * @dev Prank the next call as the deployer address - */ - function prankDeployer() internal { - vm.prank(deployer); - } -} diff --git a/test_old/gas-usage/ErrorGasUsageTest.sol b/test_old/gas-usage/ErrorGasUsageTest.sol deleted file mode 100644 index 0c2487c..0000000 --- a/test_old/gas-usage/ErrorGasUsageTest.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { PRBTest } from "@prb/test/PRBTest.sol"; - -// Size : 50499 -contract RevertWithString { - // Gas used : 311 - function sample(uint256 amount) external pure { - require(amount > 10, "Not enough amount"); - } -} - -// Size : 40293 -contract RevertWithError { - error NotEnoughAmount(); - - // Gas used : 260 - function sample(uint256 amount) external pure { - if (amount < 10) revert NotEnoughAmount(); - } -} - -// Size : 33087 -contract RevertWithErrorAssembly { - /// @dev 'bytes4(keccak256("NotEnoughAmount()"))' - uint256 private constant _NOT_ENOUGH_AMOUNT_SELECTOR = 0xe008b5f9; - - // Gas used : 230 - function sample(uint256 amount) external pure { - assembly { - if lt(amount, 10) { - mstore(0x00, _NOT_ENOUGH_AMOUNT_SELECTOR) - revert(0x1c, 0x04) - } - } - } -} - -/// Testing revert gas cost handling -contract ErrorGasUsageTest is PRBTest { - RevertWithString testStringContract; - - RevertWithError testErrorContract; - - RevertWithErrorAssembly testErrorAssemblyContract; - - function setUp() public { - testStringContract = new RevertWithString(); - testErrorContract = new RevertWithError(); - testErrorAssemblyContract = new RevertWithErrorAssembly(); - } - - function testFail_RevertWithString() public view { - testStringContract.sample(1); - } - - function testFail_RevertWithError() public view { - testErrorContract.sample(1); - } - - function testFail_RevertWithErrorAssembly() public view { - testErrorAssemblyContract.sample(1); - } -} diff --git a/test_old/gas-usage/EventGasUsageTest.sol b/test_old/gas-usage/EventGasUsageTest.sol deleted file mode 100644 index 5c703d6..0000000 --- a/test_old/gas-usage/EventGasUsageTest.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { PRBTest } from "@prb/test/PRBTest.sol"; - -contract SampleEvent { - event LogTransfer(address indexed from, address indexed to, uint256 value); - - function transfer(address to, uint256 value) public { - emit LogTransfer(msg.sender, to, value); - } -} - -contract SampleAssemblyEvent { - event LogTransfer(address indexed from, address indexed to, uint256 value); - - /// @dev 'keccak256("LogTransfer(address,address,uint256")' - uint256 private constant _LOG_TRANSFER_SELECTOR = 0x3c70bac155b1df6b781842a200c9369a387d8d24e7cb6fafecba18a53e2de32b; - - function transfer(address to, uint256 value) public { - assembly { - mstore(0, value) - log3(0x00, 0x20, _LOG_TRANSFER_SELECTOR, caller(), to) - } - } -} - -/// Testing is event gas cost -contract EventGasUsageTest is PRBTest { - SampleEvent sampleEvent; - - SampleAssemblyEvent sampleAssemblyEvent; - - function setUp() public { - sampleEvent = new SampleEvent(); - sampleAssemblyEvent = new SampleAssemblyEvent(); - } - - event Test(bytes32 selector); - - function test_event() public { - sampleEvent.transfer(address(1), 10); - } - - function test_eventAssembly() public { - sampleAssemblyEvent.transfer(address(1), 10); - } -} diff --git a/test_old/gas-usage/IsZeroGasUsageTest.sol b/test_old/gas-usage/IsZeroGasUsageTest.sol deleted file mode 100644 index ba61bf2..0000000 --- a/test_old/gas-usage/IsZeroGasUsageTest.sol +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { PRBTest } from "@prb/test/PRBTest.sol"; - -contract IsZero { - function sample(address addr) external pure returns (bool) { - return addr == address(0); - } -} - -contract IsZeroAssembly { - function sample(address addr) external pure returns (bool) { - assembly { - if iszero(addr) { return(0x20, 32) } - - mstore(0x20, 1) - return(0x00, 32) - } - } -} - -/// Testing is zero gas cost handling -contract IsZeroGasUsageTest is PRBTest { - IsZero isZeroContract; - - IsZeroAssembly isZeroAssemblyContract; - - function setUp() public { - isZeroContract = new IsZero(); - isZeroAssemblyContract = new IsZeroAssembly(); - } - - function test_isZero() public view { - isZeroContract.sample(address(123)); - // isZeroContract.sample(address(0)); - } - - function test_isZeroAssembly() public view { - isZeroAssemblyContract.sample(address(123)); - // isZeroAssemblyContract.sample(address(0)); - } -} diff --git a/test_old/gas-usage/LoopGasUsageTest.sol b/test_old/gas-usage/LoopGasUsageTest.sol deleted file mode 100644 index 79c5283..0000000 --- a/test_old/gas-usage/LoopGasUsageTest.sol +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { PRBTest } from "@prb/test/PRBTest.sol"; - -// Deployment cost : 116_565 -contract SolidityLoop { - // value : [13, 12, 1337] Gas used : 1_546 - function sample(uint256[] calldata values) external pure returns (uint256[] memory transformed) { - unchecked { - transformed = new uint256[](values.length); - for (uint256 i = 0; i < values.length; i++) { } - } - } -} - -// Deployment cost : 79_929 -contract AssemblyRegularForLoop { - // value : [13, 12, 1337] Gas used : 1_211 - function sample(uint256[] calldata values) external pure returns (uint256[] memory transformed) { - assembly { - // Get the free mem pointer and allocate it to the transformed array - transformed := mload(0x40) - // Store the array length - mstore(transformed, values.length) - // Initial transformed offset - let transformedOffset := add(transformed, 0x20) - // Update free mem pointer - mstore(0x40, add(transformedOffset, shl(5, values.length))) - - for { let i := 0 } lt(i, values.length) { i := add(i, 1) } { - // Load value from calldata - let value := calldataload(add(values.offset, mul(i, 0x20))) - // Build transformed value - let newTransformed := or(shl(4, value), 3) - // Store it - mstore(add(transformedOffset, shl(5, i)), newTransformed) - } - } - } -} - -// Deployment cost : 77_129 -contract AssemblyInfiniteForLoop { - // value : [13, 12, 1337] Gas used : 1_113 - function sample(uint256[] calldata values) external pure returns (uint256[] memory transformed) { - assembly { - // Get the free mem pointer and allocate it to the transformed array - transformed := mload(0x40) - // Store the array length - mstore(transformed, values.length) - // Initial transformed and values offset - let valuesOffset := values.offset - let transformedOffset := add(transformed, 0x20) - // Check where we should end - let valuesEnd := add(valuesOffset, shl(5, values.length)) - - // Infinite loop - for { } 1 { } { - // Load value from calldata - let value := calldataload(valuesOffset) - // Build transformed value - let newTransformed := or(shl(4, value), 3) - // Store it - mstore(transformedOffset, newTransformed) - // Increase each iterator - valuesOffset := add(valuesOffset, 0x20) - transformedOffset := add(transformedOffset, 0x20) - // Exit if we reached the end of our values array - if iszero(lt(valuesOffset, valuesEnd)) { break } - } - - // Update free mem pointer - mstore(0x40, transformedOffset) - } - } -} - -/// Testing loop gas usage -contract LoopUsageTest is PRBTest { - AssemblyInfiniteForLoop testLoop; - - uint256[] private testValues = [13, 12, 1337]; - - function setUp() public { - testLoop = new AssemblyInfiniteForLoop(); - } - - function test() public view { - testLoop.sample(testValues); - } -} diff --git a/test_old/minter/Minter.t.sol b/test_old/minter/Minter.t.sol deleted file mode 100644 index 02bc57b..0000000 --- a/test_old/minter/Minter.t.sol +++ /dev/null @@ -1,469 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { NotAuthorized, InvalidAddress, ContractPaused, BadgeTooLarge } from "@frak/utils/FrakErrors.sol"; -import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { IFrakToken } from "@frak/tokens/IFrakToken.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { FraktionId } from "@frak/libs/FraktionId.sol"; -import { FrakRoles } from "@frak/roles/FrakRoles.sol"; -import { Minter } from "@frak/minter/Minter.sol"; -import { IMinter } from "@frak/minter/IMinter.sol"; -import { FrkTokenTestHelper } from "../FrkTokenTestHelper.sol"; -import { - NotAuthorized, - InvalidAddress, - ContractPaused, - BadgeTooLarge, - InvalidFraktionType -} from "@frak/utils/FrakErrors.sol"; - -/// Testing minter contract -contract MinterTest is FrkTokenTestHelper { - FraktionTokens fraktionTokens; - address foundationAddr = address(13); - - address minterAddr; - Minter minter; - - function setUp() public { - _setupFrkToken(); - - // Deploy fraktions token - bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("test_url")); - address fraktionProxyAddr = deployContract(address(new FraktionTokens()), initData); - fraktionTokens = FraktionTokens(fraktionProxyAddr); - - // Deploy our minter contract - initData = abi.encodeCall(Minter.initialize, (address(frakToken), fraktionProxyAddr, foundationAddr)); - minterAddr = deployContract(address(new Minter()), initData); - minter = Minter(minterAddr); - - // Grant the minter role to our minter contract - prankDeployer(); - fraktionTokens.grantRole(FrakRoles.MINTER, minterAddr); - } - - /* - * ===== TEST : initialize( - address frkTokenAddr, - address fraktionTokensAddr, - address foundationAddr - ) ===== - */ - function test_fail_InitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - minter.initialize(address(0), address(0), address(0)); - } - - /* - * ===== TEST : addContent( - address contentOwnerAddress, - uint256 commonSupply, - uint256 premiumSupply, - uint256 goldSupply, - uint256 diamondSupply - ) ===== - */ - function test_addContent() public prankExecAsDeployer { - minter.addContent(address(1), 1, 1, 1, 1); - } - - function test_fail_addContent_ContractPaused() public prankExecAsDeployer { - minter.pause(); - vm.expectRevert(ContractPaused.selector); - minter.addContent(address(1), 1, 1, 1, 1); - } - - function test_fail_addContent_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - minter.addContent(address(1), 1, 1, 1, 1); - } - - function test_fail_addContent_InvalidAddress() public prankExecAsDeployer { - vm.expectRevert(InvalidAddress.selector); - minter.addContent(address(0), 1, 1, 1, 1); - } - - function test_fail_addContent_InvalidSupply() public prankExecAsDeployer { - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 0, 1, 1, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 501, 1, 1, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 1, 201, 1, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 1, 1, 51, 1); - - vm.expectRevert(IMinter.InvalidSupply.selector); - minter.addContent(address(1), 1, 1, 1, 21); - } - - /* - * ===== TEST : mintFraktionForUser( - uint256 id, - address to, - uint256 amount, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) ===== - */ - bytes32 constant PERMIT_TYPEHASH = - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - - /// @dev Get permit signature for the given private key and cost - function _getSignedPermit(uint256 privateKey, uint256 cost) private view returns (uint8 v, bytes32 r, bytes32 s) { - address user = vm.addr(privateKey); - (v, r, s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - frakToken.getDomainSeperator(), - keccak256( - abi.encode( - PERMIT_TYPEHASH, user, address(minter), cost, frakToken.getNonce(user), block.timestamp - ) - ) - ) - ) - ); - } - - function test_mintFraktionForUser() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - prankDeployer(); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - // Ensure the supply is good - assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); - assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); - } - - function test_fail_mintFraktionForUser_ContractPaused() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - prankDeployer(); - minter.pause(); - vm.expectRevert(ContractPaused.selector); - prankDeployer(); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - } - - function test_fail_mintFraktionForUser_NotAuthorized() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.expectRevert(NotAuthorized.selector); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - } - - function test_fail_mintFraktionForUser_InsuficiantSupply() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 1, 0, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.premiumFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.expectRevert(FraktionTokens.InsuficiantSupply.selector); - prankDeployer(); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - } - - function test_fail_mintFraktionForUser_InvalidFraktionType() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.expectRevert(InvalidFraktionType.selector); - prankDeployer(); - minter.mintFraktionForUser(contentId.freeFraktionId(), user, block.timestamp, v, r, s); - } - - function test_fail_mintFractionForUser_InvalidSigner() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost - 1); - - // Launch the buy prcess - prankDeployer(); - vm.expectRevert(IFrakToken.InvalidSigner.selector); - minter.mintFraktionForUser(fraktionCommonId, user, block.timestamp, v, r, s); - // Ensure the supply hasn't changed - assertEq(fraktionTokens.supplyOf(fraktionCommonId), 10); - } - - /* - * ===== TEST : mintFraktion( - uint256 id, - uint256 amount, - uint256 deadline, - uint8 v, - bytes32 r, - bytes32 s - ) ===== - */ - function test_mintFraktion() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - // Ensure the supply is good - assertEq(fraktionTokens.supplyOf(fraktionCommonId), 9); - assertEq(fraktionTokens.balanceOf(user, FraktionId.unwrap(fraktionCommonId)), 1); - } - - function test_fail_mintFraktion_ContractPaused() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the buy prcess - prankDeployer(); - minter.pause(); - vm.expectRevert(ContractPaused.selector); - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - } - - function test_fail_mintFraktion_TooManyFraktion() public { - uint256 privateKey = 0xACAB; - address user = vm.addr(privateKey); - // Add an initial content - prankDeployer(); - ContentId contentId = minter.addContent(address(1), 10, 1, 1, 1); - // Mint some token to our user - prankDeployer(); - frakToken.mint(user, 500 ether); - - // Get the cost of the buy process - FraktionId fraktionCommonId = contentId.commonFraktionId(); - uint256 cost = minter.getCostBadge(fraktionCommonId); - - // Sign the tx for the user - (uint8 v, bytes32 r, bytes32 s) = _getSignedPermit(privateKey, cost); - - // Launch the first buy process - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - - // Sign the tx for the user - (v, r, s) = _getSignedPermit(privateKey, cost); - - // Launch the second buy process - vm.expectRevert(IMinter.TooManyFraktion.selector); - vm.prank(user); - minter.mintFraktion(fraktionCommonId, block.timestamp, v, r, s); - } - - /* - * ===== TEST : mintFreeFraktionForUser( - uint256 id, - address to - ) ===== - */ - function test_mintFreeFraktionForUser() public prankExecAsDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); - } - - function test_fail_mintFreeFraktionForUser_ContractPaused() public prankExecAsDeployer { - minter.pause(); - vm.expectRevert(ContractPaused.selector); - minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); - } - - function test_fail_mintFreeFraktionForUser_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - minter.mintFreeFraktionForUser(FraktionId.wrap(1), address(1)); - } - - function test_fail_mintFreeFraktionForUser_ExpectingOnlyFreeFraktion() public prankExecAsDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - vm.expectRevert(IMinter.ExpectingOnlyFreeFraktion.selector); - minter.mintFreeFraktionForUser(contentId.commonFraktionId(), address(1)); - } - - function test_fail_mintFreeFraktionForUser_AlreadyHaveFreeFraktion() public prankExecAsDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 1); - minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); - vm.expectRevert(IMinter.TooManyFraktion.selector); - minter.mintFreeFraktionForUser(contentId.freeFraktionId(), address(1)); - } - - /* - * ===== TEST : increaseSupply(uint256 id, uint256 newSupply) ===== - */ - function test_increaseSupply() public prankExecAsDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); - // Increase it's diamond supply - minter.increaseSupply(contentId.diamondFraktionId(), 1); - } - - function test_fail_increaseSupply_ContractPaused() public prankExecAsDeployer { - minter.pause(); - vm.expectRevert(ContractPaused.selector); - minter.increaseSupply(FraktionId.wrap(1), 1); - } - - function test_fail_increaseSupply_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - minter.increaseSupply(FraktionId.wrap(1), 1); - } - - function test_fail_increaseSupply_SupplyUpdateNotAllowed() public prankExecAsDeployer { - // Add an initial content - ContentId contentId = minter.addContent(address(1), 1, 1, 1, 0); - // Revert cause of free fraktion - vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - minter.increaseSupply(contentId.freeFraktionId(), 1); - // Revert cause of nft id - vm.expectRevert(FraktionTokens.SupplyUpdateNotAllowed.selector); - minter.increaseSupply(contentId.creatorFraktionId(), 1); - } - - /* - * ===== TEST : multicall(bytes[] calldata data) ===== - */ - function test_multicall() public prankExecAsDeployer { - // Build our calldata - bytes[] memory callingData = new bytes[](5); - callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[1] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[2] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[3] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[4] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - - minter.multicall(callingData); - } - - function test_fail_multicall_NotAuthorized() public { - // Build our calldata - bytes[] memory callingData = new bytes[](5); - callingData[0] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[1] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[2] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[3] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - callingData[4] = abi.encodeWithSelector(minter.addContent.selector, address(1), 1, 1, 1, 0); - - vm.expectRevert(NotAuthorized.selector); - minter.multicall(callingData); - } -} diff --git a/test_old/reward/Rewarder.pay.t.sol b/test_old/reward/Rewarder.pay.t.sol deleted file mode 100644 index 4e0edb7..0000000 --- a/test_old/reward/Rewarder.pay.t.sol +++ /dev/null @@ -1,325 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { StdUtils } from "@forge-std/StdUtils.sol"; -import { Rewarder } from "@frak/reward/Rewarder.sol"; -import { IRewarder } from "@frak/reward/IRewarder.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { FraktionId } from "@frak/libs/FraktionId.sol"; -import { NotAuthorized, InvalidArray, InvalidAddress, RewardTooLarge } from "@frak/utils/FrakErrors.sol"; -import { RewarderTestHelper } from "./RewarderTestHelper.sol"; - -/// Testing the rewarder pay function -contract RewarderPayTest is RewarderTestHelper, StdUtils { - using ArrayLib for uint256; - - ContentId contentId; - - function setUp() public { - _baseSetUp(); - - contentId = mintAContent(); - } - - /* - * ===== TEST : payUserDirectly(address listener, uint256 amount) ===== - */ - function test_payUserDirectly() public withFrkToken(rewarderAddr) prankExecAsDeployer { - rewarder.payUserDirectly(address(1), 10); - } - - function test_fail_payUserDirectly_InvalidRole() public withFrkToken(rewarderAddr) { - vm.expectRevert(NotAuthorized.selector); - rewarder.payUserDirectly(address(1), 10); - } - - function test_fail_payUserDirectly_InvalidAddress() public withFrkToken(rewarderAddr) prankExecAsDeployer { - vm.expectRevert(InvalidAddress.selector); - rewarder.payUserDirectly(address(0), 10); - } - - function test_fail_payUserDirectly_InvalidReward() public withFrkToken(rewarderAddr) prankExecAsDeployer { - vm.expectRevert(IRewarder.InvalidReward.selector); - rewarder.payUserDirectly(address(1), 0); - } - - function test_fail_payUserDirectly_TooLargeReward() public withFrkToken(rewarderAddr) prankExecAsDeployer { - vm.expectRevert(IRewarder.InvalidReward.selector); - rewarder.payUserDirectly(address(1), 1_000_001 ether); - } - - function test_fail_payUserDirectly_NotEnoughBalance() public withFrkToken(rewarderAddr) prankExecAsDeployer { - vm.expectRevert(); - rewarder.payUserDirectly(address(1), 11); - } - - /* - * ===== TEST : payCreatorDirectlyBatch( - uint256[] calldata contentIds, - uint256[] calldata amounts - ) ===== - */ - function test_payCreatorDirectlyBatch() public withFrkToken(rewarderAddr) prankExecAsDeployer { - rewarder.payCreatorDirectlyBatch(contentId.asSingletonArray(), uint256(10).asSingletonArray()); - } - - function test_fail_payCreatorDirectlyBatch_InvalidRole() public withFrkToken(rewarderAddr) { - vm.expectRevert(NotAuthorized.selector); - rewarder.payCreatorDirectlyBatch(contentId.asSingletonArray(), uint256(10).asSingletonArray()); - } - - function test_fail_payCreatorDirectlyBatch_InvalidArray() public withFrkToken(rewarderAddr) prankExecAsDeployer { - ContentId[] memory contentIds = new ContentId[](3); - uint256[] memory amountsIds = new uint256[](4); - vm.expectRevert(InvalidArray.selector); - rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); - } - - function test_fail_payCreatorDirectlyBatch_TooLargeArray() public withFrkToken(rewarderAddr) prankExecAsDeployer { - ContentId[] memory contentIds = new ContentId[](21); - uint256[] memory amountsIds = new uint256[](21); - vm.expectRevert(InvalidArray.selector); - rewarder.payCreatorDirectlyBatch(contentIds, amountsIds); - } - - function test_fail_payCreatorDirectlyBatch_EmptyAmount() public withFrkToken(rewarderAddr) prankExecAsDeployer { - vm.expectRevert(IRewarder.InvalidReward.selector); - rewarder.payCreatorDirectlyBatch(contentId.asSingletonArray(), uint256(0).asSingletonArray()); - } - - function test_fail_payCreatorDirectlyBatch_TooLargeAmount() - public - withLotFrkToken(rewarderAddr) - prankExecAsDeployer - { - vm.expectRevert(IRewarder.InvalidReward.selector); - rewarder.payCreatorDirectlyBatch(contentId.asSingletonArray(), uint256(1_000_001 ether).asSingletonArray()); - } - - /* - * ===== TEST : payUser( - address listener, - uint8 contentType, - uint256[] calldata contentIds, - uint16[] calldata listenCounts - )s ===== - */ - function test_payUser() public withLotFrkToken(rewarderAddr) prankExecAsDeployer { - (uint256[] memory listenCounts, ContentId[] memory contentIds) = basePayParam(); - rewarder.payUser(address(1), 1, contentIds, listenCounts); - } - - function test_payUser_LargeReward() public withLotFrkToken(rewarderAddr) prankExecAsDeployer { - mintFraktions(address(1), 20); - - (uint256[] memory listenCounts, ContentId[] memory contentIds) = basePayParam(300); - rewarder.payUser(address(1), 1, contentIds, listenCounts); - } - - function testFuzz_payUser(uint16 listenCount) public withLotFrkToken(rewarderAddr) prankExecAsDeployer { - listenCount = uint16(bound(listenCount, 1, 300)); - - uint256[] memory listenCounts = new uint256[](1); - listenCounts[0] = listenCount; - - // Get the previous claimable balance - uint256 claimableBalance = rewarder.getAvailableFounds(address(1)); - uint256 frakMinted = rewarder.getFrkMinted(); - // Launch the pay - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - // Ensure the claimable balance has increase - assertGt(rewarder.getAvailableFounds(address(1)), claimableBalance); - assertGt(rewarder.getFrkMinted(), frakMinted); - } - - function testFuzz_payUser_WithFraktions(uint16 listenCount) - public - withLotFrkToken(rewarderAddr) - prankExecAsDeployer - { - listenCount = uint16(bound(listenCount, 1, 300)); - - mintFraktions(address(1)); - - uint256[] memory listenCounts = new uint256[](1); - listenCounts[0] = listenCount; - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - } - - function testFuzz_payUser_WithFraktions_ClaimRewards(uint16 listenCount) public withLotFrkToken(rewarderAddr) { - vm.startPrank(deployer); - listenCount = uint16(bound(listenCount, 1, 300)); - - mintFraktions(address(1)); - - uint256[] memory listenCounts = new uint256[](1); - listenCounts[0] = listenCount; - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - - // Self claim rewarder reward - uint256 balance = frakToken.balanceOf(address(1)); - uint256 availableFound = rewarder.getAvailableFounds(address(1)); - vm.stopPrank(); - vm.prank(address(1)); - rewarder.withdrawFounds(); - // Ensure the balance had increase of the 98% available found - assertEq(frakToken.balanceOf(address(1)), balance + ((availableFound * 98) / 100)); - balance = frakToken.balanceOf(address(1)); - - // Ensure the foundation doesn't have any fee's - balance = frakToken.balanceOf(foundationAddr); - availableFound = rewarder.getAvailableFounds(foundationAddr); - vm.prank(foundationAddr); - rewarder.withdrawFounds(); - assertEq(frakToken.balanceOf(foundationAddr), balance + availableFound); - - // Compute and claim content pool rewards - balance = frakToken.balanceOf(address(1)); - vm.prank(address(1)); - contentPool.withdrawFounds(); - assertGt(frakToken.balanceOf(address(1)), balance); - } - - function testFuzz_payUser_WithFraktionsAndLoadOfState(uint16 listenCount) - public - withLotFrkToken(rewarderAddr) - prankExecAsDeployer - { - listenCount = uint16(bound(listenCount, 1, 300)); - - mintFraktions(address(1)); - mintFraktions(address(2)); - - uint256[] memory listenCounts = new uint256[](1); - listenCounts[0] = listenCount; - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - - mintFraktions(address(3)); - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - mintFraktions(address(4)); - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - mintFraktions(address(5)); - rewarder.payUser(address(1), 1, contentId.asSingletonArray(), listenCounts); - } - - function test_fail_payUser_NotRewarder() public withFrkToken(rewarderAddr) { - (uint256[] memory listenCounts, ContentId[] memory contentIds) = basePayParam(); - vm.expectRevert(NotAuthorized.selector); - rewarder.payUser(address(1), 1, contentIds, listenCounts); - } - - function test_fail_payUser_TooLargeArray() public withFrkToken(rewarderAddr) prankExecAsDeployer { - uint256[] memory listenCounts = new uint256[](21); - ContentId[] memory contentIds = new ContentId[](21); - vm.expectRevert(InvalidArray.selector); - rewarder.payUser(address(1), 1, contentIds, listenCounts); - } - - function test_fail_payUser_ArrayNotSameSize() public withFrkToken(rewarderAddr) prankExecAsDeployer { - uint256[] memory listenCounts = new uint256[](4); - ContentId[] memory contentIds = new ContentId[](3); - vm.expectRevert(InvalidArray.selector); - rewarder.payUser(address(1), 1, contentIds, listenCounts); - } - - function test_fail_payUser_InexistantContent() public withFrkToken(rewarderAddr) prankExecAsDeployer { - // Then try to pay him - (uint256[] memory listenCounts,) = basePayParam(); - vm.expectRevert(InvalidAddress.selector); - rewarder.payUser(address(1), 1, ContentId.wrap(13).asSingletonArray(), listenCounts); - } - - function test_payUser_NoReward_ContentTypeNotKnown() public withLotFrkToken(rewarderAddr) prankExecAsDeployer { - (uint256[] memory listenCounts, ContentId[] memory contentIds) = basePayParam(); - - // Get the previous claimable balance - uint256 claimableBalance = rewarder.getAvailableFounds(address(1)); - uint256 frakMinted = rewarder.getFrkMinted(); - // Launch the pay - rewarder.payUser(address(1), 0, contentIds, listenCounts); - // Ensure the claimable balance is the same - assertEq(rewarder.getAvailableFounds(address(1)), claimableBalance); - assertEq(rewarder.getFrkMinted(), frakMinted); - } - - function test_payUser_ContentTypeImpactReward() public withLotFrkToken(rewarderAddr) prankExecAsDeployer { - (uint256[] memory listenCounts, ContentId[] memory contentIds) = basePayParam(); - - // Get the previous claimable balance - uint256 claimableBalance = rewarder.getAvailableFounds(address(1)); - - // Launch the pay with content type 3 (music, lowest one) - rewarder.payUser(address(1), 3, contentIds, listenCounts); - // Ensure the claimable diff is greater than 0 - uint256 claimableDiff = rewarder.getAvailableFounds(address(1)) - claimableBalance; - claimableBalance = rewarder.getAvailableFounds(address(1)); - assertGt(claimableDiff, 0); - - // Launch the pay with content type 2 (podcast, middle one) - rewarder.payUser(address(1), 2, contentIds, listenCounts); - // Ensure the claimable diff is greater - uint256 newClaimableDiff = rewarder.getAvailableFounds(address(1)) - claimableBalance; - assertGt(newClaimableDiff, claimableDiff); - claimableDiff = newClaimableDiff; - claimableBalance = rewarder.getAvailableFounds(address(1)); - - // Launch the pay with content type 4 (streaming, middle one) - rewarder.payUser(address(1), 4, contentIds, listenCounts); - // Ensure the claimable diff is greater - newClaimableDiff = rewarder.getAvailableFounds(address(1)) - claimableBalance; - assertEq(newClaimableDiff, claimableDiff); - claimableDiff = newClaimableDiff; - claimableBalance = rewarder.getAvailableFounds(address(1)); - - // Launch the pay with content type 1 (video, highest one) - rewarder.payUser(address(1), 1, contentIds, listenCounts); - // Ensure the claimable diff is greater - newClaimableDiff = rewarder.getAvailableFounds(address(1)) - claimableBalance; - assertGt(newClaimableDiff, claimableDiff); - claimableDiff = newClaimableDiff; - claimableBalance = rewarder.getAvailableFounds(address(1)); - } - - /* - * ===== UTILS===== - */ - - function basePayParam() private view returns (uint256[] memory, ContentId[] memory) { - return basePayParam(50); - } - - function basePayParam(uint16 listenCount) private view returns (uint256[] memory, ContentId[] memory) { - uint256[] memory listenCounts = new uint256[](1); - listenCounts[0] = listenCount; - return (listenCounts, contentId.asSingletonArray()); - } - - function mintFraktions(address target) private { - mintFraktions(target, 10); - } - - function mintFraktions(address target, uint256 amount) private { - // Build the param for our new content mint, and mint it - uint256[] memory fTypeArray = payableFraktionTypes(); - uint256[] memory amounts = new uint256[](fTypeArray.length); - for (uint256 i = 0; i < fTypeArray.length; i++) { - amounts[i] = amount; - } - contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, amounts); - - FraktionId[] memory fIds = contentId.payableFraktionIds(); - for (uint256 i = 0; i < fIds.length; i++) { - fraktionTokens.mint(target, FraktionId.unwrap(fIds[i]), 1); - } - } - - /// @dev Build an array of all the payable fraktion types - function payableFraktionTypes() internal pure returns (uint256[] memory types) { - types = new uint256[](4); - types[0] = 3; - types[1] = 4; - types[2] = 5; - types[3] = 6; - } -} diff --git a/test_old/reward/Rewarder.t.sol b/test_old/reward/Rewarder.t.sol deleted file mode 100644 index e3f046b..0000000 --- a/test_old/reward/Rewarder.t.sol +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { RewarderTestHelper } from "./RewarderTestHelper.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { NotAuthorized, InvalidAddress, BadgeTooLarge } from "@frak/utils/FrakErrors.sol"; - -/// Testing the rewarder -contract RewarderTest is RewarderTestHelper { - using ArrayLib for uint256; - - uint256[] fTypeArray = uint256(3).asSingletonArray(); - - function setUp() public { - _baseSetUp(); - } - - /* - * ===== TEST : initialize( - address frkTokenAddr, - address internalTokenAddr, - address contentPoolAddr, - address referralAddr, - address foundationAddr - ) ===== - */ - function test_fail_InitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - rewarder.initialize(address(0), address(0), address(0), address(0), address(0)); - } - - /* - * ===== TEST : updateTpu(uint256 newTpu) ===== - */ - function test_updateTpu() public prankExecAsDeployer { - rewarder.updateTpu(1 ether); - assertEq(rewarder.getTpu(), 1 ether); - } - - function test_fail_updateTpu_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - rewarder.updateTpu(1 ether); - } - - /* - * ===== TEST : updateContentBadge( - uint256 contentId, - uint256 badge - ) ===== - */ - function test_updateContentBadge() public prankExecAsDeployer { - ContentId contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - rewarder.updateContentBadge(contentId, 2 ether); - assertEq(rewarder.getContentBadge(contentId), 2 ether); - } - - function test_fail_updateContentBadge_NotAuthorized() public { - prankDeployer(); - ContentId contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - - vm.expectRevert(NotAuthorized.selector); - rewarder.updateContentBadge(contentId, 2 ether); - } - - function test_fail_updateContentBadge_BadgeCapReached() public prankExecAsDeployer { - ContentId contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - - vm.expectRevert(BadgeTooLarge.selector); - rewarder.updateContentBadge(contentId, 1001 ether); - } - - /* - * ===== TEST : updateListenerBadge( - address listener, - uint256 badge - ) ===== - */ - function test_updateListenerBadge() public prankExecAsDeployer { - rewarder.updateListenerBadge(address(1), 2 ether); - assertEq(rewarder.getListenerBadge(address(1)), 2 ether); - } - - function test_fail_updateListenerBadge_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - rewarder.updateListenerBadge(address(1), 2 ether); - } - - function test_fail_updateListenerBadge_BadgeCapReached() public prankExecAsDeployer { - vm.expectRevert(BadgeTooLarge.selector); - rewarder.updateListenerBadge(address(1), 1001 ether); - } - - /* - * ===== TEST : multicall(bytes[] calldata data) ===== - */ - function test_multicall_emptyData() public prankExecAsDeployer { - // Build our calldata - bytes[] memory callingData = new bytes[](0); - rewarder.multicall(callingData); - } - - function test_multicall_singleData() public prankExecAsDeployer { - ContentId contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - - // Build our calldata - bytes[] memory callingData = new bytes[](1); - callingData[0] = abi.encodeWithSelector(rewarder.updateContentBadge.selector, contentId, 1 ether); - - rewarder.multicall(callingData); - } - - function test_multicall_multipleData() public prankExecAsDeployer { - ContentId contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - - frakToken.mint(address(rewarder), 5 ether); - - // Build our calldata - bytes[] memory callingData = new bytes[](4); - callingData[0] = abi.encodeWithSelector(rewarder.updateContentBadge.selector, contentId, 1 ether); - callingData[1] = abi.encodeWithSelector(rewarder.updateContentBadge.selector, contentId, 2 ether); - callingData[2] = abi.encodeWithSelector(rewarder.payUserDirectly.selector, address(1), 2 ether); - callingData[3] = abi.encodeWithSelector(rewarder.payUserDirectly.selector, address(2), 3 ether); - - rewarder.multicall(callingData); - - // Ensure array is executed in the right order - assertEq(rewarder.getContentBadge(contentId), 2 ether); - assertEq(frakToken.balanceOf(address(1)), 2 ether); - assertEq(frakToken.balanceOf(address(2)), 3 ether); - } - - function test_multicall_reallyLargeData() public prankExecAsDeployer { - frakToken.mint(address(rewarder), 1000 ether); - - // Build our calldata - uint256 length = 1000; - bytes[] memory callingData = new bytes[](length); - for (uint256 index; index < length; index++) { - callingData[index] = abi.encodeWithSelector(rewarder.payUserDirectly.selector, address(1), 1 ether); - } - - rewarder.multicall(callingData); - } - - function test_fail_multicall_NotAuthorized() public { - prankDeployer(); - ContentId contentId = fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - - // Build our calldata - bytes[] memory callingData = new bytes[](1); - callingData[0] = abi.encodeWithSelector(rewarder.updateContentBadge.selector, contentId, 1 ether); - - vm.expectRevert(NotAuthorized.selector); - rewarder.multicall(callingData); - } -} diff --git a/test_old/reward/RewarderTestHelper.sol b/test_old/reward/RewarderTestHelper.sol deleted file mode 100644 index 837914c..0000000 --- a/test_old/reward/RewarderTestHelper.sol +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; -import { ContentPool } from "@frak/reward/contentPool/ContentPool.sol"; -import { ReferralPool } from "@frak/reward/referralPool/ReferralPool.sol"; -import { Rewarder } from "@frak/reward/Rewarder.sol"; -import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { FrakRoles } from "@frak/roles/FrakRoles.sol"; -import { MultiVestingWallets } from "@frak/wallets/MultiVestingWallets.sol"; -import { PRBTest } from "@prb/test/PRBTest.sol"; -import { FrkTokenTestHelper } from "../FrkTokenTestHelper.sol"; - -/// Helper for our rewarder test -contract RewarderTestHelper is FrkTokenTestHelper { - FraktionTokens fraktionTokens; - ContentPool contentPool; - ReferralPool referralPool; - address foundationAddr = address(13); - - address rewarderAddr; - Rewarder rewarder; - - address contentOwnerAddress = address(2); - - function _baseSetUp() internal { - _setupFrkToken(); - - // Deploy fraktions token - bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("test_url")); - address fraktionProxyAddr = deployContract(address(new FraktionTokens()), initData); - fraktionTokens = FraktionTokens(fraktionProxyAddr); - vm.label(fraktionProxyAddr, "FraktionTokens"); - - // Deploy content pool - initData = abi.encodeCall(ContentPool.initialize, (address(frakToken))); - address contentPoolProxyAddr = deployContract(address(new ContentPool()), initData); - contentPool = ContentPool(contentPoolProxyAddr); - vm.label(contentPoolProxyAddr, "ContentPool"); - - // Deploy referral pool - initData = abi.encodeCall(ReferralPool.initialize, (address(frakToken))); - address referralProxyAddr = deployContract(address(new ReferralPool()), initData); - referralPool = ReferralPool(referralProxyAddr); - vm.label(referralProxyAddr, "ReferralPool"); - - // Deploy rewarder contract - initData = abi.encodeCall( - Rewarder.initialize, - (address(frakToken), fraktionProxyAddr, contentPoolProxyAddr, referralProxyAddr, foundationAddr) - ); - rewarderAddr = deployContract(address(new Rewarder()), initData); - rewarder = Rewarder(rewarderAddr); - vm.label(rewarderAddr, "Rewarder"); - - // Link our content pool to the fraktion token - prankDeployer(); - fraktionTokens.registerNewCallback(contentPoolProxyAddr); - - // Grant the right roles - _grantSetupRoles(); - } - - function _grantSetupRoles() private prankExecAsDeployer { - fraktionTokens.grantRole(FrakRoles.MINTER, rewarderAddr); - frakToken.grantRole(FrakRoles.MINTER, rewarderAddr); - - contentPool.grantRole(FrakRoles.REWARDER, rewarderAddr); - referralPool.grantRole(FrakRoles.REWARDER, rewarderAddr); - - contentPool.grantRole(FrakRoles.TOKEN_CONTRACT, address(fraktionTokens)); - - fraktionTokens.registerNewCallback(address(contentPool)); - } - - /* - * ===== UTILS===== - */ - - function mintAContent() public returns (ContentId) { - prankDeployer(); - uint256[] memory fTypeArray = ArrayLib.asSingletonArray(uint256(3)); - return fraktionTokens.mintNewContent(contentOwnerAddress, fTypeArray, fTypeArray); - } -} diff --git a/test_old/reward/pool/ContentPool.t.sol b/test_old/reward/pool/ContentPool.t.sol deleted file mode 100644 index 6da6db7..0000000 --- a/test_old/reward/pool/ContentPool.t.sol +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import "forge-std/console.sol"; -import { ContentPool } from "@frak/reward/contentPool/ContentPool.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { FraktionId } from "@frak/libs/FraktionId.sol"; -import { FrakRoles } from "@frak/roles/FrakRoles.sol"; -import { NotAuthorized, InvalidAddress, NoReward } from "@frak/utils/FrakErrors.sol"; -import { FrkTokenTestHelper } from "../../FrkTokenTestHelper.sol"; - -/// Testing the content pool -contract ContentPoolTest is FrkTokenTestHelper { - using ArrayLib for uint256; - - ContentPool contentPool; - - function setUp() public { - _setupFrkToken(); - - // Deploy content pool - bytes memory initData = abi.encodeCall(ContentPool.initialize, (address(frakToken))); - address contentPoolProxyAddr = deployContract(address(new ContentPool()), initData); - contentPool = ContentPool(contentPoolProxyAddr); - - prankDeployer(); - frakToken.mint(address(contentPool), 1000 ether); - - prankDeployer(); - contentPool.grantRole(FrakRoles.REWARDER, deployer); - prankDeployer(); - contentPool.grantRole(FrakRoles.TOKEN_CONTRACT, deployer); - } - - /* - * ===== TEST : initialize(address frkTokenAddr) ===== - */ - function test_fail_InitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - contentPool.initialize(address(0)); - } - - /* - * ===== TEST : addReward(uint256 contentId, uint256 rewardAmount) ===== - */ - function test_addReward() public prankExecAsDeployer { - contentPool.addReward(ContentId.wrap(1), 1 ether); - } - - function test_fail_addReward_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - contentPool.addReward(ContentId.wrap(1), 1 ether); - } - - function test_fail_addReward_NoReward() public prankExecAsDeployer { - vm.expectRevert(NoReward.selector); - contentPool.addReward(ContentId.wrap(1), 0); - - vm.expectRevert(NoReward.selector); - contentPool.addReward(ContentId.wrap(1), 100_001 ether); - } - - function test_fullProcess() public prankExecAsDeployer { - // Add some initial reward - contentPool.addReward(ContentId.wrap(1), 1 ether); - - // Update a user shares - contentPool.onFraktionsTransferred( - address(0), - address(1), - ContentId.wrap(1).premiumFraktionId().asSingletonArray(), - uint256(1).asSingletonArray() - ); - - // Compute it's reward - contentPool.computeAllPoolsBalance(address(1)); - } - - // Test the transfer of fraktion betwen two users - function test_transferFraktion() public prankExecAsDeployer { - // Add some initial reward - console.log(""); - console.log("- Add some initial reward"); - contentPool.addReward(ContentId.wrap(1), 2 ether); - - FraktionId[] memory fraktionIds = new FraktionId[](2); - fraktionIds[0] = ContentId.wrap(1).premiumFraktionId(); - fraktionIds[1] = ContentId.wrap(1).goldFraktionId(); - uint256[] memory amounts = new uint256[](2); - amounts[0] = 2; - amounts[1] = 1; - - // Update a user shares - console.log(""); - console.log("- Simulate fraktion mint"); - contentPool.onFraktionsTransferred(address(0), address(1), fraktionIds, amounts); - - // Add a few other rewards - console.log(""); - console.log("- Add new reward"); - contentPool.addReward(ContentId.wrap(1), 10 ether); - - // Compute it's reward - console.log(""); - console.log("- Compute balance"); - contentPool.computeAllPoolsBalance(address(1)); - - // Assert the user has pending founds - assertEq(contentPool.getAvailableFounds(address(1)), 12 ether); - - contentPool.withdrawFounds(address(1)); - assertEq(contentPool.getAvailableFounds(address(1)), 0); - assertEq(frakToken.balanceOf(address(1)), 12 ether); - - // Transfer the fraktion to user2 - console.log(""); - console.log("- Transfer to user 2"); - contentPool.onFraktionsTransferred(address(1), address(2), fraktionIds, amounts); - // Ensure the fraktion transfer didn't trigger any new movment - assertEq(contentPool.getAvailableFounds(address(1)), 0); - assertEq(contentPool.getAvailableFounds(address(2)), 0); - - // Add a few other rewards - contentPool.addReward(ContentId.wrap(1), 20 ether); - - console.log(""); - console.log("- Compute user 2"); - contentPool.computeAllPoolsBalance(address(2)); - // contentPool.getParticipantStates(address(2)); - assertEq(contentPool.getAvailableFounds(address(2)), 20 ether); - - // Mint a few more fraktion to user 3 - contentPool.onFraktionsTransferred(address(0), address(3), fraktionIds, amounts); - contentPool.addReward(ContentId.wrap(1), 20 ether); - - // Mint a few more fraktion to user 3 - contentPool.onFraktionsTransferred(address(0), address(4), fraktionIds, amounts); - contentPool.onFraktionsTransferred(address(0), address(5), fraktionIds, amounts); - contentPool.addReward(ContentId.wrap(1), 20 ether); - - console.log(""); - console.log("- Compute user 2"); - contentPool.computeAllPoolsBalance(address(2)); - assertEq(contentPool.getAvailableFounds(address(2)), 35 ether); - - // Mint a few more fraktion to user 3 - contentPool.onFraktionsTransferred(address(4), address(0), fraktionIds, amounts); - contentPool.onFraktionsTransferred(address(5), address(0), fraktionIds, amounts); - contentPool.addReward(ContentId.wrap(1), 20 ether); - - contentPool.computeAllPoolsBalance(address(2)); - assertEq(contentPool.getAvailableFounds(address(2)), 45 ether); - - contentPool.computeAllPoolsBalance(address(4)); - assertEq(contentPool.getAvailableFounds(address(4)), 5 ether); - - contentPool.computeAllPoolsBalance(address(5)); - assertEq(contentPool.getAvailableFounds(address(5)), 5 ether); - } -} diff --git a/test_old/tokens/FraktionTokens.t.sol b/test_old/tokens/FraktionTokens.t.sol deleted file mode 100644 index 24abf41..0000000 --- a/test_old/tokens/FraktionTokens.t.sol +++ /dev/null @@ -1,96 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { PRBTest } from "@prb/test/PRBTest.sol"; -import { StdUtils } from "@forge-std/StdUtils.sol"; -import { FraktionTokens } from "@frak/fraktions/FraktionTokens.sol"; -import { UUPSTestHelper } from "../UUPSTestHelper.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { ContentId } from "@frak/libs/ContentId.sol"; -import { FraktionId } from "@frak/libs/FraktionId.sol"; -import { NotAuthorized, InvalidAddress, BadgeTooLarge, InvalidFraktionType } from "@frak/utils/FrakErrors.sol"; - -/// Testing the frak l2 token -contract FraktionTokensTest is UUPSTestHelper, StdUtils { - using ArrayLib for uint256; - - FraktionTokens fraktionTokens; - - uint256[] internal sampleArray = uint256(3).asSingletonArray(); - - function setUp() public { - // Deploy our contract via proxy and set the proxy address - bytes memory initData = abi.encodeCall(FraktionTokens.initialize, ("test")); - address proxyAddress = deployContract(address(new FraktionTokens()), initData); - fraktionTokens = FraktionTokens(proxyAddress); - } - - /* - * ===== TEST : initialize(address childChainManager) ===== - */ - function test_fail_initialize_CantInitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - fraktionTokens.initialize("test"); - } - - /* - * ===== TEST : mintNewContent(address ownerAddress) ===== - */ - function test_mintNewContent() public prankExecAsDeployer { - ContentId contentId = fraktionTokens.mintNewContent(address(1), sampleArray, sampleArray); - FraktionId nftId = contentId.creatorFraktionId(); - assertEq(fraktionTokens.balanceOf(address(1), FraktionId.unwrap(nftId)), 1); - } - - function test_fail_mintNewContent_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - fraktionTokens.mintNewContent(address(1), sampleArray, sampleArray); - } - - function test_fail_mintNewContent_InvalidAddress() public prankExecAsDeployer { - vm.expectRevert("ERC1155: mint to the zero address"); - fraktionTokens.mintNewContent(address(0), sampleArray, sampleArray); - } - - /* - * ===== TEST : mint(address to, uint256 id, uint256 amount) ===== - */ - function test_mint() public prankExecAsDeployer { - fraktionTokens.mint(address(1), 1312, 1); - assertEq(fraktionTokens.balanceOf(address(1), 1312), 1); - } - - function test_fail_mint_NotAuthorized() public { - vm.expectRevert(NotAuthorized.selector); - fraktionTokens.mint(address(1), 1312, 1); - } - - function test_fail_mint_InvalidAddress() public prankExecAsDeployer { - vm.expectRevert("ERC1155: mint to the zero address"); - fraktionTokens.mint(address(0), 1312, 1); - } - - /* - * ===== TEST : safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) ===== - */ - function test_transfer() public { - // Mint a few initial tokens to different address - vm.startPrank(deployer); - fraktionTokens.mint(address(1), 1312, 1); - fraktionTokens.mint(address(2), 1312, 1); - fraktionTokens.mint(address(3), 1312, 1); - vm.stopPrank(); - - // Ensure we can transfer all the assets to the target address - vm.prank(address(1)); - fraktionTokens.safeTransferFrom(address(1), address(13), 1312, 1, ""); - - vm.prank(address(2)); - fraktionTokens.safeTransferFrom(address(2), address(13), 1312, 1, ""); - - vm.prank(address(3)); - fraktionTokens.safeTransferFrom(address(3), address(13), 1312, 1, ""); - - assertEq(fraktionTokens.balanceOf(address(13), 1312), 3); - } -} diff --git a/test_old/tokens/FrkToken.t.sol b/test_old/tokens/FrkToken.t.sol deleted file mode 100644 index 584c897..0000000 --- a/test_old/tokens/FrkToken.t.sol +++ /dev/null @@ -1,307 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { PRBTest } from "@prb/test/PRBTest.sol"; -import { StdUtils } from "@forge-std/StdUtils.sol"; -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { IFrakToken } from "@frak/tokens/FrakToken.sol"; -import { NotAuthorized } from "@frak/utils/FrakErrors.sol"; -import { UUPSTestHelper } from "../UUPSTestHelper.sol"; - -/// Testing the frak l2 token -contract FrkTokenL2Test is UUPSTestHelper, StdUtils { - FrakToken frakToken; - - function setUp() public { - // Deploy our contract via proxy and set the proxy address - bytes memory initData = abi.encodeCall(FrakToken.initialize, ()); - address proxyAddress = deployContract(address(new FrakToken()), initData); - frakToken = FrakToken(proxyAddress); - } - - /* - * ===== TEST : invariant ===== - */ - function invariant_supplyCap() public { - assertGt(frakToken.cap(), frakToken.totalSupply()); - } - - function invariant_metadata() public { - assertEq(frakToken.name(), "Frak"); - assertEq(frakToken.symbol(), "FRK"); - assertEq(frakToken.decimals(), 18); - } - - /* - * ===== TEST : initialize(address childChainManager) ===== - */ - function test_fail_initialize_CantInitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - frakToken.initialize(); - } - - /* - * ===== TEST : name() ===== - */ - function test_name() public { - assertEq(frakToken.name(), "Frak"); - } - - /* - * ===== TEST : decimals() ===== - */ - function test_decimals() public { - assertEq(frakToken.decimals(), 18); - } - - /* - * ===== TEST : symbol() ===== - */ - function test_symbol() public { - assertEq(frakToken.symbol(), "FRK"); - } - - /* - * ===== TEST : totalSupply() ===== - */ - function test_totalSupply() public { - assertEq(frakToken.totalSupply(), 0); - - prankDeployer(); - frakToken.mint(address(1), 1); - assertEq(frakToken.totalSupply(), 1); - - vm.prank(address(1)); - frakToken.burn(1); - assertEq(frakToken.totalSupply(), 0); - } - - /* - * ===== TEST : balanceOf(address account) ===== - */ - function test_balanceOf() public { - assertEq(frakToken.balanceOf(address(1)), 0); - - prankDeployer(); - frakToken.mint(address(1), 1); - - assertEq(frakToken.balanceOf(address(1)), 1); - - vm.prank(address(1)); - frakToken.burn(1); - assertEq(frakToken.balanceOf(address(1)), 0); - } - - /* - * ===== TEST : transfer(address to, uint256 amount) ===== - */ - function test_transfer() public { - prankDeployer(); - frakToken.mint(address(1), 10); - - vm.prank(address(1)); - frakToken.transfer(address(2), 5); - assertEq(frakToken.balanceOf(address(2)), 5); - assertEq(frakToken.balanceOf(address(1)), 5); - - vm.prank(address(1)); - frakToken.transfer(address(2), 5); - assertEq(frakToken.balanceOf(address(2)), 10); - assertEq(frakToken.balanceOf(address(1)), 0); - } - - function testFuzz_transfer(address target, uint256 amount) public { - vm.assume(target != address(0) && target != address(1)); - vm.assume(amount < 3_000_000_000 ether); - - prankDeployer(); - frakToken.mint(address(1), amount); - - vm.prank(address(1)); - frakToken.transfer(target, amount); - assertEq(frakToken.balanceOf(target), amount); - assertEq(frakToken.balanceOf(address(1)), 0); - } - - function test_fail_transfer_NotEnoughBalance() public { - prankDeployer(); - frakToken.mint(address(1), 10); - - vm.expectRevert("ERC20: transfer amount exceeds balance"); - vm.prank(address(1)); - frakToken.transfer(address(2), 15); - } - - function test_fail_transfer_InvalidAddress() public { - prankDeployer(); - frakToken.mint(address(1), 10); - - vm.expectRevert("ERC20: transfer to the zero address"); - vm.prank(address(1)); - frakToken.transfer(address(0), 5); - } - - /* - * ===== TEST : approve(address spender, uint256 amount) ===== - * ===== TEST : allowance(address owner, address spender) ===== - * ===== TEST : addedValue(address owner, uint256 addedValue) ===== - * ===== TEST : decreaseAllowance(address owner, uint256 subtractedValue) ===== - */ - function test_approve_increase_decrease() public { - uint256 allowance = frakToken.allowance(address(this), address(1)); - assertEq(allowance, 0); - - frakToken.approve(address(1), 100); - allowance = frakToken.allowance(address(this), address(1)); - assertEq(allowance, 100); - - frakToken.increaseAllowance(address(1), 50); - allowance = frakToken.allowance(address(this), address(1)); - assertEq(allowance, 150); - - frakToken.decreaseAllowance(address(1), 50); - allowance = frakToken.allowance(address(this), address(1)); - assertEq(allowance, 100); - } - - function test_fail_approve_InvalidAddress() public { - vm.expectRevert("ERC20: approve to the zero address"); - frakToken.approve(address(0), 100); - } - - function test_fail_increaseAllowance_InvalidAddress() public { - vm.expectRevert("ERC20: approve to the zero address"); - frakToken.increaseAllowance(address(0), 100); - } - - function test_fail_decreaseAllowance_BelowZero() public { - vm.expectRevert("ERC20: decreased allowance below zero"); - frakToken.decreaseAllowance(address(1), 100); - } - - /* - * ===== TEST : transferFrom(address from, address to, uint256 amount) ===== - */ - function test_transferFrom(uint256 amount) public { - vm.assume(amount < 3_000_000_000 ether); - - prankDeployer(); - frakToken.mint(address(1), amount); - - vm.prank(address(1)); - frakToken.approve(address(2), amount); - - vm.prank(address(2)); - frakToken.transferFrom(address(1), address(3), amount); - assertEq(frakToken.balanceOf(address(3)), amount); - } - - /* - * ===== TEST : mint(address to, uint256 amount) ===== - */ - function test_fail_mint_NotMinter() public { - vm.expectRevert(NotAuthorized.selector); - frakToken.mint(address(1), 1 ether); - } - - function test_fail_mint_Addr0() public prankExecAsDeployer { - vm.expectRevert("ERC20: mint to the zero address"); - frakToken.mint(address(0), 1 ether); - } - - function test_fail_mint_TooLarge() public prankExecAsDeployer { - vm.expectRevert(IFrakToken.CapExceed.selector); - frakToken.mint(address(1), 3_000_000_001 ether); - } - - function testFuzz_mint(uint256 mintAmount) public prankExecAsDeployer { - vm.assume(mintAmount < 3_000_000_000 ether); - frakToken.mint(address(1), mintAmount); - assertEq(frakToken.balanceOf(address(1)), mintAmount); - } - - /* - * ===== TEST : permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 - s) ===== - */ - - bytes32 constant PERMIT_TYPEHASH = - keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); - - function test_permit() public { - uint256 privateKey = 0xACAB; - address owner = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - frakToken.getDomainSeperator(), - keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(2), 1 ether, 0, block.timestamp)) - ) - ) - ); - - frakToken.permit(owner, address(2), 1e18, block.timestamp, v, r, s); - - assertEq(frakToken.allowance(owner, address(2)), 1 ether); - } - - function test_fail_permit_InvalidSigner() public { - uint256 privateKey = 0xACAB; - address owner = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - frakToken.getDomainSeperator(), - keccak256(abi.encode(PERMIT_TYPEHASH, address(1), address(2), 1 ether, 0, block.timestamp)) - ) - ) - ); - - vm.expectRevert(IFrakToken.InvalidSigner.selector); - frakToken.permit(owner, address(2), 1 ether, block.timestamp, v, r, s); - } - - function test_fail_permit_InvalidAddress() public { - uint256 privateKey = 0xACAB; - address owner = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - frakToken.getDomainSeperator(), - keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0), 1 ether, 0, block.timestamp)) - ) - ) - ); - - vm.expectRevert("ERC20: approve to the zero address"); - frakToken.permit(owner, address(0), 1 ether, block.timestamp, v, r, s); - } - - function test_fail_permit_PermitDelayExpired() public { - uint256 privateKey = 0xACAB; - address owner = vm.addr(privateKey); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign( - privateKey, - keccak256( - abi.encodePacked( - "\x19\x01", - frakToken.getDomainSeperator(), - keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(1), 0, 1 ether, block.timestamp - 1)) - ) - ) - ); - - vm.expectRevert(IFrakToken.PermitDelayExpired.selector); - frakToken.permit(owner, address(1), 1 ether, block.timestamp - 1, v, r, s); - } -} diff --git a/test_old/wallets/FrakTreasuryWallet.t.sol b/test_old/wallets/FrakTreasuryWallet.t.sol deleted file mode 100644 index 041cd1f..0000000 --- a/test_old/wallets/FrakTreasuryWallet.t.sol +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { StdUtils } from "@forge-std/StdUtils.sol"; -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { FrakRoles } from "@frak/roles/FrakRoles.sol"; -import { FrakTreasuryWallet, NotEnoughTreasury } from "@frak/wallets/FrakTreasuryWallet.sol"; -import { FrkTokenTestHelper } from "../FrkTokenTestHelper.sol"; -import { NotAuthorized, InvalidAddress, NoReward, RewardTooLarge, InvalidArray } from "@frak/utils/FrakErrors.sol"; - -/// Testing the frak l2 token -contract FrakTreasuryWalletTest is FrkTokenTestHelper, StdUtils { - using ArrayLib for address; - using ArrayLib for uint256; - - address treasuryWalletAddr; - FrakTreasuryWallet treasuryWallet; - - function setUp() public { - _setupFrkToken(); - - // Deploy our multi vesting wallets - bytes memory initData = abi.encodeCall(FrakTreasuryWallet.initialize, (address(frakToken))); - treasuryWalletAddr = deployContract(address(new FrakTreasuryWallet()), initData); - treasuryWallet = FrakTreasuryWallet(treasuryWalletAddr); - - // Grant the minter role to our treasury wallets - prankDeployer(); - frakToken.grantRole(FrakRoles.MINTER, treasuryWalletAddr); - } - - /* - * ===== TEST : initialize(address tokenAddr) ===== - */ - function test_fail_initialize_CantInitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - treasuryWallet.initialize(address(0)); - } - - /* - * ===== TEST : transfer(address target, uint256 amount) ===== - */ - function test_transfer() public { - prankDeployer(); - treasuryWallet.transfer(address(1), 1 ether); - - assertEq(frakToken.balanceOf(address(1)), 1 ether); - assertEq(frakToken.balanceOf(treasuryWalletAddr) > 0, true); - } - - function testFuzz_transfer(address target, uint96 amount) public { - vm.assume(target != address(0)); - amount = uint96(bound(amount, 1, 500_000 ether)); - - // Get the previous balance - uint256 prevBalance = frakToken.balanceOf(target); - - prankDeployer(); - treasuryWallet.transfer(target, uint256(amount)); - - // Get the balance diff - uint256 newBalance = frakToken.balanceOf(target); - uint256 balanceDiff = newBalance - prevBalance; - - assertEq(balanceDiff, uint256(amount)); - } - - function test_fail_transfer_NotMinter() public { - vm.expectRevert(NotAuthorized.selector); - treasuryWallet.transfer(address(1), 1 ether); - } - - function test_fail_transfer_InvalidAddress() public prankExecAsDeployer { - vm.expectRevert(InvalidAddress.selector); - treasuryWallet.transfer(address(0), 1 ether); - } - - function test_fail_transfer_NoReward() public prankExecAsDeployer { - vm.expectRevert(NoReward.selector); - treasuryWallet.transfer(address(1), 0); - } - - function test_fail_transfer_RewardTooLarge() public prankExecAsDeployer { - vm.expectRevert(RewardTooLarge.selector); - treasuryWallet.transfer(address(1), 500_001 ether); - } - - function test_fail_transfer_NotEnoughTreasury() public prankExecAsDeployer { - uint256 totalToTransfer = 330_000_000 ether; - uint256 iteration = 500_000 ether; - - do { - treasuryWallet.transfer(address(1), iteration); - totalToTransfer -= iteration; - } while (totalToTransfer > 0); - - vm.expectRevert(NotEnoughTreasury.selector); - treasuryWallet.transfer(address(1), iteration); - } - - /* - * ===== TEST : transferBatch(address[] calldata targets, uint256[] calldata amounts) ===== - uint256[] memory listenCounts = new uint256[](1); - */ - function test_transferBatch() public { - prankDeployer(); - (address[] memory addrs, uint256[] memory amounts) = baseBatchParam(1 ether); - treasuryWallet.transferBatch(addrs, amounts); - - assertEq(frakToken.balanceOf(address(1)), 1 ether); - assertEq(frakToken.balanceOf(treasuryWalletAddr) > 0, true); - } - - function testFuzz_transferBatch(address target, uint96 amount) public { - vm.assume(target != address(0)); - amount = uint96(bound(amount, 1, 500_000 ether)); - - // Get the previous balance - uint256 prevBalance = frakToken.balanceOf(target); - - prankDeployer(); - (address[] memory addrs, uint256[] memory amounts) = baseBatchParam(target, uint256(amount)); - treasuryWallet.transferBatch(addrs, amounts); - - // Get the balance diff - uint256 newBalance = frakToken.balanceOf(target); - uint256 balanceDiff = newBalance - prevBalance; - - assertEq(balanceDiff, uint256(amount)); - } - - function test_fail_transferBatch_NotMinter() public { - vm.expectRevert(NotAuthorized.selector); - (address[] memory addrs, uint256[] memory amounts) = baseBatchParam(1 ether); - treasuryWallet.transferBatch(addrs, amounts); - } - - function test_fail_transferBatch_NoReward() public prankExecAsDeployer { - (address[] memory addrs, uint256[] memory amounts) = baseBatchParam(0); - vm.expectRevert(NoReward.selector); - treasuryWallet.transferBatch(addrs, amounts); - } - - function test_fail_transferBatch_RewardTooLarge() public prankExecAsDeployer { - (address[] memory addrs, uint256[] memory amounts) = baseBatchParam(500_001 ether); - vm.expectRevert(RewardTooLarge.selector); - treasuryWallet.transferBatch(addrs, amounts); - } - - function test_fail_transferBatch_InvalidArray() public prankExecAsDeployer { - uint256[] memory amounts = uint256(1 ether).asSingletonArray(); - address[] memory addrs = new address[](2); - vm.expectRevert(InvalidArray.selector); - treasuryWallet.transferBatch(addrs, amounts); - } - - function test_fail_transferBatch_InvalidArray_Empty() public prankExecAsDeployer { - uint256[] memory amounts = uint256(1 ether).asSingletonArray(); - address[] memory addrs = new address[](0); - vm.expectRevert(InvalidArray.selector); - treasuryWallet.transferBatch(addrs, amounts); - } - - function test_fail_transferBatch_NotEnoughTreasury() public prankExecAsDeployer { - uint256 totalToTransfer = 330_000_000 ether; - uint256 iteration = 500_000 ether; - - do { - treasuryWallet.transfer(address(1), iteration); - totalToTransfer -= iteration; - } while (totalToTransfer > 0); - - (address[] memory addrs, uint256[] memory amounts) = baseBatchParam(iteration); - vm.expectRevert(NotEnoughTreasury.selector); - treasuryWallet.transferBatch(addrs, amounts); - } - - /* - * ===== TEST : multicall(bytes[] calldata data) ===== - */ - function test_multicall() public prankExecAsDeployer { - // Build our calldata - bytes[] memory callingData = new bytes[](2); - callingData[0] = abi.encodeWithSelector(treasuryWallet.transfer.selector, address(1), 1); - callingData[1] = abi.encodeWithSelector(treasuryWallet.transfer.selector, address(1), 2); - - treasuryWallet.multicall(callingData); - } - - function testFuzz_multicall(uint256 amount, address target1, address target2) public prankExecAsDeployer { - vm.assume(target1 != address(0) && target2 != address(0)); - amount = bound(amount, 1, 500_000 ether); - - // Build our calldata - bytes[] memory callingData = new bytes[](2); - callingData[0] = abi.encodeWithSelector(treasuryWallet.transfer.selector, target1, amount); - callingData[1] = abi.encodeWithSelector(treasuryWallet.transfer.selector, target2, amount); - - treasuryWallet.multicall(callingData); - } - - function test_fail_multicall_NotAuthorized() public { - // Build our calldata - bytes[] memory callingData = new bytes[](2); - callingData[0] = abi.encodeWithSelector(treasuryWallet.transfer.selector, address(1), 1); - callingData[1] = abi.encodeWithSelector(treasuryWallet.transfer.selector, address(1), 2); - - vm.expectRevert(NotAuthorized.selector); - treasuryWallet.multicall(callingData); - } - - /* -------------------------------------------------------------------------- */ - /* Utils */ - /* -------------------------------------------------------------------------- */ - - function baseBatchParam(uint256 amount) private pure returns (address[] memory, uint256[] memory) { - return baseBatchParam(address(1), amount); - } - - function baseBatchParam(address addr, uint256 amount) private pure returns (address[] memory, uint256[] memory) { - return (addr.asSingletonArray(), uint256(amount).asSingletonArray()); - } -} diff --git a/test_old/wallets/MultiVestingWallets.t.sol b/test_old/wallets/MultiVestingWallets.t.sol deleted file mode 100644 index a0d8e1b..0000000 --- a/test_old/wallets/MultiVestingWallets.t.sol +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: GNU GPLv3 -pragma solidity 0.8.21; - -import { FrakToken } from "@frak/tokens/FrakToken.sol"; -import { ArrayLib } from "@frak/libs/ArrayLib.sol"; -import { - MultiVestingWallets, NotEnoughFounds, InvalidDuration, InvalidDate -} from "@frak/wallets/MultiVestingWallets.sol"; -import { FrkTokenTestHelper } from "../FrkTokenTestHelper.sol"; -import { NotAuthorized, InvalidArray, InvalidAddress, NoReward, RewardTooLarge } from "@frak/utils/FrakErrors.sol"; - -/// Testing the frak l2 token -contract MultiVestingWalletsTest is FrkTokenTestHelper { - using ArrayLib for address; - using ArrayLib for uint256; - - address multiVestingAddr; - MultiVestingWallets vestingWallets; - - function setUp() public { - _setupFrkToken(); - - // Deploy our multi vesting wallets - bytes memory initData = abi.encodeCall(MultiVestingWallets.initialize, (address(frakToken))); - multiVestingAddr = deployContract(address(new MultiVestingWallets()), initData); - vestingWallets = MultiVestingWallets(multiVestingAddr); - } - - /* - * ===== TEST : initialize(address tokenAddr) ===== - */ - function test_fail_initialize_CantInitTwice() public { - vm.expectRevert("Initializable: contract is already initialized"); - vestingWallets.initialize(address(0)); - } - - /* - * ===== TEST : name() ===== - */ - function test_name() public { - assertEq(vestingWallets.name(), "Vested FRK Token"); - } - - /* - * ===== TEST : decimals() ===== - */ - function test_decimals() public { - assertEq(vestingWallets.decimals(), 18); - } - - /* - * ===== TEST : symbol() ===== - */ - function test_symbol() public { - assertEq(vestingWallets.symbol(), "vFRK"); - } - - /* - * ===== TEST : availableReserve() ===== - */ - function test_availableReserve() public { - assertEq(vestingWallets.availableReserve(), 0); - prankDeployer(); - frakToken.mint(multiVestingAddr, 1); - assertEq(vestingWallets.availableReserve(), 1); - assertEq(vestingWallets.availableReserve(), frakToken.balanceOf(multiVestingAddr)); - } - - /* - * ===== TEST : transferAvailableReserve(address receiver) ===== - */ - function test_transferAvailableReserve() public withFrkToken(multiVestingAddr) { - // Ask to transfer the available reserve - prankDeployer(); - vestingWallets.transferAvailableReserve(address(1)); - assertEq(vestingWallets.availableReserve(), 0); - assertEq(frakToken.balanceOf(address(1)), 10); - } - - function test_fail_transferAvailableReserve_NotAdmin() public withFrkToken(multiVestingAddr) { - // Ask to transfer the available reserve - vm.expectRevert(NotAuthorized.selector); - vestingWallets.transferAvailableReserve(address(1)); - } - - function test_fail_TransferAvailableReserve_NoReserve() public { - // Ask to transfer the available reserve - vm.expectRevert(NoReward.selector); - prankDeployer(); - vestingWallets.transferAvailableReserve(address(1)); - } - - /* - * ===== TEST : createVest( - address beneficiary, - uint256 amount, - uint32 duration, - uint48 startDate - ) ===== - */ - function test_createVest() public withFrkToken(multiVestingAddr) { - // Ask to transfer the available reserve - prankDeployer(); - vestingWallets.createVest(address(1), 10, 10, uint48(block.timestamp + 1)); - assertEq(vestingWallets.balanceOf(address(1)), 10); - } - - function test_fail_createVest_NotManager() public withFrkToken(multiVestingAddr) { - vm.expectRevert(NotAuthorized.selector); - vestingWallets.createVest(address(1), 10, 10, uint48(block.timestamp + 1)); - } - - function test_fail_createVest_InvalidDuration() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(InvalidDuration.selector); - vestingWallets.createVest(address(1), 10, 0, uint48(block.timestamp + 1)); - } - - function test_fail_createVest_InvalidStartDate() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(InvalidDate.selector); - vestingWallets.createVest(address(1), 10, 10, uint48(block.timestamp - 1)); - } - - function test_fail_createVest_InvalidStartDateTooFar() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(InvalidDate.selector); - vestingWallets.createVest(address(1), 10, 10, 2_525_644_801); - } - - function test_fail_createVest_NotEnoughReserve() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(NotEnoughFounds.selector); - vestingWallets.createVest(address(1), 11, 10, uint48(block.timestamp + 1)); - } - - function test_fail_createVest_InvalidAddress() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(InvalidAddress.selector); - vestingWallets.createVest(address(0), 10, 10, uint48(block.timestamp + 1)); - } - - function test_fail_createVest_InvalidReward() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(NoReward.selector); - vestingWallets.createVest(address(10), 0, 10, uint48(block.timestamp + 1)); - } - - function test_fail_createVest_TooLargeReward() public withLotFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(RewardTooLarge.selector); - vestingWallets.createVest(address(10), 200_000_001 ether, 10, uint48(block.timestamp + 1)); - } - - /* - * ===== createVestBatch( - address[] calldata beneficiaries, - uint256[] calldata amounts, - uint32 duration, - uint48 startDate - ) ===== - */ - function test_createVestBatch() public withFrkToken(multiVestingAddr) { - // Ask to transfer the available reserve - prankDeployer(); - vestingWallets.createVestBatch( - address(1).asSingletonArray(), uint256(10).asSingletonArray(), 10, uint48(block.timestamp + 1) - ); - assertEq(vestingWallets.balanceOf(address(1)), 10); - } - - function test_fail_createVestBatch_NotManager() public withFrkToken(multiVestingAddr) { - vm.expectRevert(NotAuthorized.selector); - vestingWallets.createVestBatch( - address(1).asSingletonArray(), uint256(10).asSingletonArray(), 10, uint48(block.timestamp + 1) - ); - } - - function test_fail_createVestBatch_NotEnoughReserve() public withFrkToken(multiVestingAddr) prankExecAsDeployer { - vm.expectRevert(NotEnoughFounds.selector); - vestingWallets.createVestBatch( - address(1).asSingletonArray(), uint256(11).asSingletonArray(), 10, uint48(block.timestamp + 1) - ); - } - - function test_fail_createVestBatch_EmptyArray() public withFrkToken(multiVestingAddr) { - address[] memory addresses = new address[](0); - uint256[] memory amounts = new uint256[](0); - prankDeployer(); - - vm.expectRevert(InvalidArray.selector); - vestingWallets.createVestBatch(addresses, amounts, 10, uint48(block.timestamp + 1)); - } - - function test_fail_createVestBatch_ArrayInvalidLength() public withFrkToken(multiVestingAddr) { - address[] memory addresses = new address[](0); - prankDeployer(); - - vm.expectRevert(InvalidArray.selector); - vestingWallets.createVestBatch(addresses, uint256(10).asSingletonArray(), 10, uint48(block.timestamp + 1)); - } - - /* - * ===== TEST : transfer(address to, uint24 vestingId) ===== - */ - function test_transfer() public withFrkToken(multiVestingAddr) { - // Ask to transfer the available reserve - prankDeployer(); - vestingWallets.createVest(address(1), 10, 10, uint48(block.timestamp + 1)); - assertEq(vestingWallets.balanceOf(address(1)), 10); - // Ask to transfer the vesting - vm.prank(address(1)); - vestingWallets.transfer(address(2), 0); - } -}