diff --git a/contracts/modules/royalty-module/policies/RoyaltyPolicyLS.sol b/contracts/modules/royalty-module/policies/RoyaltyPolicyLS.sol index 332e7b942..1e9bc908f 100644 --- a/contracts/modules/royalty-module/policies/RoyaltyPolicyLS.sol +++ b/contracts/modules/royalty-module/policies/RoyaltyPolicyLS.sol @@ -21,6 +21,13 @@ import { Errors } from "contracts/lib/Errors.sol"; contract RoyaltyPolicyLS is IRoyaltyPolicyLS, ERC1155Holder { using SafeERC20 for IERC20; + struct LSRoyaltyData { + address splitClone; // Indicates the address of the LiquidSplitClone contract for a given ipId + address claimer; // Indicates the address of the claimer contract for a given ipId + uint32 royaltyStack; // Indicates the royalty stack for a given ipId + uint32 minRoyalty; // Indicates the minimum royalty for a given ipId + } + /// @notice Percentage scale - 1000 rnfts represents 100% uint32 public constant TOTAL_RNFT_SUPPLY = 1000; @@ -36,13 +43,6 @@ contract RoyaltyPolicyLS is IRoyaltyPolicyLS, ERC1155Holder { /// @notice LiquidSplitMain address address public immutable LIQUID_SPLIT_MAIN; - struct LSRoyaltyData { - address splitClone; // Indicates the address of the LiquidSplitClone contract for a given ipId - address claimer; // Indicates the address of the claimer contract for a given ipId - uint32 royaltyStack; // Indicates the royalty stack for a given ipId - uint32 minRoyalty; // Indicates the minimum royalty for a given ipId - } - /// @notice Links the ipId to its royalty data mapping(address ipId => LSRoyaltyData) public royaltyData; @@ -138,6 +138,9 @@ contract RoyaltyPolicyLS is IRoyaltyPolicyLS, ERC1155Holder { ILiquidSplitMain(LIQUID_SPLIT_MAIN).withdraw(_account, _withdrawETH, _tokens); } + /// @notice Checks if the royalty stack is valid + /// @param _parentIpIds The parent ipIds + /// @param _minRoyalty The minimum royalty function _checkRoyaltyStackIsValid(address[] memory _parentIpIds, uint32 _minRoyalty) internal view returns (uint32, uint32) { // the loop below is limited to a length of 100 // given the minimum royalty step of 1% and a cap of 100% diff --git a/test/foundry/modules/royalty/RoyaltyModule.t.sol b/test/foundry/modules/royalty/RoyaltyModule.t.sol new file mode 100644 index 000000000..7a6478ac2 --- /dev/null +++ b/test/foundry/modules/royalty/RoyaltyModule.t.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + + +import {console2} from "forge-std/console2.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import { TestHelper } from "../../../utils/TestHelper.sol"; +import { Errors } from "contracts/lib/Errors.sol"; + +contract TestRoyaltyModule is TestHelper { + event RoyaltyPolicyWhitelistUpdated(address royaltyPolicy, bool allowed); + event RoyaltyTokenWhitelistUpdated(address token, bool allowed); + event RoyaltyPolicySet(address ipId, address royaltyPolicy, bytes data); + event RoyaltyPaid(address receiverIpId, address payerIpId, address sender, address token, uint256 amount); + + function setUp() public override { + super.setUp(); + + // fund USDC + vm.startPrank(USDC_RICH); + IERC20(USDC).transfer(ipAccount2, 1000 * 10 ** 6); // 1000 USDC + vm.stopPrank(); + + // whitelist royalty policy + royaltyModule.whitelistRoyaltyPolicy(address(royaltyPolicyLS), true); + + // whitelist royalty token + royaltyModule.whitelistRoyaltyToken(USDC, true); + } + + function test_RoyaltyModule_whitelistRoyaltyPolicy_revert_ZeroRoyaltyToken() public { + vm.expectRevert(Errors.RoyaltyModule__ZeroRoyaltyToken.selector); + + royaltyModule.whitelistRoyaltyToken(address(0), true); + } + + function test_RoyaltyModule_whitelistRoyaltyPolicy() public { + assertEq(royaltyModule.isWhitelistedRoyaltyPolicy(address(1)), false); + + vm.expectEmit(true, true, true, true, address(royaltyModule)); + emit RoyaltyPolicyWhitelistUpdated(address(1), true); + + royaltyModule.whitelistRoyaltyPolicy(address(1), true); + + assertEq(royaltyModule.isWhitelistedRoyaltyPolicy(address(1)), true); + } + + function test_RoyaltyModule_whitelistRoyaltyToken_revert_ZeroRoyaltyPolicy() public { + vm.expectRevert(Errors.RoyaltyModule__ZeroRoyaltyPolicy.selector); + + royaltyModule.whitelistRoyaltyPolicy(address(0), true); + } + + function test_RoyaltyModule_whitelistRoyaltyToken() public { + assertEq(royaltyModule.isWhitelistedRoyaltyToken(address(1)), false); + + vm.expectEmit(true, true, true, true, address(royaltyModule)); + emit RoyaltyTokenWhitelistUpdated(address(1), true); + + royaltyModule.whitelistRoyaltyToken(address(1), true); + + assertEq(royaltyModule.isWhitelistedRoyaltyToken(address(1)), true); + } + + function test_RoyaltyModule_setRoyaltyPolicy_revert_AlreadySetRoyaltyPolicy() public { + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data); + + vm.expectRevert(Errors.RoyaltyModule__AlreadySetRoyaltyPolicy.selector); + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data); + } + + function test_RoyaltyModule_setRoyaltyPolicy_revert_NotWhitelistedRoyaltyPolicy() public { + vm.expectRevert(Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy.selector); + + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(1), parentIpIds1, data); + } + + function test_RoyaltyModule_setRoyaltyPolicy_revert_IncompatibleRoyaltyPolicy() public { + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + address[] memory parentIpIds2 = new address[](1); + parentIpIds2[0] = ipAccount1; + uint32 minRoyaltyIpAccount2 = 100; // 10% + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + + royaltyModule.whitelistRoyaltyPolicy(address(1), true); + + vm.expectRevert(Errors.RoyaltyModule__IncompatibleRoyaltyPolicy.selector); + royaltyModule.setRoyaltyPolicy(ipAccount2, address(1), parentIpIds2, data2); + } + + function test_RoyaltyModule_setRoyaltyPolicy() public { + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data = abi.encode(minRoyaltyIpAccount1); + + vm.expectEmit(true, true, true, true, address(royaltyModule)); + emit RoyaltyPolicySet(ipAccount1, address(royaltyPolicyLS), data); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data); + + assertEq(royaltyModule.royaltyPolicies(ipAccount1), address(royaltyPolicyLS)); + } + + function test_RoyaltyModule_payRoyaltyOnBehalf_revert_NoRoyaltyPolicySet() public { + vm.expectRevert(Errors.RoyaltyModule__NoRoyaltyPolicySet.selector); + + royaltyModule.payRoyaltyOnBehalf(ipAccount1, ipAccount2, USDC, 100); + } + + function test_RoyaltyModule_payRoyaltyOnBehalf_revert_NotWhitelistedRoyaltyToken() public { + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data); + + vm.expectRevert(Errors.RoyaltyModule__NotWhitelistedRoyaltyToken.selector); + royaltyModule.payRoyaltyOnBehalf(ipAccount1, ipAccount2, address(1), 100); + } + + function test_RoyaltyModule_payRoyaltyOnBehalf_revert_NotWhitelistedRoyaltyPolicy() public { + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data); + + royaltyModule.whitelistRoyaltyPolicy(address(royaltyPolicyLS), false); + + vm.expectRevert(Errors.RoyaltyModule__NotWhitelistedRoyaltyPolicy.selector); + royaltyModule.payRoyaltyOnBehalf(ipAccount1, ipAccount2, USDC, 100); + } + + function test_RoyaltyModule_payRoyaltyOnBehalf() public { + uint256 royaltyAmount = 100 * 10 ** 6; // 100 USDC + + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; // 10% + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + address[] memory parentIpIds2 = new address[](0); + uint32 minRoyaltyIpAccount2 = 100; // 10% + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + + royaltyModule.setRoyaltyPolicy(ipAccount2, address(royaltyPolicyLS), parentIpIds2, data2); + + (address splitClone1,,,) = royaltyPolicyLS.royaltyData(ipAccount1); + + vm.startPrank(ipAccount2); + IERC20(USDC).approve(address(royaltyPolicyLS), royaltyAmount); + + uint256 ipAccount2USDCBalBefore = IERC20(USDC).balanceOf(ipAccount2); + uint256 splitClone1USDCBalBefore = IERC20(USDC).balanceOf(splitClone1); + + vm.expectEmit(true, true, true, true, address(royaltyModule)); + emit RoyaltyPaid(ipAccount1, ipAccount2, ipAccount2, USDC, royaltyAmount); + + royaltyModule.payRoyaltyOnBehalf(ipAccount1, ipAccount2, USDC, royaltyAmount); + + uint256 ipAccount2USDCBalAfter = IERC20(USDC).balanceOf(ipAccount2); + uint256 splitClone1USDCBalAfter = IERC20(USDC).balanceOf(splitClone1); + + assertEq(ipAccount2USDCBalBefore - ipAccount2USDCBalAfter, royaltyAmount); + assertEq(splitClone1USDCBalAfter - splitClone1USDCBalBefore, royaltyAmount); + } +} \ No newline at end of file diff --git a/test/foundry/modules/royalty/RoyaltyPolicyLS.t.sol b/test/foundry/modules/royalty/RoyaltyPolicyLS.t.sol new file mode 100644 index 000000000..63c99deb6 --- /dev/null +++ b/test/foundry/modules/royalty/RoyaltyPolicyLS.t.sol @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.23; + +import { console2 } from "forge-std/console2.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +import { TestHelper } from "../../../utils/TestHelper.sol"; +import { RoyaltyPolicyLS } from "../../../../contracts/modules/royalty-module/policies/RoyaltyPolicyLS.sol"; +import { IClaimerLS } from "../../../../contracts/interfaces/modules/royalty/policies/IClaimerLS.sol"; +import { ILiquidSplitClone } from "../../../../contracts/interfaces/modules/royalty/policies/ILiquidSplitClone.sol"; +import { Errors } from "../../../../contracts/lib/Errors.sol"; + + + +contract TestLSClaimer is TestHelper { + RoyaltyPolicyLS internal testRoyaltyPolicyLS; + + function setUp() public override { + super.setUp(); + + // whitelist royalty policy + royaltyModule.whitelistRoyaltyPolicy(address(royaltyPolicyLS), true); + } + + function test_RoyaltyPolicyLS_constructor_revert_ZeroRoyaltyModule() public { + vm.expectRevert(Errors.RoyaltyPolicyLS__ZeroRoyaltyModule.selector); + + testRoyaltyPolicyLS = new RoyaltyPolicyLS(address(0), address(1), LIQUID_SPLIT_FACTORY, LIQUID_SPLIT_MAIN); + } + + function test_RoyaltyPolicyLS_constructor_revert_ZeroLicenseRegistry() public { + vm.expectRevert(Errors.RoyaltyPolicyLS__ZeroLicenseRegistry.selector); + + testRoyaltyPolicyLS = new RoyaltyPolicyLS(address(royaltyModule), address(0), LIQUID_SPLIT_FACTORY, LIQUID_SPLIT_MAIN); + } + + function test_RoyaltyPolicyLS_constructor_revert_ZeroLiquidSplitFactory() public { + vm.expectRevert(Errors.RoyaltyPolicyLS__ZeroLiquidSplitFactory.selector); + + testRoyaltyPolicyLS = new RoyaltyPolicyLS(address(royaltyModule), address(1), address(0), LIQUID_SPLIT_MAIN); + } + + function test_RoyaltyPolicyLS_constructor_revert_ZeroLiquidSplitMain() public { + vm.expectRevert(Errors.RoyaltyPolicyLS__ZeroLiquidSplitMain.selector); + + testRoyaltyPolicyLS = new RoyaltyPolicyLS(address(royaltyModule), address(1), LIQUID_SPLIT_FACTORY, address(0)); + } + + function test_RoyaltyPolicyLS_constructor() public { + testRoyaltyPolicyLS = new RoyaltyPolicyLS(address(royaltyModule), address(1), LIQUID_SPLIT_FACTORY, LIQUID_SPLIT_MAIN); + + assertEq(testRoyaltyPolicyLS.ROYALTY_MODULE(), address(royaltyModule)); + assertEq(testRoyaltyPolicyLS.LICENSE_REGISTRY(), address(1)); + assertEq(testRoyaltyPolicyLS.LIQUID_SPLIT_FACTORY(), LIQUID_SPLIT_FACTORY); + assertEq(testRoyaltyPolicyLS.LIQUID_SPLIT_MAIN(), LIQUID_SPLIT_MAIN); + + } + + function test_RoyaltyPolicyLS_revert_InvalidMinRoyalty() public { + // set root parent royalty policy + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + // set derivative royalty policy + address[] memory parentIpIds2 = new address[](1); + parentIpIds2[0] = ipAccount1; + uint32 minRoyaltyIpAccount2 = 5; + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + + vm.expectRevert(Errors.RoyaltyPolicyLS__InvalidMinRoyalty.selector); + royaltyModule.setRoyaltyPolicy(ipAccount2, address(royaltyPolicyLS), parentIpIds2, data2); + } + + function test_RoyaltyPolicyLS_revert_ZeroMinRoyalty() public { + // set root parent royalty policy + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + // set derivative royalty policy + address[] memory parentIpIds2 = new address[](1); + parentIpIds2[0] = ipAccount1; + uint32 minRoyaltyIpAccount2 = 0; + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + + vm.expectRevert(Errors.RoyaltyPolicyLS__ZeroMinRoyalty.selector); + royaltyModule.setRoyaltyPolicy(ipAccount2, address(royaltyPolicyLS), parentIpIds2, data2); + } + + function test_RoyaltyPolicyLS_revert_InvalidRoyaltyStack() public { + address[] memory parentIpIds = new address[](0); + uint32 minRoyaltyIpAccount3 = 1010; // 100.1% + bytes memory data = abi.encode(minRoyaltyIpAccount3); + + vm.expectRevert(Errors.RoyaltyPolicyLS__InvalidRoyaltyStack.selector); + royaltyModule.setRoyaltyPolicy(ipAccount3, address(royaltyPolicyLS), parentIpIds, data); + } + + function test_RoyaltyPolicyLS_initPolicy_rootIPA() public { + address[] memory parentIpIds = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; + bytes memory data = abi.encode(minRoyaltyIpAccount1); + + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds, data); + + (address splitClone, address claimer, uint32 royaltyStack, uint32 minRoyalty) = royaltyPolicyLS.royaltyData(ipAccount1); + + assertFalse(splitClone == address(0)); + assertEq(claimer, address(royaltyPolicyLS)); + assertEq(royaltyStack, minRoyaltyIpAccount1); + assertEq(minRoyalty, minRoyaltyIpAccount1); + } + + function test_RoyaltyPolicyLS_initPolicy_derivativeIPA() public { + // set root parent royalty policy + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + // set derivative royalty policy + address[] memory parentIpIds2 = new address[](1); + parentIpIds2[0] = ipAccount1; + uint32 minRoyaltyIpAccount2 = 200; + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + royaltyModule.setRoyaltyPolicy(ipAccount2, address(royaltyPolicyLS), parentIpIds2, data2); + + (address splitClone, address claimer, uint32 royaltyStack, uint32 minRoyalty) = royaltyPolicyLS.royaltyData(ipAccount2); + + assertFalse(splitClone == address(0)); + assertFalse(claimer == address(royaltyPolicyLS)); + assertFalse(claimer == address(0)); + assertEq(royaltyStack, minRoyaltyIpAccount1 + minRoyaltyIpAccount2); + assertEq(minRoyalty, minRoyaltyIpAccount2); + } + + function test_RoyaltyPolicyLS_distributeFunds() public { + // set root parent royalty policy + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + // set derivative royalty policy + address[] memory parentIpIds2 = new address[](1); + parentIpIds2[0] = ipAccount1; + uint32 minRoyaltyIpAccount2 = 200; + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + royaltyModule.setRoyaltyPolicy(ipAccount2, address(royaltyPolicyLS), parentIpIds2, data2); + (address splitClone2, address claimer2,,) = royaltyPolicyLS.royaltyData(ipAccount2); + + // send USDC to 0xSplitClone + vm.startPrank(USDC_RICH); + uint256 royaltyAmount = 1000 * 10 ** 6; + IERC20(USDC).transfer(splitClone2, royaltyAmount); + vm.stopPrank(); + + address[] memory accounts = new address[](2); + accounts[1] = ipAccount2; + accounts[0] = claimer2; + + uint256 splitClone2USDCBalBefore = IERC20(USDC).balanceOf(splitClone2); + uint256 splitMainUSDCBalBefore = IERC20(USDC).balanceOf(royaltyPolicyLS.LIQUID_SPLIT_MAIN()); + + royaltyPolicyLS.distributeFunds(ipAccount2, USDC, accounts, address(0)); + + uint256 splitClone2USDCBalAfter = IERC20(USDC).balanceOf(splitClone2); + uint256 splitMainUSDCBalAfter = IERC20(USDC).balanceOf(royaltyPolicyLS.LIQUID_SPLIT_MAIN()); + + assertApproxEqRel(splitClone2USDCBalBefore - splitClone2USDCBalAfter, royaltyAmount, 0.0001e18); + assertApproxEqRel(splitMainUSDCBalAfter - splitMainUSDCBalBefore, royaltyAmount, 0.0001e18); + } + + function test_RoyaltyPolicyLS_claimRoyalties() public{ + // set root parent royalty policy + address[] memory parentIpIds1 = new address[](0); + uint32 minRoyaltyIpAccount1 = 100; + bytes memory data1 = abi.encode(minRoyaltyIpAccount1); + royaltyModule.setRoyaltyPolicy(ipAccount1, address(royaltyPolicyLS), parentIpIds1, data1); + + // set derivative royalty policy + address[] memory parentIpIds2 = new address[](1); + parentIpIds2[0] = ipAccount1; + uint32 minRoyaltyIpAccount2 = 200; + bytes memory data2 = abi.encode(minRoyaltyIpAccount2); + royaltyModule.setRoyaltyPolicy(ipAccount2, address(royaltyPolicyLS), parentIpIds2, data2); + (address splitClone2, address claimer2,,) = royaltyPolicyLS.royaltyData(ipAccount2); + + // send USDC to 0xSplitClone + vm.startPrank(USDC_RICH); + uint256 royaltyAmount = 1000 * 10 ** 6; + IERC20(USDC).transfer(splitClone2, royaltyAmount); + vm.stopPrank(); + + address[] memory accounts = new address[](2); + accounts[1] = ipAccount2; + accounts[0] = claimer2; + + ERC20[] memory tokens = new ERC20[](1); + tokens[0] = ERC20(USDC); + + royaltyPolicyLS.distributeFunds(ipAccount2, USDC, accounts, address(0)); + + royaltyPolicyLS.claimRoyalties(ipAccount2, 0, tokens); + } +} \ No newline at end of file diff --git a/test/utils/DeployHelper.sol b/test/utils/DeployHelper.sol index 04a2bd63e..1c4dbfc98 100644 --- a/test/utils/DeployHelper.sol +++ b/test/utils/DeployHelper.sol @@ -16,7 +16,6 @@ contract DeployHelper is Test { ArbitrationPolicySP public arbitrationPolicySP; RoyaltyModule public royaltyModule; RoyaltyPolicyLS public royaltyPolicyLS; - LSClaimer public lsClaimer; uint256 public constant ARBITRATION_PRICE = 1000 * 10 ** 6; // 1000 USDC @@ -35,17 +34,17 @@ contract DeployHelper is Test { disputeModule = new DisputeModule(); arbitrationPolicySP = new ArbitrationPolicySP(address(disputeModule), USDC, ARBITRATION_PRICE); royaltyModule = new RoyaltyModule(); - royaltyPolicyLS = new RoyaltyPolicyLS(address(royaltyModule), LIQUID_SPLIT_FACTORY, LIQUID_SPLIT_MAIN); + royaltyPolicyLS = new RoyaltyPolicyLS(address(royaltyModule), address(1), LIQUID_SPLIT_FACTORY, LIQUID_SPLIT_MAIN); // if code at USDC is zero, then deploy ERC20 to that address // and also deploy other RoyaltyModule dependencies - if (USDC.code.length == 0) { + /* if (USDC.code.length == 0) { bytes memory code = vm.getDeployedCode("MockUSDC.sol:MockUSDC"); vm.etch(USDC, code); vm.label(USDC, "USDC"); // assertEq(USDC.code, code); MockUSDC(USDC).mint(USDC_RICH, 100_000_000 ether); - } + } */ vm.label(address(disputeModule), "disputeModule"); vm.label(address(arbitrationPolicySP), "arbitrationPolicySP");