From b90a3e7e64793b4f7851c0274e5423892ebdf58e Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Wed, 11 Jun 2025 14:51:56 +0530 Subject: [PATCH 01/11] fix: new audit fixes 1 --- src/modules/logicModule/LM_PC_FundingPot_v1.sol | 12 ++++-------- .../logicModule/interfaces/ILM_PC_FundingPot_v1.sol | 4 ++-- .../modules/logicModule/LM_PC_FundingPot_v1.t.sol | 4 ++-- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index 1d1bd3369..c18b7613c 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -305,10 +305,6 @@ contract LM_PC_FundingPot_v1 is view returns (bool isEligible, uint remainingAmountAllowedToContribute) { - if (accessCriteriaId_ > MAX_ACCESS_CRITERIA_TYPE) { - revert Module__LM_PC_FundingPot__InvalidAccessCriteriaId(); - } - Round storage round = rounds[roundId_]; if (round.roundEnd == 0 && round.roundCap == 0) { @@ -472,7 +468,7 @@ contract LM_PC_FundingPot_v1 is Round storage round = rounds[roundId_]; if (accessCriteriaType_ > MAX_ACCESS_CRITERIA_TYPE) { - revert Module__LM_PC_FundingPot__InvalidAccessCriteriaId(); + revert Module__LM_PC_FundingPot__InvalidAccessCriteriaType(); } _validateEditRoundParameters(round); @@ -494,7 +490,7 @@ contract LM_PC_FundingPot_v1 is round.accessCriterias[criteriaId].accessCriteriaType == AccessCriteriaType.UNSET ) { - revert Module__LM_PC_FundingPot__InvalidAccessCriteriaId(); + revert Module__LM_PC_FundingPot__InvalidAccessCriteriaType(); } } @@ -562,7 +558,7 @@ contract LM_PC_FundingPot_v1 is round.accessCriterias[accessCriteriaId_].accessCriteriaType == AccessCriteriaType.UNSET ) { - revert Module__LM_PC_FundingPot__InvalidAccessCriteriaId(); + revert Module__LM_PC_FundingPot__InvalidAccessCriteriaType(); } _validateEditRoundParameters(round); @@ -899,7 +895,7 @@ contract LM_PC_FundingPot_v1 is } if (accessCriteriaId_ > MAX_ACCESS_CRITERIA_TYPE) { - revert Module__LM_PC_FundingPot__InvalidAccessCriteriaId(); + revert Module__LM_PC_FundingPot__InvalidAccessCriteriaType(); } _validateAccessCriteria( diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index 915a61dfd..b4f3b0c75 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -259,8 +259,8 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Incorrect access criteria. error Module__LM_PC_FundingPot__MissingRequiredAccessCriteriaData(); - /// @notice Invalid access criteria ID. - error Module__LM_PC_FundingPot__InvalidAccessCriteriaId(); + /// @notice Invalid access criteria type. + error Module__LM_PC_FundingPot__InvalidAccessCriteriaType(); /// @notice Invalid times. error Module__LM_PC_FundingPot__InvalidTimes(); diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 782714af7..30e7fd79b 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -935,7 +935,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__InvalidAccessCriteriaId + .Module__LM_PC_FundingPot__InvalidAccessCriteriaType .selector ) ); @@ -4925,7 +4925,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__InvalidAccessCriteriaId + .Module__LM_PC_FundingPot__InvalidAccessCriteriaType .selector ) ); From 5d4e56a45541c9db3e0491f0f516ffdd4c9c87f1 Mon Sep 17 00:00:00 2001 From: JeffreyJoel Date: Wed, 11 Jun 2025 17:38:56 +0100 Subject: [PATCH 02/11] fix: new audit fixes 2 --- .../logicModule/LM_PC_FundingPot_v1.sol | 6 + .../interfaces/ILM_PC_FundingPot_v1.sol | 3 + .../logicModule/LM_PC_FundingPot_v1.t.sol | 131 +++++++++++++++++- 3 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index c18b7613c..346e0da18 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -651,6 +651,12 @@ contract LM_PC_FundingPot_v1 is ); } + // Enforcement: Round IDs must be strictly before the current roundId_ + if (currentProcessingRoundId >= roundId_) { + revert + Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds(); + } + lastSeenRoundId = currentProcessingRoundId; // Update lastSeenRoundId before continuing // Skip if this round is before the global accumulation start round diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index b4f3b0c75..a89f3af08 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -320,6 +320,9 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Thrown when round IDs in UnspentPersonalRoundCap array are not strictly increasing. error Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotStrictlyIncreasing(); + /// @notice Unspent personal round cap references a round that is not previous to the current round. + error Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds(); + // ------------------------------------------------------------------------- // Public - Getters diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 30e7fd79b..25af3be73 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -1355,10 +1355,14 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { │ │ └── When the user contributes to the round │ │ └── Then the transaction should revert │ │ - │ └── Given a user has already contributed up to their personal cap - │ └── When the user attempts to contribute again - │ └── Then the transaction should revert - │ + │ ├── Given a user has already contributed up to their personal cap + │ │ └── When the user attempts to contribute again + │ │ └── Then the transaction should revert + │ │ + │ ├── Given the user tries to use unspent caps not from a previous round(i.e. using the current or a future round's ID) + │ │ └── When the user attempts to contribute + │ │ └── Then the transaction should revert + │ │ └── Given the round contribution cap is reached └── When the user attempts to contribute └── Then the transaction should revert @@ -1573,6 +1577,125 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); } + function testContributeToRoundFor_revertsGivenUnspentCapsIsNotFromPreviousRounds( + ) public { + RoundParams memory params1 = _defaultRoundParams; + params1.accumulationMode = ILM_PC_FundingPot_v1.AccumulationMode.All; + + fundingPot.createRound( + params1.roundStart, + params1.roundEnd, + params1.roundCap, + params1.hookContract, + params1.hookFunction, + params1.autoClosure, + params1.accumulationMode + ); + uint32 round1Id = fundingPot.getRoundCount(); + + uint8 accessCriteriaId = 1; + uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); + + ( + address nftContract, + bytes32 merkleRoot, + address[] memory allowedAddresses + ) = _helper_createAccessCriteria(accessType, round1Id); + + fundingPot.setAccessCriteria( + round1Id, accessType, 0, nftContract, merkleRoot, allowedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round1Id, accessCriteriaId, 500, false, 0, 0, 0 + ); + + mockNFTContract.mint(contributor1_); + + RoundParams memory params2 = _defaultRoundParams; + params2.roundStart = _defaultRoundParams.roundStart + 3 days; + params2.roundEnd = _defaultRoundParams.roundEnd + 3 days; + params2.accumulationMode = ILM_PC_FundingPot_v1.AccumulationMode.All; + + fundingPot.createRound( + params2.roundStart, + params2.roundEnd, + params2.roundCap, + params2.hookContract, + params2.hookFunction, + params2.autoClosure, + params2.accumulationMode + ); + uint32 round2Id = fundingPot.getRoundCount(); + + fundingPot.setAccessCriteria( + round2Id, accessType, 0, nftContract, merkleRoot, allowedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round2Id, accessCriteriaId, 400, false, 0, 0, 0 + ); + + vm.warp(params2.roundStart + 1); + + //Attempt to use current round's ID + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory + invalidUnspentCaps1 = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](1); + invalidUnspentCaps1[0] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round2Id, + accessCriteriaId: accessCriteriaId, + merkleProof: new bytes32[](0) + }); + + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 700); + + vm.expectRevert( + abi.encodeWithSelector( + ILM_PC_FundingPot_v1 + .Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds + .selector + ) + ); + fundingPot.contributeToRoundFor( + contributor1_, + round2Id, + 700, + accessCriteriaId, + new bytes32[](0), + invalidUnspentCaps1 + ); + + //Attempt to use future round's ID + uint32 round3Id = round2Id + 1; + + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory + invalidUnspentCaps2 = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](1); + invalidUnspentCaps2[0] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round3Id, + accessCriteriaId: accessCriteriaId, + merkleProof: new bytes32[](0) + }); + + vm.expectRevert( + abi.encodeWithSelector( + ILM_PC_FundingPot_v1 + .Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds + .selector + ) + ); + fundingPot.contributeToRoundFor( + contributor1_, + round2Id, + 700, + accessCriteriaId, + new bytes32[](0), + invalidUnspentCaps2 + ); + + vm.stopPrank(); + } + function testContributeToRoundFor_revertsGivenPreviousContributionExceedsPersonalCap( ) public { testCreateRound(); From f779c36c912c4f302c1ad26c8d45c7351eebeee3 Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Fri, 13 Jun 2025 11:27:37 +0530 Subject: [PATCH 03/11] fix: new audit fixes 3 --- .../logicModule/LM_PC_FundingPot_v1.sol | 10 +- .../interfaces/ILM_PC_FundingPot_v1.sol | 4 +- test/e2e/logicModule/FundingPotE2E.t.sol | 8 +- .../logicModule/LM_PC_FundingPot_v1.t.sol | 558 +++++++++++++++--- 4 files changed, 500 insertions(+), 80 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index 346e0da18..e32d5ccec 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -463,7 +463,8 @@ contract LM_PC_FundingPot_v1 is uint8 accessCriteriaId_, // Optional: 0 for new, non-zero for edit address nftContract_, bytes32 merkleRoot_, - address[] calldata allowedAddresses_ + address[] calldata allowedAddresses_, + address[] calldata removedAddresses_ ) external onlyModuleRole(FUNDING_POT_ADMIN_ROLE) { Round storage round = rounds[roundId_]; @@ -529,6 +530,13 @@ contract LM_PC_FundingPot_v1 is } else if (accessCriteriaType == AccessCriteriaType.MERKLE) { round.accessCriterias[criteriaId].merkleRoot = merkleRoot_; } else if (accessCriteriaType == AccessCriteriaType.LIST) { + // Remove the addresses from the allowed list if any + if (removedAddresses_.length > 0) { + for (uint i = 0; i < removedAddresses_.length; i++) { + round.accessCriterias[criteriaId].allowedAddresses[removedAddresses_[i]] + = false; + } + } // For LIST type, update the allowed addresses for (uint i = 0; i < allowedAddresses_.length; i++) { round.accessCriterias[criteriaId].allowedAddresses[allowedAddresses_[i]] diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index a89f3af08..5a5c6e2ee 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -492,13 +492,15 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @param nftContract_ Address of the NFT contract. /// @param merkleRoot_ Merkle root for the access criteria. /// @param allowedAddresses_ List of explicitly allowed addresses. + /// @param removedAddresses_ List of addresses to remove from the allowed list. function setAccessCriteria( uint32 roundId_, uint8 accessCriteriaType_, uint8 accessCriteriaId_, address nftContract_, bytes32 merkleRoot_, - address[] memory allowedAddresses_ + address[] memory allowedAddresses_, + address[] memory removedAddresses_ ) external; /// @notice Removes addresses from the allowed list for a specific access criteria. diff --git a/test/e2e/logicModule/FundingPotE2E.t.sol b/test/e2e/logicModule/FundingPotE2E.t.sol index 25ca300e0..38edb08b7 100644 --- a/test/e2e/logicModule/FundingPotE2E.t.sol +++ b/test/e2e/logicModule/FundingPotE2E.t.sol @@ -199,13 +199,16 @@ contract FundingPotE2E is E2ETest { allowedAddresses[0] = contributor1; allowedAddresses[1] = contributor2; + address[] memory removedAddresses = new address[](0); + fundingPot.setAccessCriteria( round1Id, uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.LIST), 0, address(0), bytes32(0), - allowedAddresses + allowedAddresses, + removedAddresses ); // Add access criteria to round 2 @@ -218,7 +221,8 @@ contract FundingPotE2E is E2ETest { 0, address(0), bytes32(0), - allowedAddresses + allowedAddresses, + removedAddresses ); // 5. Set access criteria privileges for the rounds diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 25af3be73..bdab724e8 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -81,6 +81,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ERC721Mock mockNFTContract = new ERC721Mock("NFT Mock", "NFT"); MockFailingHookContract failingHook = new MockFailingHookContract(); + address[] public removedAddresses; + // ------------------------------------------------------------------------- // Setup @@ -130,6 +132,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { true, ILM_PC_FundingPot_v1.AccumulationMode.All ); + + removedAddresses = new address[](0); } // ------------------------------------------------------------------------- @@ -812,7 +816,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { │ └── Then it should not revert └── Given all the valid parameters and access criteria is set └── When user attempts to edit access criteria - └── Then it should not revert + └── Then it should not revert */ function testFuzzSetAccessCriteria_revertsGivenUserDoesNotHaveFundingPotAdminRole( @@ -846,7 +850,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); vm.stopPrank(); } @@ -877,7 +882,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -911,7 +917,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -945,7 +952,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -977,7 +985,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -1009,7 +1018,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -1041,7 +1051,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -1064,7 +1075,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); ( @@ -1113,7 +1125,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 1, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } @@ -1147,7 +1160,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); address[] memory addressesToRemove = new address[](2); @@ -1172,6 +1191,76 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { assertTrue(otherAddressesHaveAccess); } + /* + ├── Given the round exists + | ├── Given an initial access criteria list with addresses [0x1, 0x2, 0x3] + │ │ └── When checking access for address 0x3 + │ │ └── Then access should be granted + │ │ + │ └── Given an update to the access criteria + │ ├── When adding new addresses [0x4, 0x5] + │ ├── And removing address [0x3] + │ │ └── Then access for address 0x3 should be revoked + │ └── And the final allowed list should contain [0x1, 0x2, 0x4, 0x5] + */ + function testRemoveAllowAddressesSetAccessCriteria() public { + testCreateRound(); + uint32 roundId = fundingPot.getRoundCount(); + + uint8 accessCriteriaId = 1; + uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.LIST); + ( + address nftContract, + bytes32 merkleRoot, + address[] memory allowedAddresses + ) = _helper_createAccessCriteria(accessType, roundId); + + allowedAddresses = new address[](3); + allowedAddresses[0] = address(0x1); + allowedAddresses[1] = address(0x2); + allowedAddresses[2] = address(0x3); + + fundingPot.setAccessCriteria( + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses + ); + + bool hasAccess = fundingPot.exposed_checkAccessCriteriaEligibility( + roundId, accessCriteriaId, new bytes32[](0), address(0x3) + ); + assertTrue(hasAccess); + //Admin wants to give access to two new users and removed one user + allowedAddresses = new address[](4); + allowedAddresses[0] = address(0x1); + allowedAddresses[1] = address(0x2); + allowedAddresses[2] = address(0x4); + allowedAddresses[3] = address(0x5); + + removedAddresses = new address[](1); + removedAddresses[0] = address(0x3); + + //Edit the AccessCriteria + fundingPot.setAccessCriteria( + roundId, + accessType, + 1, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses + ); + + hasAccess = fundingPot.exposed_checkAccessCriteriaEligibility( + roundId, accessCriteriaId, new bytes32[](0), address(0x3) + ); + assertFalse(hasAccess); + } + /* Test: setAccessCriteriaPrivileges() ├── Given user does not have FUNDING_POT_ADMIN_ROLE │ └── When user attempts to set access criteria privileges @@ -1213,7 +1302,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); vm.startPrank(user_); @@ -1258,7 +1348,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( @@ -1286,7 +1377,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ├── Given the access criteria does not exist │ └── When user attempts to get access criteria privileges │ └── Then it should return default values - + */ function testFuzzGetRoundAccessCriteriaPrivileges_returnsDefaultValuesGivenInvalidAccessCriteriaId( uint8 accessCriteriaEnum @@ -1384,7 +1475,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 500, false, 0, 0, 0 @@ -1426,7 +1523,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 500, false, 0, 0, 0 @@ -1507,7 +1610,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 500, false, 0, 0, 0 @@ -1550,7 +1659,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 500, false, 0, 0, 0 @@ -1603,7 +1718,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, round1Id); fundingPot.setAccessCriteria( - round1Id, accessType, 0, nftContract, merkleRoot, allowedAddresses + round1Id, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessCriteriaId, 500, false, 0, 0, 0 @@ -1628,7 +1749,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint32 round2Id = fundingPot.getRoundCount(); fundingPot.setAccessCriteria( - round2Id, accessType, 0, nftContract, merkleRoot, allowedAddresses + round2Id, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessCriteriaId, 400, false, 0, 0, 0 @@ -1712,7 +1839,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 500, false, 0, 0, 0 @@ -1764,7 +1897,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { │ └── Then the funds are transferred to the funding pot │ And the contribution is recorded │ - ├── Given the access criteria is MERKLE + ├── Given the access criteria is MERKLE │ And the user fulfills the access criteria │ └── When the user contributes to the round │ └── Then the funds are transferred to the funding pot @@ -1902,7 +2035,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -2050,7 +2189,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); uint personalCap = 200; @@ -2104,7 +2249,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, personalCap, false, 0, 0, 0 @@ -2174,7 +2325,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); // Set privileges with override capability @@ -2240,7 +2397,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( @@ -2266,7 +2424,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); // Set personal cap of 400 for round 2 @@ -2343,7 +2502,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { address[] memory allowedAddresses ) = _helper_createAccessCriteria(accessType, round1Id); fundingPot.setAccessCriteria( - round1Id, accessType, 0, nftContract, merkleRoot, allowedAddresses + round1Id, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessCriteriaId, 500, false, 0, 0, 0 @@ -2362,7 +2527,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); uint32 round2Id = fundingPot.getRoundCount(); fundingPot.setAccessCriteria( - round2Id, accessType, 0, nftContract, merkleRoot, allowedAddresses + round2Id, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessCriteriaId, 500, false, 0, 0, 0 @@ -2452,7 +2623,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round1Id, 1, 0, address(0), bytes32(0), new address[](0) + round1Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); // Open access fundingPot.setAccessCriteriaPrivileges( round1Id, 1, r1PersonalCap, false, 0, 0, 0 @@ -2469,7 +2646,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round2Id, 1, 0, address(0), bytes32(0), new address[](0) + round2Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, 1, r2PersonalCap, false, 0, 0, 0 @@ -2486,7 +2669,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round3Id, 1, 0, address(0), bytes32(0), new address[](0) + round3Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round3Id, 1, r3BasePersonalCap, false, 0, 0, 0 @@ -2579,7 +2768,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round1Id, 1, 0, address(0), bytes32(0), new address[](0) + round1Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); // Open access fundingPot.setAccessCriteriaPrivileges( round1Id, 1, r1BaseCap, false, 0, 0, 0 @@ -2596,7 +2791,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round2Id, 1, 0, address(0), bytes32(0), new address[](0) + round2Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, 1, r2BaseCap, false, 0, 0, 0 @@ -2613,7 +2814,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round3Id, 1, 0, address(0), bytes32(0), new address[](0) + round3Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round3Id, 1, r3BaseCap + r2Contribution, false, 0, 0, 0 @@ -2696,7 +2903,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1PersonalCapC1, false, 0, 0, 0 @@ -2713,7 +2926,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, r2BasePersonalCapC1, false, 0, 0, 0 @@ -2815,7 +3034,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1PersonalCap, false, 0, 0, 0 @@ -2845,7 +3070,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); // Set personal cap for R2 to be at least the expected effective total cap uint r2ExpectedEffectiveTotalCap = r2BaseCap + r1UnusedTotal; // 500 + 400 = 900 @@ -2945,7 +3176,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1PersonalCapC1, false, 0, 0, 0 @@ -2974,7 +3211,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Disabled ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, r2BasePersonalCapC1, false, 0, 0, 0 @@ -3060,7 +3303,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1PersonalCapC1, false, 0, 0, 0 @@ -3089,7 +3338,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, r2BasePersonalCapC1, false, 0, 0, 0 @@ -3179,7 +3434,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round1Id, 1, 0, address(0), bytes32(0), new address[](0) + round1Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, 1, r1PersonalCapC1, false, 0, 0, 0 @@ -3208,7 +3469,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round2Id, 1, 0, address(0), bytes32(0), new address[](0) + round2Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, 1, r2PersonalCapC1, false, 0, 0, 0 @@ -3237,7 +3504,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round3Id, 1, 0, address(0), bytes32(0), new address[](0) + round3Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round3Id, 1, r3BasePersonalCapC1, false, 0, 0, 0 @@ -3348,7 +3621,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round1Id, 1, 0, address(0), bytes32(0), new address[](0) + round1Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, 1, r1BaseCap, false, 0, 0, 0 @@ -3376,7 +3655,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Total ); fundingPot.setAccessCriteria( - round2Id, 1, 0, address(0), bytes32(0), new address[](0) + round2Id, + 1, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, 1, r2BaseCap, false, 0, 0, 0 @@ -3408,8 +3693,9 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { (address nftR3, bytes32 merkleR3, address[] memory allowedR3) = _helper_createAccessCriteria(1, round3Id); - // TODO - fundingPot.setAccessCriteria(round3Id, 1, 0, nftR3, merkleR3, allowedR3); + fundingPot.setAccessCriteria( + round3Id, 1, 0, nftR3, merkleR3, allowedR3, removedAddresses + ); fundingPot.setAccessCriteriaPrivileges( round3Id, 1, r3ExpectedEffectiveCap, false, 0, 0, 0 ); @@ -3478,7 +3764,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1PersonalCapC1, false, 0, 0, 0 @@ -3509,7 +3801,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, r2BasePersonalCapC1, false, 0, 0, 0 @@ -3589,7 +3887,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1C1PersonalCap, false, 0, 0, 0 @@ -3619,7 +3923,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); uint r2ExpectedEffectiveTotalCap = r2BaseTotalCap + r1UnusedTotal; fundingPot.setAccessCriteriaPrivileges( @@ -3690,7 +4000,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1PersonalCapC1, false, 0, 0, 0 @@ -3719,7 +4035,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, r2BasePersonalCapC1, false, 0, 0, 0 @@ -3800,7 +4122,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, r1C1PersonalCap, false, 0, 0, 0 @@ -3829,7 +4157,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.All ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, r2BaseTotalCap, false, 0, 0, 0 @@ -3890,7 +4224,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round1Id, accessId, 0, address(0), bytes32(0), new address[](0) + round1Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round1Id, accessId, personalCap, false, 0, 0, 0 @@ -3907,7 +4247,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round2Id, accessId, 0, address(0), bytes32(0), new address[](0) + round2Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round2Id, accessId, personalCap, false, 0, 0, 0 @@ -3924,7 +4270,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ILM_PC_FundingPot_v1.AccumulationMode.Personal ); fundingPot.setAccessCriteria( - round3Id, accessId, 0, address(0), bytes32(0), new address[](0) + round3Id, + accessId, + 0, + address(0), + bytes32(0), + new address[](0), + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( round3Id, accessId, personalCap, false, 0, 0, 0 @@ -4044,7 +4396,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, // accessCriteriaId (0 for new) nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); // Set a personal cap of 500 for round 1 @@ -4082,7 +4435,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, // accessCriteriaId (0 for new) nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); // Set a personal cap of 400 for round 2 @@ -4215,7 +4569,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, // accessCriteriaId (0 for new) nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); // Set a personal cap of 800 for round 1 @@ -4252,7 +4607,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, // accessCriteriaId (0 for new) nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); // Set a personal cap of 300 for round 2 @@ -4515,7 +4871,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges(roundId, 0, 1000, false, 0, 0, 0); @@ -4590,7 +4947,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -4629,7 +4992,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -4673,7 +5042,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -4714,7 +5089,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( @@ -4752,7 +5133,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -5091,7 +5478,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { address[] memory allowedAddresses ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -5180,7 +5573,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { address[] memory allowedAddresses ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, @@ -5255,7 +5654,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(accessType, roundId); fundingPot.setAccessCriteria( - roundId, accessType, 0, nftContract, merkleRoot, allowedAddresses + roundId, + accessType, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses ); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 @@ -5445,7 +5850,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { 0, nftContract, merkleRoot, - allowedAddresses + allowedAddresses, + removedAddresses ); } } From 0fbdacca101ba05134796e6181c4b7f340923362 Mon Sep 17 00:00:00 2001 From: JeffreyJoel Date: Mon, 16 Jun 2025 14:38:52 +0100 Subject: [PATCH 04/11] fix: audit fixes 4 --- .../logicModule/LM_PC_FundingPot_v1.sol | 155 ++++++---- .../interfaces/ILM_PC_FundingPot_v1.sol | 7 +- .../logicModule/LM_PC_FundingPot_v1.t.sol | 290 ++++++++++++++++++ 3 files changed, 387 insertions(+), 65 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index e32d5ccec..722cd9dee 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -626,7 +626,7 @@ contract LM_PC_FundingPot_v1 is uint32 roundId_, uint amount_, uint8 accessCriteriaId_, - bytes32[] calldata merkleProof_ + bytes32[] memory merkleProof_ ) external { // Call the internal function with no additional unspent personal cap _contributeToRoundFor( @@ -643,68 +643,9 @@ contract LM_PC_FundingPot_v1 is bytes32[] memory merkleProof_, UnspentPersonalRoundCap[] calldata unspentPersonalRoundCaps_ ) external { - uint unspentPersonalCap = 0; // Initialize to 0 - uint32 lastSeenRoundId = 0; // Tracks the last seen roundId to ensure strictly increasing order - - // Process each previous round cap that the user wants to carry over - for (uint i = 0; i < unspentPersonalRoundCaps_.length; i++) { - UnspentPersonalRoundCap memory roundCapInfo = - unspentPersonalRoundCaps_[i]; - uint32 currentProcessingRoundId = roundCapInfo.roundId; - - // Enforcement: Round IDs in the array must be strictly increasing. - if (currentProcessingRoundId <= lastSeenRoundId) { - revert - Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotStrictlyIncreasing( - ); - } - - // Enforcement: Round IDs must be strictly before the current roundId_ - if (currentProcessingRoundId >= roundId_) { - revert - Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds(); - } - - lastSeenRoundId = currentProcessingRoundId; // Update lastSeenRoundId before continuing - - // Skip if this round is before the global accumulation start round - if (currentProcessingRoundId < globalAccumulationStartRoundId) { - continue; - } - - // For PERSONAL cap rollover, the PREVIOUS round must have allowed it (Personal or All). - if ( - rounds[currentProcessingRoundId].accumulationMode - != AccumulationMode.Personal - && rounds[currentProcessingRoundId].accumulationMode - != AccumulationMode.All - ) { - continue; - } - - if ( - _checkAccessCriteriaEligibility( - currentProcessingRoundId, - roundCapInfo.accessCriteriaId, - roundCapInfo.merkleProof, - user_ - ) - ) { - AccessCriteriaPrivileges storage privileges = - roundIdToAccessCriteriaIdToPrivileges[currentProcessingRoundId][roundCapInfo - .accessCriteriaId]; - - uint userContribution = - roundIdToUserToContribution[currentProcessingRoundId][user_]; - uint personalCap = privileges.personalCap; - uint unspentForThisEntry = 0; - - if (userContribution < personalCap) { - unspentForThisEntry = personalCap - userContribution; - } - unspentPersonalCap += unspentForThisEntry; - } - } + uint unspentPersonalCap = _calculateUnspentPersonalCap( + user_, roundId_, unspentPersonalRoundCaps_ + ); _contributeToRoundFor( user_, @@ -817,6 +758,94 @@ contract LM_PC_FundingPot_v1 is // ------------------------------------------------------------------------- // Internal + /// @notice Calculates the unspent personal capacity from previous rounds. + /// @param user_ The user address to calculate unspent capacity for. + /// @param roundId_ The current round ID. + /// @param unspentPersonalRoundCaps_ Array of previous rounds and access criteria to calculate unused capacity from. + /// @return unspentPersonalCap The amount of unspent personal capacity that can be used. + function _calculateUnspentPersonalCap( + address user_, + uint32 roundId_, + UnspentPersonalRoundCap[] calldata unspentPersonalRoundCaps_ + ) internal view returns (uint unspentPersonalCap) { + if (unspentPersonalRoundCaps_.length == 0) { + return 0; + } + + uint totalAggregatedPersonalCap = 0; + uint totalSpentInPastRounds = 0; + uint32 firstRoundId = unspentPersonalRoundCaps_[0].roundId; + uint32 lastSeenRoundId = 0; + // Enforcement: All rounds from the start of the array to the end must be contiguous. + for (uint i = 0; i < unspentPersonalRoundCaps_.length; i++) { + UnspentPersonalRoundCap memory roundCapInfo = + unspentPersonalRoundCaps_[i]; + uint32 currentProcessingRoundId = roundCapInfo.roundId; + + // Check for strictly increasing first (order matters) + if (currentProcessingRoundId <= lastSeenRoundId) { + revert + Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotStrictlyIncreasing( + ); + } + lastSeenRoundId = currentProcessingRoundId; + + // Check for contiguity (consecutive sequence) + if (currentProcessingRoundId != firstRoundId + i) { + revert + Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotContiguous(); + } + + // Enforcement: Round IDs must be strictly before the current roundId_ + if (currentProcessingRoundId >= roundId_) { + revert + Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds(); + } + + // For PERSONAL cap rollover, the PREVIOUS round must have allowed it (Personal or All). + if ( + rounds[currentProcessingRoundId].accumulationMode + != AccumulationMode.Personal + && rounds[currentProcessingRoundId].accumulationMode + != AccumulationMode.All + ) { + continue; + } + + // Skip if this round is before the global accumulation start round + if (currentProcessingRoundId < globalAccumulationStartRoundId) { + continue; + } + + // Only count spent amounts from rounds that meet the accumulation criteria + totalSpentInPastRounds += + roundIdToUserToContribution[currentProcessingRoundId][user_]; + + // Check eligibility for the past round + if ( + _checkAccessCriteriaEligibility( + currentProcessingRoundId, + roundCapInfo.accessCriteriaId, + roundCapInfo.merkleProof, + user_ + ) + ) { + AccessCriteriaPrivileges storage privileges = + roundIdToAccessCriteriaIdToPrivileges[currentProcessingRoundId][roundCapInfo + .accessCriteriaId]; + + totalAggregatedPersonalCap += privileges.personalCap; + } + } + + if (totalAggregatedPersonalCap > totalSpentInPastRounds) { + unspentPersonalCap = + totalAggregatedPersonalCap - totalSpentInPastRounds; + } + + return unspentPersonalCap; + } + /// @notice Validates the round parameters. /// @param round_ The round to validate. /// @dev Reverts if the round parameters are invalid. diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index 5a5c6e2ee..be786b8ef 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -247,7 +247,7 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Round has already started and cannot be modified. error Module__LM_PC_FundingPot__RoundAlreadyStarted(); - /// @notice Thrown when a hook contract is specified without a hook function. + /// @notice Thrown when a hook contract is specified with a hook function that has a non-empty implementation. error Module__LM_PC_FundingPot__HookFunctionRequiredWithHookContract(); /// @notice Thrown when a hook function is specified without a hook contract. @@ -320,9 +320,12 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Thrown when round IDs in UnspentPersonalRoundCap array are not strictly increasing. error Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotStrictlyIncreasing(); - /// @notice Unspent personal round cap references a round that is not previous to the current round. + /// @notice Unspent caps must be from previous rounds. error Module__LM_PC_FundingPot__UnspentCapsMustBeFromPreviousRounds(); + /// @notice The round IDs for unspent caps must be contiguous. + error Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotContiguous(); + // ------------------------------------------------------------------------- // Public - Getters diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index bdab724e8..db3c61b1a 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -1454,9 +1454,18 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { │ │ └── When the user attempts to contribute │ │ └── Then the transaction should revert │ │ + │ ├── Given the user tries to use unspent caps with round IDs that are not strictly increasing + │ │ └── When the user attempts to contribute + │ │ └── Then the transaction should revert + │ │ + │ ├── Given the user tries to use unspent caps with non-contiguous round IDs + │ │ └── When the user attempts to contribute + │ │ └── Then the transaction should revert + │ │ └── Given the round contribution cap is reached └── When the user attempts to contribute └── Then the transaction should revert + */ function testContributeToRoundFor_revertsGivenContributionIsBeforeRoundStart( @@ -1823,6 +1832,118 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); } + function testContributeToRoundFor_revertsGivenUnspentCapsWithNonContiguousRoundIds( + ) public { + // Setup: Create 3 rounds + uint8 accessCriteriaId = 1; + uint personalCap = 300; + + // Round 1 + uint32 round1Id = fundingPot.createRound( + block.timestamp + 1 days, + block.timestamp + 2 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.Personal + ); + _helper_setupAccessCriteriaForRound( + round1Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + // Round 2 + uint32 round2Id = fundingPot.createRound( + block.timestamp + 3 days, + block.timestamp + 4 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.Personal + ); + _helper_setupAccessCriteriaForRound( + round2Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + // Round 3 + uint32 round3Id = fundingPot.createRound( + block.timestamp + 5 days, + block.timestamp + 6 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.Personal + ); + _helper_setupAccessCriteriaForRound( + round3Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + // Round 4 (target) + uint32 round4Id = fundingPot.createRound( + block.timestamp + 7 days, + block.timestamp + 8 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.Personal + ); + _helper_setupAccessCriteriaForRound( + round4Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + vm.warp(block.timestamp + 7 days + 1 hours); // Enter Round 4 + + // Create non-contiguous unspent caps array (skipping round 2) + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory + nonContiguousUnspentCaps = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](2); + nonContiguousUnspentCaps[0] = ILM_PC_FundingPot_v1 + .UnspentPersonalRoundCap({ + roundId: round1Id, + accessCriteriaId: accessCriteriaId, + merkleProof: new bytes32[](0) + }); + nonContiguousUnspentCaps[1] = ILM_PC_FundingPot_v1 + .UnspentPersonalRoundCap({ + roundId: round3Id, // Skip round 2, making it non-contiguous + accessCriteriaId: accessCriteriaId, + merkleProof: new bytes32[](0) + }); + + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 500); + + vm.expectRevert( + ILM_PC_FundingPot_v1 + .Module__LM_PC_FundingPot__UnspentCapsRoundIdsNotContiguous + .selector + ); + fundingPot.contributeToRoundFor( + contributor1_, + round4Id, + 200, + accessCriteriaId, + new bytes32[](0), + nonContiguousUnspentCaps + ); + vm.stopPrank(); + } + function testContributeToRoundFor_revertsGivenPreviousContributionExceedsPersonalCap( ) public { testCreateRound(); @@ -1967,6 +2088,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { │ └── When calculating effective total cap │ └── Then unspent total capacity from all applicable previous rounds should expand the effective cap │ + └── Given the user has unspent caps from previous contiguous rounds + │ └── When the user attempts to contribute using valid unspent caps from previous rounds + │ └── Then the contribution should succeed + │ And the unspent caps should be applied to expand their effective personal cap + │ And the funds should be transferred to the funding pot + │ And the contribution should be recorded + │ ├── Given target round's AccumulationMode is Disabled │ └── When globalAccumulationStartRoundId is set to allow previous rounds │ └── Then no accumulation (personal or total) should occur for the target round @@ -3270,6 +3398,141 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); } + function testContributeToRoundFor_worksGivenUnspentCapsWithContiguousRoundIds( + ) public { + uint8 accessCriteriaId = 1; + uint personalCap = 300; + + // Round 1 - All accumulation enabled + uint32 round1Id = fundingPot.createRound( + block.timestamp + 1 days, + block.timestamp + 2 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.All + ); + _helper_setupAccessCriteriaForRound( + round1Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + // Round 2 - Personal accumulation enabled + uint32 round2Id = fundingPot.createRound( + block.timestamp + 3 days, + block.timestamp + 4 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.Personal + ); + _helper_setupAccessCriteriaForRound( + round2Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + // Round 3 - Target round with personal accumulation + uint32 round3Id = fundingPot.createRound( + block.timestamp + 5 days, + block.timestamp + 6 days, + 1000, + address(0), + bytes(""), + false, + ILM_PC_FundingPot_v1.AccumulationMode.Personal + ); + _helper_setupAccessCriteriaForRound( + round3Id, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + accessCriteriaId, + personalCap + ); + + // Contribute to previous rounds + vm.warp(block.timestamp + 1 days + 1 hours); // Enter Round 1 + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 1000); + + fundingPot.contributeToRoundFor( + contributor1_, + round1Id, + 100, // Contributed 100 out of 300 cap + accessCriteriaId, + new bytes32[](0) + ); + vm.stopPrank(); + + vm.warp(block.timestamp + 2 days); // Enter Round 2 (3 days total from start) + vm.startPrank(contributor1_); + fundingPot.contributeToRoundFor( + contributor1_, + round2Id, + 150, // Contributed 150 out of 300 cap + accessCriteriaId, + new bytes32[](0) + ); + vm.stopPrank(); + + // Now contribute to round 3 using unspent caps from previous rounds + vm.warp(block.timestamp + 2 days); // Enter Round 3 (5 days total from start) + + // Create unspent caps array for rounds 1 and 2 + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory unspentCaps = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](2); + unspentCaps[0] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round1Id, + accessCriteriaId: accessCriteriaId, + merkleProof: new bytes32[](0) + }); + unspentCaps[1] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round2Id, + accessCriteriaId: accessCriteriaId, + merkleProof: new bytes32[](0) + }); + + vm.startPrank(contributor1_); + + // Should be able to contribute more than the base personal cap + // Round 1: 300 cap - 100 spent = 200 unused + // Round 2: 300 cap - 150 spent = 150 unused + // Total unspent = 350 + // Round 3 base cap = 300 + // Total effective cap for round 3 = 300 + 350 = 650 + + uint initialBalance = _token.balanceOf(contributor1_); + + fundingPot.contributeToRoundFor( + contributor1_, + round3Id, + 500, // Should work because effective cap is 650 + accessCriteriaId, + new bytes32[](0), + unspentCaps + ); + + vm.stopPrank(); + + // Verify the contribution was recorded + assertEq( + fundingPot.getUserContributionToRound(round3Id, contributor1_), + 500, + "User contribution should be 500" + ); + + // Verify tokens were transferred + assertEq( + _token.balanceOf(contributor1_), + initialBalance - 500, + "Tokens should have been transferred from contributor" + ); + } + function testContributeToRoundFor_noAccumulationWhenGlobalStartEqualsTargetRound( ) public { // SCENARIO: If globalAccumulationStartRoundId is set to the target round's ID (R2), @@ -5854,4 +6117,31 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { removedAddresses ); } + + // Helper function to set up access criteria for an existing round + function _helper_setupAccessCriteriaForRound( + uint32 roundId_, + uint8 accessCriteriaEnum_, + uint8 accessCriteriaId_, + uint personalCap_ + ) internal { + ( + address nftContract, + bytes32 merkleRoot, + address[] memory allowedAddresses + ) = _helper_createAccessCriteria(accessCriteriaEnum_, roundId_); + + fundingPot.setAccessCriteria( + roundId_, + accessCriteriaEnum_, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + roundId_, accessCriteriaId_, personalCap_, false, 0, 0, 0 + ); + } } From 30ed78e6a0bddb4075454d2e0559432dcb29d6af Mon Sep 17 00:00:00 2001 From: JeffreyJoel Date: Mon, 16 Jun 2025 14:50:42 +0100 Subject: [PATCH 05/11] fix: new audit fixes 4 -remove unneccessary code --- .../interfaces/ILM_PC_FundingPot_v1.sol | 2 +- .../logicModule/LM_PC_FundingPot_v1.t.sol | 27 ------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index be786b8ef..52310465f 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -247,7 +247,7 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Round has already started and cannot be modified. error Module__LM_PC_FundingPot__RoundAlreadyStarted(); - /// @notice Thrown when a hook contract is specified with a hook function that has a non-empty implementation. + /// @notice Thrown when a hook contract is specified without a hook function. error Module__LM_PC_FundingPot__HookFunctionRequiredWithHookContract(); /// @notice Thrown when a hook function is specified without a hook contract. diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index db3c61b1a..60467e9e7 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -6117,31 +6117,4 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { removedAddresses ); } - - // Helper function to set up access criteria for an existing round - function _helper_setupAccessCriteriaForRound( - uint32 roundId_, - uint8 accessCriteriaEnum_, - uint8 accessCriteriaId_, - uint personalCap_ - ) internal { - ( - address nftContract, - bytes32 merkleRoot, - address[] memory allowedAddresses - ) = _helper_createAccessCriteria(accessCriteriaEnum_, roundId_); - - fundingPot.setAccessCriteria( - roundId_, - accessCriteriaEnum_, - 0, - nftContract, - merkleRoot, - allowedAddresses, - removedAddresses - ); - fundingPot.setAccessCriteriaPrivileges( - roundId_, accessCriteriaId_, personalCap_, false, 0, 0, 0 - ); - } } From 5a9b2974679879946dd31776241e3ae30b17be5d Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Tue, 17 Jun 2025 20:14:44 +0530 Subject: [PATCH 06/11] fix: new audit fixes 5 --- .../logicModule/LM_PC_FundingPot_v1.sol | 21 ++ .../logicModule/LM_PC_FundingPot_v1.t.sol | 257 ++++++++++++++++++ 2 files changed, 278 insertions(+) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index 722cd9dee..bd1d864c2 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -157,6 +157,10 @@ contract LM_PC_FundingPot_v1 is /// only previous rounds with roundId >= globalAccumulationStartRoundId will be included. uint32 internal globalAccumulationStartRoundId; + /// @notice Maps user addresses to a mapping of round IDs to a mapping of access criteria IDs to whether their unspent cap has been used + mapping(address => mapping(uint32 => mapping(uint8 => bool))) public + usedUnspentCaps; + /// @notice Storage gap for future upgrades. uint[50] private __gap; @@ -647,6 +651,16 @@ contract LM_PC_FundingPot_v1 is user_, roundId_, unspentPersonalRoundCaps_ ); + if (unspentPersonalCap > 0) { + // Mark the specific caps that were used in this contribution + for (uint i = 0; i < unspentPersonalRoundCaps_.length; i++) { + UnspentPersonalRoundCap memory roundCapInfo = + unspentPersonalRoundCaps_[i]; + usedUnspentCaps[user_][roundCapInfo.roundId][roundCapInfo + .accessCriteriaId] = true; + } + } + _contributeToRoundFor( user_, roundId_, @@ -812,6 +826,13 @@ contract LM_PC_FundingPot_v1 is continue; } + if ( + usedUnspentCaps[user_][currentProcessingRoundId][roundCapInfo + .accessCriteriaId] + ) { + continue; + } + // Skip if this round is before the global accumulation start round if (currentProcessingRoundId < globalAccumulationStartRoundId) { continue; diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 60467e9e7..8323c8915 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -5015,6 +5015,236 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); } + function testContributeToRoundFor_UsedUnspentCapsIsSet() public { + // Step 1: Create round 1 and round 2 + uint32 round1 = fundingPot.createRound({ + roundStart_: block.timestamp + 1, + roundEnd_: block.timestamp + 1 days, + roundCap_: 1000, + hookContract_: address(0), + hookFunction_: "", + autoClosure_: false, + accumulationMode_: ILM_PC_FundingPot_v1.AccumulationMode.Personal + }); + + uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); + + ( + address nftContract, + bytes32 merkleRoot, + address[] memory allowedAddresses + ) = _helper_createAccessCriteria(accessType, round1); + + fundingPot.setAccessCriteria( + round1, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + 0, + address(0), + 0, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round1, 1, 200, false, block.timestamp, 0, block.timestamp + 1 days + ); + + vm.warp(block.timestamp + 2); + + // Contribute in round 1 + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 100); + fundingPot.contributeToRoundFor( + contributor1_, round1, 100, 1, new bytes32[](0) + ); + vm.stopPrank(); + + // Step 2: Create round 2 with accumulationMode enabled + uint32 round2 = fundingPot.createRound({ + roundStart_: block.timestamp + 1, + roundEnd_: block.timestamp + 2 days, + roundCap_: 1000, + hookContract_: address(0), + hookFunction_: "", + autoClosure_: false, + accumulationMode_: ILM_PC_FundingPot_v1.AccumulationMode.Personal + }); + + fundingPot.setAccessCriteria( + round2, + uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN), + 0, + address(0), + 0, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round2, 1, 200, false, block.timestamp, 0, block.timestamp + 1 days + ); + + // Step 3: Contribute to round 2 using unspent cap from round 1 + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory caps = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](1); + + caps[0] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round1, + accessCriteriaId: 1, + merkleProof: new bytes32[](0) + }); + + vm.warp(block.timestamp + 2); + + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 100); + fundingPot.contributeToRoundFor( + contributor1_, round2, 100, 1, new bytes32[](0), caps + ); + vm.stopPrank(); + + // Step 4: Validate that usedUnspentCaps is set to true + bool isUsed = fundingPot.usedUnspentCaps(contributor1_, round1, 1); // expose via helper function if needed + assertTrue(isUsed, "usedUnspentCaps should be true after contribution"); + } + + function testContributeToRoundFor_UsedUnspentCapsSkippedIfAlreadyUsed() + public + { + // Step 1: Create round 1 and round 2 + uint32 round1 = fundingPot.createRound({ + roundStart_: block.timestamp + 1, + roundEnd_: block.timestamp + 1 days, + roundCap_: 1000, + hookContract_: address(0), + hookFunction_: "", + autoClosure_: false, + accumulationMode_: ILM_PC_FundingPot_v1.AccumulationMode.Personal + }); + + uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); + (address nftContract,, address[] memory allowedAddresses) = + _helper_createAccessCriteria(accessType, round1); + + fundingPot.setAccessCriteria( + round1, + accessType, + 0, + address(0), + 0, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round1, 1, 300, false, block.timestamp, 0, block.timestamp + 1 days + ); + + vm.warp(block.timestamp + 2); + + // Step 1b: Contribute in round 1 + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 100); + fundingPot.contributeToRoundFor( + contributor1_, round1, 100, 1, new bytes32[](0) + ); + vm.stopPrank(); + + // Step 2: Create round 2 + uint32 round2 = fundingPot.createRound({ + roundStart_: block.timestamp + 1, + roundEnd_: block.timestamp + 2 days, + roundCap_: 1000, + hookContract_: address(0), + hookFunction_: "", + autoClosure_: false, + accumulationMode_: ILM_PC_FundingPot_v1.AccumulationMode.Personal + }); + + fundingPot.setAccessCriteria( + round2, + accessType, + 0, + address(0), + 0, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round2, 1, 200, false, block.timestamp, 0, block.timestamp + 1 days + ); + + // Step 2b: Contribute using round1 cap → sets usedUnspentCaps + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory caps1 = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](1); + caps1[0] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round1, + accessCriteriaId: 1, + merkleProof: new bytes32[](0) + }); + + vm.warp(block.timestamp + 2); + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 200); + fundingPot.contributeToRoundFor( + contributor1_, round2, 200, 1, new bytes32[](0), caps1 + ); + vm.stopPrank(); + + // Step 3: Create round 3 + uint32 round3 = fundingPot.createRound({ + roundStart_: block.timestamp + 1, + roundEnd_: block.timestamp + 2 days, + roundCap_: 1000, + hookContract_: address(0), + hookFunction_: "", + autoClosure_: false, + accumulationMode_: ILM_PC_FundingPot_v1.AccumulationMode.Personal + }); + + fundingPot.setAccessCriteria( + round3, + accessType, + 0, + address(0), + 0, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + round3, 1, 300, false, block.timestamp, 0, block.timestamp + 1 days + ); + + // Step 4: Try reusing round1 cap again → should skip because it's already used + ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[] memory caps2 = + new ILM_PC_FundingPot_v1.UnspentPersonalRoundCap[](1); + caps2[0] = ILM_PC_FundingPot_v1.UnspentPersonalRoundCap({ + roundId: round1, + accessCriteriaId: 1, + merkleProof: new bytes32[](0) + }); + + vm.warp(block.timestamp + 2); + vm.startPrank(contributor1_); + _token.approve(address(fundingPot), 100); + fundingPot.contributeToRoundFor( + contributor1_, round3, 100, 1, new bytes32[](0), caps2 + ); + vm.stopPrank(); + + // Step 5: Check that contribution in round3 is only based on round3 cap (not reused from round1) + uint contributed = + fundingPot.getUserContributionToRound(round3, contributor1_); + assertLe( + contributed, + 300, + "Should not include unspent cap from already-used round" + ); + + // Confirm usedUnspentCaps[round1] is still true, not overwritten or reused + bool isStillUsed = fundingPot.usedUnspentCaps(contributor1_, round1, 1); + assertTrue( + isStillUsed, "usedUnspentCaps should still be true from earlier use" + ); + } + // ------------------------------------------------------------------------- // Test: closeRound() @@ -6117,4 +6347,31 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { removedAddresses ); } + + // Helper function to set up access criteria for an existing round + function _helper_setupAccessCriteriaForRound( + uint32 roundId_, + uint8 accessCriteriaEnum_, + uint8 accessCriteriaId_, + uint personalCap_ + ) internal { + ( + address nftContract, + bytes32 merkleRoot, + address[] memory allowedAddresses + ) = _helper_createAccessCriteria(accessCriteriaEnum_, roundId_); + + fundingPot.setAccessCriteria( + roundId_, + accessCriteriaEnum_, + 0, + nftContract, + merkleRoot, + allowedAddresses, + removedAddresses + ); + fundingPot.setAccessCriteriaPrivileges( + roundId_, accessCriteriaId_, personalCap_, false, 0, 0, 0 + ); + } } From 498b54a52f92f362a8f90b176275f50ebf830094 Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Wed, 18 Jun 2025 13:11:03 +0530 Subject: [PATCH 07/11] fix: new audit fixes 5: add getter function --- src/modules/logicModule/LM_PC_FundingPot_v1.sol | 10 +++++++++- .../interfaces/ILM_PC_FundingPot_v1.sol | 14 ++++++++++++++ .../modules/logicModule/LM_PC_FundingPot_v1.t.sol | 6 ++++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index bd1d864c2..0652f4d3f 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -158,7 +158,7 @@ contract LM_PC_FundingPot_v1 is uint32 internal globalAccumulationStartRoundId; /// @notice Maps user addresses to a mapping of round IDs to a mapping of access criteria IDs to whether their unspent cap has been used - mapping(address => mapping(uint32 => mapping(uint8 => bool))) public + mapping(address => mapping(uint32 => mapping(uint8 => bool))) private usedUnspentCaps; /// @notice Storage gap for future upgrades. @@ -377,6 +377,14 @@ contract LM_PC_FundingPot_v1 is return globalAccumulationStartRoundId; } + /// @inheritdoc ILM_PC_FundingPot_v1 + function getUserUsedUnspendCaps( + address user_, + uint32 roundId_, + uint8 accessCriteriaId_ + ) external view returns (bool) { + return usedUnspentCaps[user_][roundId_][accessCriteriaId_]; + } // ------------------------------------------------------------------------- // Public - Mutating diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index 52310465f..733553315 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -443,6 +443,20 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { view returns (uint32); + /// @notice Checks whether a user has already used their unspent caps from previous rounds for a specific round and access criteria combination. + /// @dev This function is used to prevent double-counting of unspent caps when users contribute to rounds + /// with accumulation enabled. It tracks whether the user has already utilized their carry-over capacity + /// from previous rounds for the specified round and access criteria. + /// @param user_ The address of the user to check. + /// @param roundId_ The ID of the round to check for unspent cap usage. + /// @param accessCriteriaId_ The ID of the access criteria to check for unspent cap usage. + /// @return True if the user has already used their unspent caps for this round and access criteria combination, false otherwise. + function getUserUsedUnspendCaps( + address user_, + uint32 roundId_, + uint8 accessCriteriaId_ + ) external view returns (bool); + // ------------------------------------------------------------------------- // Public - Mutating diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 8323c8915..ee73c5e14 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -5102,7 +5102,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); // Step 4: Validate that usedUnspentCaps is set to true - bool isUsed = fundingPot.usedUnspentCaps(contributor1_, round1, 1); // expose via helper function if needed + bool isUsed = + fundingPot.getUserUsedUnspendCaps(contributor1_, round1, 1); // expose via helper function if needed assertTrue(isUsed, "usedUnspentCaps should be true after contribution"); } @@ -5239,7 +5240,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Confirm usedUnspentCaps[round1] is still true, not overwritten or reused - bool isStillUsed = fundingPot.usedUnspentCaps(contributor1_, round1, 1); + bool isStillUsed = + fundingPot.getUserUsedUnspendCaps(contributor1_, round1, 1); assertTrue( isStillUsed, "usedUnspentCaps should still be true from earlier use" ); From ebd3a5c680b55dc32ac7c9c465ca7e9b66bd0def Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Thu, 19 Jun 2025 11:08:14 +0530 Subject: [PATCH 08/11] fix: contract size fix 1 --- .../logicModule/LM_PC_FundingPot_v1.sol | 23 ++---------- .../interfaces/ILM_PC_FundingPot_v1.sol | 35 +++---------------- .../logicModule/LM_PC_FundingPot_v1.t.sol | 12 +++---- 3 files changed, 14 insertions(+), 56 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index 0652f4d3f..22776a1ef 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -556,12 +556,7 @@ contract LM_PC_FundingPot_v1 is } } - // Emit the appropriate event based on whether this is a new setting or an edit - if (isEdit) { - emit AccessCriteriaEdited(roundId_, criteriaId); - } else { - emit AccessCriteriaSet(roundId_, criteriaId); - } + emit AccessUpdated(isEdit, roundId_, criteriaId); } // Update removeAllowlistedAddresses to match the new approach @@ -899,14 +894,12 @@ contract LM_PC_FundingPot_v1 is if ( round_.hookContract != address(0) && round_.hookFunction.length == 0 ) { - revert - Module__LM_PC_FundingPot__HookFunctionRequiredWithHookContract(); + revert Module__LM_PC_FundingPot__InvalidHookConfiguration(); } if (round_.hookContract == address(0) && round_.hookFunction.length > 0) { - revert - Module__LM_PC_FundingPot__HookContractRequiredWithHookFunction(); + revert Module__LM_PC_FundingPot__InvalidHookConfiguration(); } } @@ -1421,16 +1414,6 @@ contract LM_PC_FundingPot_v1 is }); _addPaymentOrder(paymentOrder); - - emit PaymentOrderCreated( - roundId_, - recipient_, - accessCriteriaId_, - tokensAmount_, - start, - cliff, - end - ); } function _buyBondingCurveToken(uint32 roundId_) internal { diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index 733553315..b17075aab 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -150,16 +150,12 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { AccumulationMode accumulationMode_ ); - /// @notice Emitted when access criteria is set for a round. - /// @param roundId_ The unique identifier of the round. - /// @param accessCriteriaId_ The identifier of the access criteria. - event AccessCriteriaSet(uint32 indexed roundId_, uint8 accessCriteriaId_); - /// @notice Emitted when access criteria is edited for a round. + /// @param isEdit_ represents new or edited setting /// @param roundId_ The unique identifier of the round. /// @param accessCriteriaId_ The identifier of the access criteria. - event AccessCriteriaEdited( - uint32 indexed roundId_, uint8 accessCriteriaId_ + event AccessUpdated( + bool isEdit_, uint32 indexed roundId_, uint8 accessCriteriaId_ ); /// @notice Emitted when access criteria privileges are set for a round. @@ -199,24 +195,6 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { uint32 roundId_, uint8 accessCriteriaId_, address[] addressesRemoved_ ); - /// @notice Emitted when a payment order is created. - /// @param roundId_ The ID of the round. - /// @param contributor_ The address of the contributor. - /// @param accessCriteriaId_ The ID of the access criteria. - /// @param tokensForThisAccessCriteria_ The amount of tokens contributed for this access criteria. - /// @param start_ The start timestamp for for when the linear vesting starts. - /// @param cliff_ The time in seconds from start time at which the unlock starts. - /// @param end_ The end timestamp for when the linear vesting ends. - event PaymentOrderCreated( - uint32 roundId_, - address contributor_, - uint8 accessCriteriaId_, - uint tokensForThisAccessCriteria_, - uint start_, - uint cliff_, - uint end_ - ); - /// @notice Emitted when a contributor batch is processed. /// @param roundId_ The ID of the round. /// @param startIndex_ The starting index in the contributors array. @@ -247,11 +225,8 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Round has already started and cannot be modified. error Module__LM_PC_FundingPot__RoundAlreadyStarted(); - /// @notice Thrown when a hook contract is specified without a hook function. - error Module__LM_PC_FundingPot__HookFunctionRequiredWithHookContract(); - - /// @notice Thrown when a hook function is specified without a hook contract. - error Module__LM_PC_FundingPot__HookContractRequiredWithHookFunction(); + /// @notice Error for invalid hook settings + error Module__LM_PC_FundingPot__InvalidHookConfiguration(); /// @notice Round does not exist. error Module__LM_PC_FundingPot__RoundNotCreated(); diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index ee73c5e14..8dfe88c91 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -301,7 +301,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__HookFunctionRequiredWithHookContract + .Module__LM_PC_FundingPot__InvalidHookConfiguration .selector ) ); @@ -325,7 +325,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__HookContractRequiredWithHookFunction + .Module__LM_PC_FundingPot__InvalidHookConfiguration .selector ) ); @@ -676,7 +676,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__HookFunctionRequiredWithHookContract + .Module__LM_PC_FundingPot__InvalidHookConfiguration .selector ) ); @@ -712,7 +712,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__HookContractRequiredWithHookFunction + .Module__LM_PC_FundingPot__InvalidHookConfiguration .selector ) ); @@ -1116,8 +1116,8 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) = _helper_createAccessCriteria(newAccessCriteriaEnum, roundId); vm.expectEmit(true, true, true, false); - emit ILM_PC_FundingPot_v1.AccessCriteriaEdited( - roundId, uint8(newAccessCriteriaEnum) + emit ILM_PC_FundingPot_v1.AccessUpdated( + true, roundId, uint8(newAccessCriteriaEnum) ); fundingPot.setAccessCriteria( roundId, From 4ec4dad5798de1e27ae4d908fa8e3984b68c9286 Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Thu, 19 Jun 2025 12:10:11 +0530 Subject: [PATCH 09/11] fix: contract size fix 2: remove getter functions and make public --- .../logicModule/LM_PC_FundingPot_v1.sol | 57 +--- .../interfaces/ILM_PC_FundingPot_v1.sol | 53 --- test/e2e/logicModule/FundingPotE2E.t.sol | 4 +- .../logicModule/LM_PC_FundingPot_v1.t.sol | 303 +++++++++--------- 4 files changed, 160 insertions(+), 257 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index 22776a1ef..432fe93c4 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -115,7 +115,7 @@ contract LM_PC_FundingPot_v1 is // State /// @notice The current round count. - uint32 private roundCount; + uint32 public roundCount; /// @notice Stores all funding rounds by their unique ID. mapping(uint32 => Round) private rounds; @@ -127,14 +127,14 @@ contract LM_PC_FundingPot_v1 is ) private roundIdToAccessCriteriaIdToPrivileges; /// @notice Maps round IDs to user addresses to contribution amounts. - mapping(uint32 => mapping(address => uint)) private + mapping(uint32 => mapping(address => uint)) public roundIdToUserToContribution; /// @notice Maps round IDs to total contributions. - mapping(uint32 => uint) private roundIdToTotalContributions; + mapping(uint32 => uint) public roundIdToTotalContributions; /// @notice Maps round IDs to closed status. - mapping(uint32 => bool) private roundIdToClosedStatus; + mapping(uint32 => bool) public roundIdToClosedStatus; /// @notice Maps round IDs to bonding curve tokens bought. mapping(uint32 => uint) private roundTokensBought; @@ -155,10 +155,10 @@ contract LM_PC_FundingPot_v1 is /// @notice The minimum round ID (inclusive, >= 1) to consider for accumulation calculations. /// @dev Defaults to 1. If a target round's mode allows accumulation, /// only previous rounds with roundId >= globalAccumulationStartRoundId will be included. - uint32 internal globalAccumulationStartRoundId; + uint32 public globalAccumulationStartRoundId; /// @notice Maps user addresses to a mapping of round IDs to a mapping of access criteria IDs to whether their unspent cap has been used - mapping(address => mapping(uint32 => mapping(uint8 => bool))) private + mapping(address => mapping(uint32 => mapping(uint8 => bool))) public usedUnspentCaps; /// @notice Storage gap for future upgrades. @@ -288,16 +288,6 @@ contract LM_PC_FundingPot_v1 is ); } - /// @inheritdoc ILM_PC_FundingPot_v1 - function getRoundCount() external view returns (uint32) { - return roundCount; - } - - /// @inheritdoc ILM_PC_FundingPot_v1 - function isRoundClosed(uint32 roundId_) external view returns (bool) { - return roundIdToClosedStatus[roundId_]; - } - /// @inheritdoc ILM_PC_FundingPot_v1 function getUserEligibility( uint32 roundId_, @@ -350,41 +340,6 @@ contract LM_PC_FundingPot_v1 is } } - /// @inheritdoc ILM_PC_FundingPot_v1 - function getTotalRoundContribution(uint32 roundId_) - external - view - returns (uint) - { - return roundIdToTotalContributions[roundId_]; - } - - /// @inheritdoc ILM_PC_FundingPot_v1 - function getUserContributionToRound(uint32 roundId_, address user_) - external - view - returns (uint) - { - return roundIdToUserToContribution[roundId_][user_]; - } - - /// @inheritdoc ILM_PC_FundingPot_v1 - function getGlobalAccumulationStartRoundId() - external - view - returns (uint32) - { - return globalAccumulationStartRoundId; - } - - /// @inheritdoc ILM_PC_FundingPot_v1 - function getUserUsedUnspendCaps( - address user_, - uint32 roundId_, - uint8 accessCriteriaId_ - ) external view returns (bool) { - return usedUnspentCaps[user_][roundId_][accessCriteriaId_]; - } // ------------------------------------------------------------------------- // Public - Mutating diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index b17075aab..81d0fac45 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -255,9 +255,6 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice User is not on the allowlist. error Module__LM_PC_FundingPot__AccessCriteriaListFailed(); - /// @notice Access not permitted. - error Module__LM_PC_FundingPot__AccessNotPermitted(); - /// @notice User has reached their personal contribution cap. error Module__LM_PC_FundingPot__PersonalCapReached(); @@ -365,15 +362,6 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { uint end_ ); - /// @notice Retrieves the total number of funding rounds. - /// @return roundCount_ The total number of funding rounds. - function getRoundCount() external view returns (uint32 roundCount_); - - /// @notice Retrieves the closed status of a round. - /// @param roundId_ The ID of the round. - /// @return The closed status of the round. - function isRoundClosed(uint32 roundId_) external view returns (bool); - /// @notice Gets eligibility information for a user in a specific round. /// @param roundId_ The ID of the round to check eligibility for. /// @param accessCriteriaId_ The ID of the access criteria to check eligibility for. @@ -391,47 +379,6 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { view returns (bool isEligible, uint remainingAmountAllowedToContribute); - /// @notice Retrieves the total contribution for a specific round. - /// @param roundId_ The ID of the round to check contributions for. - /// @return The total contributions for the specified round. - function getTotalRoundContribution(uint32 roundId_) - external - view - returns (uint); - - /// @notice Retrieves the contribution amount for a specific user in a round. - /// @param roundId_ The ID of the round to check contributions for. - /// @param user_ The address of the user. - /// @return The user's contribution amount for the specified round. - function getUserContributionToRound(uint32 roundId_, address user_) - external - view - returns (uint); - - /// @notice Retrieves the globally configured start round ID for accumulation calculations. - /// @dev Accumulation (both personal and total) will only consider previous rounds - /// with IDs greater than or equal to this value, provided the target round's - /// AccumulationMode allows it. Defaults to 1. - /// @return The first round ID (inclusive) to consider for accumulation. - function getGlobalAccumulationStartRoundId() - external - view - returns (uint32); - - /// @notice Checks whether a user has already used their unspent caps from previous rounds for a specific round and access criteria combination. - /// @dev This function is used to prevent double-counting of unspent caps when users contribute to rounds - /// with accumulation enabled. It tracks whether the user has already utilized their carry-over capacity - /// from previous rounds for the specified round and access criteria. - /// @param user_ The address of the user to check. - /// @param roundId_ The ID of the round to check for unspent cap usage. - /// @param accessCriteriaId_ The ID of the access criteria to check for unspent cap usage. - /// @return True if the user has already used their unspent caps for this round and access criteria combination, false otherwise. - function getUserUsedUnspendCaps( - address user_, - uint32 roundId_, - uint8 accessCriteriaId_ - ) external view returns (bool); - // ------------------------------------------------------------------------- // Public - Mutating diff --git a/test/e2e/logicModule/FundingPotE2E.t.sol b/test/e2e/logicModule/FundingPotE2E.t.sol index 38edb08b7..7f3d06e1a 100644 --- a/test/e2e/logicModule/FundingPotE2E.t.sol +++ b/test/e2e/logicModule/FundingPotE2E.t.sol @@ -285,8 +285,8 @@ contract FundingPotE2E is E2ETest { // 8. Close rounds fundingPot.closeRound(round1Id); - assertEq(fundingPot.isRoundClosed(round1Id), true); - assertEq(fundingPot.isRoundClosed(round2Id), true); // round2 is auto closed + assertEq(fundingPot.roundIdToClosedStatus(round1Id), true); + assertEq(fundingPot.roundIdToClosedStatus(round2Id), true); // round2 is auto closed assertEq(contributionToken.balanceOf(address(fundingPot)), 0); assertGt(issuanceToken.balanceOf(address(fundingPot)), 0); diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 8dfe88c91..060b9e836 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -359,7 +359,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { params.accumulationMode ); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); // Retrieve the stored parameters ( @@ -433,7 +433,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { { vm.assume(user_ != address(0) && user_ != address(this)); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); RoundParams memory params = RoundParams({ roundStart: block.timestamp + 3 days, @@ -469,7 +469,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testEditRound_revertsGivenRoundIsNotCreated() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); RoundParams memory params = RoundParams({ roundStart: block.timestamp + 3 days, @@ -502,7 +502,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testEditRound_revertsGivenRoundIsActive() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); RoundParams memory params; ( @@ -549,7 +549,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); _editedRoundParams; vm.assume(roundStart_ < block.timestamp); _editedRoundParams.roundStart = roundStart_; @@ -576,7 +576,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testEditRound_revertsGivenRoundEndTimeAndCapAreBothZero() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); RoundParams memory params = RoundParams({ roundStart: block.timestamp + 3 days, @@ -617,7 +617,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { && roundEnd_ < roundStart_ ); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); // Get the current round start time (uint currentRoundStart,,,,,,) = @@ -661,7 +661,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); RoundParams memory params = _helper_createEditRoundParams( block.timestamp + 3 days, @@ -697,7 +697,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); RoundParams memory params = _helper_createEditRoundParams( block.timestamp + 3 days, @@ -745,7 +745,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testEditRound() public { testCreateRound(); - uint32 lastRoundId = fundingPot.getRoundCount(); + uint32 lastRoundId = fundingPot.roundCount(); RoundParams memory params = _editedRoundParams; @@ -827,7 +827,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.assume(user_ != address(0) && user_ != address(this)); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -861,7 +861,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) public { vm.assume(accessCriteriaEnum >= 0 && accessCriteriaEnum <= 4); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -893,7 +893,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.assume(accessCriteriaEnum >= 0 && accessCriteriaEnum <= 4); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -928,7 +928,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.assume(accessCriteriaEnum > 4); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -963,7 +963,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -996,7 +996,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.MERKLE); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -1029,7 +1029,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.LIST); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, @@ -1060,7 +1060,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.assume(accessCriteriaEnum >= 0 && accessCriteriaEnum <= 4); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; ( @@ -1108,7 +1108,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { testFuzzSetAccessCriteria(oldAccessCriteriaEnum); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); ( address nftContract, bytes32 merkleRoot, @@ -1149,7 +1149,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { */ function testRemoveAllowlistedAddresses() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.LIST); @@ -1205,7 +1205,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { */ function testRemoveAllowAddressesSetAccessCriteria() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.LIST); @@ -1472,7 +1472,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); uint amount = 250; @@ -1519,7 +1519,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); @@ -1572,7 +1572,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); _helper_setupRoundWithAccessCriteria(accessType); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint amount = 250; @@ -1603,7 +1603,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.MERKLE); uint amount = 250; @@ -1656,7 +1656,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.LIST); uint amount = 250; @@ -1715,7 +1715,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { params1.autoClosure, params1.accumulationMode ); - uint32 round1Id = fundingPot.getRoundCount(); + uint32 round1Id = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); @@ -1755,7 +1755,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { params2.autoClosure, params2.accumulationMode ); - uint32 round2Id = fundingPot.getRoundCount(); + uint32 round2Id = fundingPot.roundCount(); fundingPot.setAccessCriteria( round2Id, @@ -1948,7 +1948,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); uint amount = 500; @@ -2153,7 +2153,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint amount = 250; ( @@ -2200,12 +2200,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { contributor1_, roundId, amount, accessCriteriaId, new bytes32[](0) ); - uint totalContributions = fundingPot.getTotalRoundContribution(roundId); + uint totalContributions = + fundingPot.roundIdToTotalContributions(roundId); assertEq(totalContributions, amount); uint personalContributions = - fundingPot.getUserContributionToRound(roundId, contributor1_); + fundingPot.roundIdToUserToContribution(roundId, contributor1_); assertEq(personalContributions, amount); } @@ -2221,7 +2222,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8 accessCriteriaId = 1; _helper_setupRoundWithAccessCriteria(accessCriteriaId); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); mockNFTContract.mint(contributor1_); @@ -2243,10 +2244,11 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); uint userContribution = - fundingPot.getUserContributionToRound(roundId, contributor1_); + fundingPot.roundIdToUserToContribution(roundId, contributor1_); assertEq(userContribution, 250); - uint totalContributions = fundingPot.getTotalRoundContribution(roundId); + uint totalContributions = + fundingPot.roundIdToTotalContributions(roundId); assertEq(totalContributions, 250); } @@ -2258,7 +2260,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _helper_setupRoundWithAccessCriteria(accessType); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); (,,,, bytes32[] memory proofB) = _helper_generateMerkleTreeForTwoLeaves( contributor1_, contributor2_, roundId @@ -2285,10 +2287,11 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); uint userContribution = - fundingPot.getUserContributionToRound(roundId, contributor2_); + fundingPot.roundIdToUserToContribution(roundId, contributor2_); assertEq(userContribution, contributionAmount); - uint totalContributions = fundingPot.getTotalRoundContribution(roundId); + uint totalContributions = + fundingPot.roundIdToTotalContributions(roundId); assertEq(totalContributions, contributionAmount); } @@ -2351,19 +2354,19 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); uint contribution = - fundingPot.getUserContributionToRound(roundId, contributor2_); + fundingPot.roundIdToUserToContribution(roundId, contributor2_); assertEq(contribution, 50); - uint totalContribution = fundingPot.getTotalRoundContribution(roundId); + uint totalContribution = fundingPot.roundIdToTotalContributions(roundId); assertEq(totalContribution, _defaultRoundParams.roundCap); - assertTrue(fundingPot.isRoundClosed(roundId)); + assertTrue(fundingPot.roundIdToClosedStatus(roundId)); } function testContributeToRoundFor_worksGivenContributionPartiallyExceedingPersonalCap( ) public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); @@ -2431,7 +2434,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); uint totalContribution = - fundingPot.getUserContributionToRound(roundId, contributor1_); + fundingPot.roundIdToUserToContribution(roundId, contributor1_); assertEq(totalContribution, personalCap); } @@ -2441,7 +2444,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); uint amount = 250; @@ -2490,7 +2493,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Verify the contribution was recorded - uint totalContribution = fundingPot.getTotalRoundContribution(roundId); + uint totalContribution = fundingPot.roundIdToTotalContributions(roundId); assertEq(totalContribution, amount); } @@ -2509,7 +2512,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _defaultRoundParams.accumulationMode ); - uint32 round1Id = fundingPot.getRoundCount(); + uint32 round1Id = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessCriteriaType = @@ -2544,7 +2547,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _defaultRoundParams.autoClosure, _defaultRoundParams.accumulationMode ); - uint32 round2Id = fundingPot.getRoundCount(); + uint32 round2Id = fundingPot.roundCount(); fundingPot.setAccessCriteria( round2Id, @@ -2595,11 +2598,11 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); assertEq( - fundingPot.getUserContributionToRound(round1Id, contributor1_), 200 + fundingPot.roundIdToUserToContribution(round1Id, contributor1_), 200 ); assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), 700 + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), 700 ); } @@ -2619,7 +2622,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _defaultRoundParams.autoClosure, _defaultRoundParams.accumulationMode ); - uint32 round1Id = fundingPot.getRoundCount(); + uint32 round1Id = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); @@ -2653,7 +2656,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _defaultRoundParams.autoClosure, _defaultRoundParams.accumulationMode ); - uint32 round2Id = fundingPot.getRoundCount(); + uint32 round2Id = fundingPot.roundCount(); fundingPot.setAccessCriteria( round2Id, accessType, @@ -2701,23 +2704,23 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); vm.stopPrank(); - assertEq(fundingPot.getTotalRoundContribution(round1Id), 500); + assertEq(fundingPot.roundIdToTotalContributions(round1Id), 500); assertEq( - fundingPot.getUserContributionToRound(round1Id, contributor1_), 300 + fundingPot.roundIdToUserToContribution(round1Id, contributor1_), 300 ); assertEq( - fundingPot.getUserContributionToRound(round1Id, contributor2_), 200 + fundingPot.roundIdToUserToContribution(round1Id, contributor2_), 200 ); - assertEq(fundingPot.getTotalRoundContribution(round2Id), 700); + assertEq(fundingPot.roundIdToTotalContributions(round2Id), 700); assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor2_), 400 + fundingPot.roundIdToUserToContribution(round2Id, contributor2_), 400 ); assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor3_), 300 + fundingPot.roundIdToUserToContribution(round2Id, contributor3_), 300 ); - assertEq(fundingPot.getTotalRoundContribution(round2Id), 700); + assertEq(fundingPot.roundIdToTotalContributions(round2Id), 700); } function testContributeToRoundFor_globalStartRestrictsPersonalAccumulation() @@ -2826,7 +2829,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Set Global Start --- fundingPot.setGlobalAccumulationStart(2); - assertEq(fundingPot.getGlobalAccumulationStartRoundId(), 2); + assertEq(fundingPot.globalAccumulationStartRoundId(), 2); // --- Attempt Contribution in Round 3 --- vm.warp(initialTimestamp + 5 days + 1 hours); // Enter Round 3 @@ -2858,7 +2861,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertion --- assertEq( - fundingPot.getUserContributionToRound(round3Id, contributor1_), + fundingPot.roundIdToUserToContribution(round3Id, contributor1_), expectedR3PersonalCap, "R3 personal contribution incorrect" ); @@ -2971,7 +2974,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Set Global Start --- fundingPot.setGlobalAccumulationStart(2); - assertEq(fundingPot.getGlobalAccumulationStartRoundId(), 2); + assertEq(fundingPot.globalAccumulationStartRoundId(), 2); // --- Attempt Contribution in Round 3 --- vm.warp(initialTimestamp + 5 days + 1 hours); // Enter Round 3 @@ -2987,12 +2990,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertion --- assertEq( - fundingPot.getTotalRoundContribution(round3Id), + fundingPot.roundIdToTotalContributions(round3Id), expectedR3EffectiveCap, "R3 total contribution incorrect, effective cap not as expected" ); assertEq( - fundingPot.getUserContributionToRound(round3Id, contributor1_), + fundingPot.roundIdToUserToContribution(round3Id, contributor1_), expectedR3EffectiveCap, "R3 user contribution incorrect" ); @@ -3003,7 +3006,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // SCENARIO: Default globalAccumulationStartRoundId = 1 allows accumulation from R1 for R2 (Personal mode) // 1. Setup: Round 1 (Personal), Round 2 (Personal). // Partial contribution by C1 in R1. - // 2. Action: Verify getGlobalAccumulationStartRoundId() == 1 (default). + // 2. Action: Verify globalAccumulationStartRoundId() == 1 (default). // 3. Verification: For C1's contribution to R2, unused personal capacity from R1 rolls over. uint initialTimestamp = block.timestamp; @@ -3080,7 +3083,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Verify Default Global Start Round ID --- assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Default global start round ID should be 1" ); @@ -3124,7 +3127,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertion --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), expectedC1ContributionR2, "R2 C1 personal contribution incorrect (should use R1 unused)" ); @@ -3214,7 +3217,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Verify Default Global Start Round ID --- assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Default global start round ID should be 1" ); @@ -3239,12 +3242,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), c1AttemptR2, "R2 C1 contribution incorrect" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), c1AttemptR2, "R2 Total contributions after C1 incorrect" ); @@ -3264,7 +3267,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { } assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), r2ExpectedEffectiveTotalCap, "R2 final total contributions should match effective total cap" ); @@ -3354,7 +3357,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Set Global Start Round ID to allow R1 (to show it's ignored by R2's Disabled mode) --- fundingPot.setGlobalAccumulationStart(1); assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Global start round ID should be 1" ); @@ -3383,17 +3386,17 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), r2BasePersonalCapC1, "R2 C1 personal contribution should be clamped by R2's base personal cap (Disabled mode)" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), r2BasePersonalCapC1, "R2 Total contributions should not be expanded by R1 (Disabled mode)" ); assertTrue( - fundingPot.getTotalRoundContribution(round2Id) <= r2BaseCap, + fundingPot.roundIdToTotalContributions(round2Id) <= r2BaseCap, "R2 Total contributions exceeded R2's original base cap (Disabled mode)" ); } @@ -3520,7 +3523,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Verify the contribution was recorded assertEq( - fundingPot.getUserContributionToRound(round3Id, contributor1_), + fundingPot.roundIdToUserToContribution(round3Id, contributor1_), 500, "User contribution should be 500" ); @@ -3616,7 +3619,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Set Global Start Round ID to be Round 2's ID --- fundingPot.setGlobalAccumulationStart(round2Id); assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), round2Id, "Global start round ID not set to R2 ID" ); @@ -3645,17 +3648,17 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), r2BasePersonalCapC1, "R2 C1 personal contribution should be clamped by R2's base personal cap (global start = R2)" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), r2BasePersonalCapC1, "R2 Total contributions should not be expanded by R1 (global start = R2)" ); assertTrue( - fundingPot.getTotalRoundContribution(round2Id) <= r2BaseCap, + fundingPot.roundIdToTotalContributions(round2Id) <= r2BaseCap, "R2 Total contributions exceeded R2's original base cap (global start = R2)" ); } @@ -3717,7 +3720,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); vm.stopPrank(); assertEq( - fundingPot.getUserContributionToRound(round1Id, contributor1_), + fundingPot.roundIdToUserToContribution(round1Id, contributor1_), r1ContributionC1 ); @@ -3752,7 +3755,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); vm.stopPrank(); assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), r2ContributionC1 ); @@ -3781,7 +3784,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Verify Global Start Round ID --- assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Default global start round ID should be 1" ); @@ -3817,12 +3820,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round3Id, contributor1_), + fundingPot.roundIdToUserToContribution(round3Id, contributor1_), expectedR3PersonalCapC1, "R3 C1 personal contribution incorrect (should use R1 & R2 unused)" ); assertEq( - fundingPot.getTotalRoundContribution(round3Id), + fundingPot.roundIdToTotalContributions(round3Id), expectedR3PersonalCapC1, "R3 total contributions incorrect after C1" ); @@ -3904,7 +3907,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); vm.stopPrank(); assertEq( - fundingPot.getTotalRoundContribution(round1Id), r1ContributionC1 + fundingPot.roundIdToTotalContributions(round1Id), r1ContributionC1 ); // --- Create Round 2 (Total Mode) --- @@ -3938,7 +3941,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); vm.stopPrank(); assertEq( - fundingPot.getTotalRoundContribution(round2Id), r2ContributionC2 + fundingPot.roundIdToTotalContributions(round2Id), r2ContributionC2 ); // --- Create Round 3 (Total Mode) --- @@ -3964,7 +3967,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Default global start round ID should be 1" ); @@ -3980,12 +3983,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getTotalRoundContribution(round3Id), + fundingPot.roundIdToTotalContributions(round3Id), r3ExpectedEffectiveCap, "R3 total contributions should match effective cap with rollover from R1 and R2" ); assertEq( - fundingPot.getUserContributionToRound(round3Id, contributor3_), + fundingPot.roundIdToUserToContribution(round3Id, contributor3_), r3ExpectedEffectiveCap, "R3 C3 contribution incorrect" ); @@ -4078,7 +4081,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Global Start ID Check --- assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Default global start ID is 1" ); @@ -4108,12 +4111,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), expectedEffectivePersonalCapC1R2, "R2 C1 personal contribution incorrect" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), expectedEffectivePersonalCapC1R2, "R2 Total contributions incorrect" ); @@ -4201,7 +4204,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Ensure Global Start Round ID is 1 --- assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), 1, "Global start round ID should be 1 by default" ); @@ -4219,12 +4222,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), c1AttemptR2, "R2 C1 contribution should match attempt (filling effective total cap)" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), r2ExpectedEffectiveTotalCap, "R2 Total contributions should match effective total cap (All mode, global_start=1)" ); @@ -4313,7 +4316,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Set Global Start Round ID to Round 2's ID --- fundingPot.setGlobalAccumulationStart(round2Id); assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), round2Id, "Global start ID not set to R2 ID" ); @@ -4342,12 +4345,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), r2BasePersonalCapC1, "R2 C1 personal contribution should be clamped by R2 base personal cap (All mode, global_start=R2)" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), r2BasePersonalCapC1, "R2 Total contributions should be C1's clamped amount (All mode, global_start=R2)" ); @@ -4435,7 +4438,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Set Global Start Round ID to Round 2's ID --- fundingPot.setGlobalAccumulationStart(round2Id); assertEq( - fundingPot.getGlobalAccumulationStartRoundId(), + fundingPot.globalAccumulationStartRoundId(), round2Id, "Global start ID not set to R2 ID" ); @@ -4453,12 +4456,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // --- Assertions --- assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), r2BaseTotalCap, "R2 C1 contribution should be clamped by R2 base total cap (All mode, global_start=R2)" ); assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), r2BaseTotalCap, "R2 Total contributions should be R2 base total cap (All mode, global_start=R2)" ); @@ -4621,7 +4624,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); vm.stopPrank(); assertEq( - fundingPot.getUserContributionToRound(round3Id, contributor1_), 100 + fundingPot.roundIdToUserToContribution(round3Id, contributor1_), 100 ); } @@ -4641,7 +4644,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _defaultRoundParams.autoClosure, _defaultRoundParams.accumulationMode ); - uint32 round1Id = fundingPot.getRoundCount(); + uint32 round1Id = fundingPot.roundCount(); // Set up access criteria for round 1 uint8 accessCriteriaId = 1; // Open access @@ -4689,7 +4692,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { params.autoClosure, params.accumulationMode ); - uint32 round2Id = fundingPot.getRoundCount(); + uint32 round2Id = fundingPot.roundCount(); // Set up access criteria for round 2 fundingPot.setAccessCriteria( @@ -4719,7 +4722,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Verify contribution to round 1 assertEq( - fundingPot.getUserContributionToRound(round1Id, contributor1_), 200 + fundingPot.roundIdToUserToContribution(round1Id, contributor1_), 200 ); // Move to round 2 @@ -4752,7 +4755,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Verify contributions to round 2 - should be more than the personal cap of round 2 (400) // This verifies personal caps DO accumulate uint contributionAmount = - fundingPot.getUserContributionToRound(round2Id, contributor1_); + fundingPot.roundIdToUserToContribution(round2Id, contributor1_); assertEq(contributionAmount, 450); assertTrue(contributionAmount > 400, "Personal cap should accumulate"); @@ -4769,12 +4772,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Verify contributor 2's contribution was clamped to the remaining 50. assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor2_), 50 + fundingPot.roundIdToUserToContribution(round2Id, contributor2_), 50 ); vm.stopPrank(); // Verify total contributions to round 2 is exactly the round cap (450 + 50 = 500). - assertEq(fundingPot.getTotalRoundContribution(round2Id), 500); + assertEq(fundingPot.roundIdToTotalContributions(round2Id), 500); // Additional contributor3 should not be able to contribute anything as the cap is full. // Attempting to contribute when the cap is already full should revert. @@ -4795,7 +4798,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); // Final check that total contributions remain at the round cap. - assertEq(fundingPot.getTotalRoundContribution(round2Id), 500); + assertEq(fundingPot.roundIdToTotalContributions(round2Id), 500); } function testContributeToRoundFor_totalModeOnlyAccumulatesTotalCaps() @@ -4814,7 +4817,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { _defaultRoundParams.autoClosure, _defaultRoundParams.accumulationMode ); - uint32 round1Id = fundingPot.getRoundCount(); + uint32 round1Id = fundingPot.roundCount(); // Set up access criteria for round 1 (Open) uint8 accessCriteriaId = 1; @@ -4861,7 +4864,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { params.autoClosure, params.accumulationMode ); - uint32 round2Id = fundingPot.getRoundCount(); + uint32 round2Id = fundingPot.roundCount(); // Set up access criteria for round 2 (Open) fundingPot.setAccessCriteria( @@ -4891,9 +4894,9 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Verify contribution to round 1 assertEq( - fundingPot.getUserContributionToRound(round1Id, contributor1_), 600 + fundingPot.roundIdToUserToContribution(round1Id, contributor1_), 600 ); - assertEq(fundingPot.getTotalRoundContribution(round1Id), 600); + assertEq(fundingPot.roundIdToTotalContributions(round1Id), 600); // Move to round 2 vm.warp(_defaultRoundParams.roundStart + 3 days + 1); @@ -4910,7 +4913,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Verify contributor 2's contribution was clamped by personal cap. assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor2_), + fundingPot.roundIdToUserToContribution(round2Id, contributor2_), 300, "C2 contribution should be clamped by personal cap" ); @@ -4918,7 +4921,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Verify total contributions after C2 is 300 assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), 300, "Total after C2 should be 300" ); @@ -4955,7 +4958,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Verify contributor 1's contribution was clamped to their R2 personal cap. assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor1_), + fundingPot.roundIdToUserToContribution(round2Id, contributor1_), 300, "C1 contribution should be clamped by personal cap" ); @@ -4963,7 +4966,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Verify total round contributions: 300 (C2) + 300 (C1) = 600 assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), 600, "Total after C1 and C2 should be 600" ); @@ -4977,7 +4980,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Verify C3 contributed 300 assertEq( - fundingPot.getUserContributionToRound(round2Id, contributor3_), + fundingPot.roundIdToUserToContribution(round2Id, contributor3_), 300, "C3 contributes remaining 300" ); @@ -4985,7 +4988,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Total contributions should now be 900 (300 + 300 + 300), matching the effective cap. assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), 900, "Total should match effective cap after C3" ); @@ -5009,7 +5012,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Final total check should remain 900 assertEq( - fundingPot.getTotalRoundContribution(round2Id), + fundingPot.roundIdToTotalContributions(round2Id), 900, "Final total should be effective cap" ); @@ -5102,8 +5105,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.stopPrank(); // Step 4: Validate that usedUnspentCaps is set to true - bool isUsed = - fundingPot.getUserUsedUnspendCaps(contributor1_, round1, 1); // expose via helper function if needed + bool isUsed = fundingPot.usedUnspentCaps(contributor1_, round1, 1); // expose via helper function if needed assertTrue(isUsed, "usedUnspentCaps should be true after contribution"); } @@ -5232,7 +5234,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { // Step 5: Check that contribution in round3 is only based on round3 cap (not reused from round1) uint contributed = - fundingPot.getUserContributionToRound(round3, contributor1_); + fundingPot.roundIdToUserToContribution(round3, contributor1_); assertLe( contributed, 300, @@ -5240,8 +5242,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ); // Confirm usedUnspentCaps[round1] is still true, not overwritten or reused - bool isStillUsed = - fundingPot.getUserUsedUnspendCaps(contributor1_, round1, 1); + bool isStillUsed = fundingPot.usedUnspentCaps(contributor1_, round1, 1); assertTrue( isStillUsed, "usedUnspentCaps should still be true from earlier use" ); @@ -5306,7 +5307,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.assume(user_ != address(0) && user_ != address(this)); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); vm.startPrank(user_); bytes32 roleId = _authorizer.generateRoleId( @@ -5326,7 +5327,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { ) public { vm.assume(accessCriteriaEnum >= 0 && accessCriteriaEnum <= 4); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); _helper_createAccessCriteria(accessCriteriaEnum, roundId); @@ -5387,7 +5388,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); _helper_setupRoundWithAccessCriteria(accessCriteriaId); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); fundingPot.setAccessCriteriaPrivileges(roundId, 0, 1000, false, 0, 0, 0); @@ -5404,7 +5405,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); _helper_setupRoundWithAccessCriteria(accessCriteriaId); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); fundingPot.setAccessCriteriaPrivileges( roundId, accessCriteriaId, 1000, false, 0, 0, 0 ); @@ -5431,7 +5432,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCloseRound_worksGivenRoundHasStartedButNotEnded() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); @@ -5470,12 +5471,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { fundingPot.closeRound(roundId); // Verify round is closed - assertEq(fundingPot.isRoundClosed(roundId), true); + assertEq(fundingPot.roundIdToClosedStatus(roundId), true); } function testCloseRound_worksGivenRoundHasEnded() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); @@ -5518,13 +5519,13 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { fundingPot.closeRound(roundId); // Verify round is closed - assertEq(fundingPot.isRoundClosed(roundId), true); + assertEq(fundingPot.roundIdToClosedStatus(roundId), true); } function testCloseRound_worksGivenRoundCapHasBeenReached() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.NFT); @@ -5563,15 +5564,15 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { contributor1_, roundId, amount, accessCriteriaId, new bytes32[](0) ); - assertEq(fundingPot.isRoundClosed(roundId), false); + assertEq(fundingPot.roundIdToClosedStatus(roundId), false); fundingPot.closeRound(roundId); - assertEq(fundingPot.isRoundClosed(roundId), true); + assertEq(fundingPot.roundIdToClosedStatus(roundId), true); } function testCloseRound_worksGivenRoundisAutoClosure() public { testEditRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); @@ -5610,12 +5611,12 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { contributor1_, roundId, amount, accessCriteriaId, new bytes32[](0) ); - assertEq(fundingPot.isRoundClosed(roundId), true); + assertEq(fundingPot.roundIdToClosedStatus(roundId), true); } function testCloseRound_worksWithMultipleContributors() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); // Set up access criteria uint8 accessCriteriaId = 1; @@ -5670,7 +5671,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { fundingPot.closeRound(roundId); // Verify round is closed - assertEq(fundingPot.isRoundClosed(roundId), true); + assertEq(fundingPot.roundIdToClosedStatus(roundId), true); } //------------------------------------------------------------------------- @@ -5727,7 +5728,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCreatePaymentOrdersForContributorsBatch_revertsGivenRoundIsNotClosed( ) public { testContributeToRoundFor_worksGivenGenericConfigAndAccessCriteria(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); vm.expectRevert( abi.encodeWithSelector( @@ -5742,7 +5743,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCreatePaymentOrdersForContributorsBatch_revertsGivenBatchSizeIsZero( ) public { testCloseRound_worksWithMultipleContributors(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); vm.expectRevert( abi.encodeWithSelector( @@ -5757,7 +5758,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCreatePaymentOrdersForContributorsBatch_revertsGivenUserDoesNotHaveFundingPotAdminRole( ) public { testCloseRound_worksWithMultipleContributors(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); vm.startPrank(contributor1_); bytes32 roleId = _authorizer.generateRoleId( @@ -5777,7 +5778,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCreatePaymentOrdersForContributorsBatch_worksGivenBatchSizeIsGreaterThanContributorCount( ) public { testCloseRound_worksWithMultipleContributors(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); fundingPot.createPaymentOrdersForContributorsBatch(roundId, 999); assertEq(fundingPot.paymentOrders().length, 3); @@ -5786,7 +5787,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCreatePaymentOrdersForContributorsBatch_worksGivenRoundIsAutoClosure( ) public { testCloseRound_worksGivenRoundisAutoClosure(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); fundingPot.createPaymentOrdersForContributorsBatch(roundId, 1); assertEq(fundingPot.paymentOrders().length, 1); @@ -5795,7 +5796,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function testCreatePaymentOrdersForContributorsBatch_worksGivenRoundIsManualClosure( ) public { testCloseRound_worksWithMultipleContributors(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); fundingPot.createPaymentOrdersForContributorsBatch(roundId, 3); assertEq(fundingPot.paymentOrders().length, 3); @@ -5810,7 +5811,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { bool canOverrideContributionSpan_, uint unspentPersonalCap_ ) external { - vm.assume(roundId_ > 0 && roundId_ >= fundingPot.getRoundCount()); + vm.assume(roundId_ > 0 && roundId_ >= fundingPot.roundCount()); vm.assume(amount_ <= 1000); vm.assume(accessCriteriaId_ <= 4); vm.assume(unspentPersonalCap_ >= 0); @@ -5920,7 +5921,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.assume(accessCriteriaEnum > 4); testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); (uint roundStart,,,,,,) = fundingPot.getRoundGenericParameters(roundId); vm.warp(roundStart + 1); @@ -6136,7 +6137,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { function test_closeRound_worksGivenCapReached() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); uint8 accessCriteriaId = 1; uint8 accessType = uint8(ILM_PC_FundingPot_v1.AccessCriteriaType.OPEN); @@ -6187,14 +6188,14 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { uint32(roundId), startIndex, batchSize ); - assertTrue(fundingPot.isRoundClosed(roundId)); + assertTrue(fundingPot.roundIdToClosedStatus(roundId)); } // ------------------------------------------------------------------------- // Test: _buyBondingCurveToken function test_buyBondingCurveToken_revertsGivenNoContributions() public { testCreateRound(); - uint32 roundId = fundingPot.getRoundCount(); + uint32 roundId = fundingPot.roundCount(); (uint roundStart,,,,,,) = fundingPot.getRoundGenericParameters(roundId); vm.warp(roundStart + 1); From bdd6dfdeac5111d2b9ed5b54fdec61647aced326 Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Thu, 19 Jun 2025 19:06:55 +0530 Subject: [PATCH 10/11] fix: contract size fix 3 --- src/modules/logicModule/LM_PC_FundingPot_v1.sol | 12 ------------ .../logicModule/interfaces/ILM_PC_FundingPot_v1.sol | 9 +-------- .../modules/logicModule/LM_PC_FundingPot_v1.t.sol | 6 +++--- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index 432fe93c4..e7ed9537d 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -987,19 +987,7 @@ contract LM_PC_FundingPot_v1 is roundId_, accessCriteriaId_, merkleProof_, user_ ); - if (!isEligible) { - if (accessCriteria.accessCriteriaType == AccessCriteriaType.NFT) { - revert Module__LM_PC_FundingPot__AccessCriteriaNftFailed(); - } - if (accessCriteria.accessCriteriaType == AccessCriteriaType.MERKLE) - { - revert Module__LM_PC_FundingPot__AccessCriteriaMerkleFailed(); - } - if (accessCriteria.accessCriteriaType == AccessCriteriaType.LIST) { - revert Module__LM_PC_FundingPot__AccessCriteriaListFailed(); - } - } } /// @notice Validates and adjusts the contribution amount considering caps and unspent capacity. diff --git a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol index 81d0fac45..54d2431f1 100644 --- a/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/interfaces/ILM_PC_FundingPot_v1.sol @@ -246,14 +246,7 @@ interface ILM_PC_FundingPot_v1 is IERC20PaymentClientBase_v2 { /// @notice Round has already ended. error Module__LM_PC_FundingPot__RoundHasEnded(); - /// @notice User does not meet the NFT access criteria. - error Module__LM_PC_FundingPot__AccessCriteriaNftFailed(); - - /// @notice User does not meet the merkle proof access criteria. - error Module__LM_PC_FundingPot__AccessCriteriaMerkleFailed(); - - /// @notice User is not on the allowlist. - error Module__LM_PC_FundingPot__AccessCriteriaListFailed(); + error Module__LM_PC_FundingPot__AccessCriteriaFailed(); /// @notice User has reached their personal contribution cap. error Module__LM_PC_FundingPot__PersonalCapReached(); diff --git a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol index 060b9e836..f9a7df885 100644 --- a/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol +++ b/test/unit/modules/logicModule/LM_PC_FundingPot_v1.t.sol @@ -1588,7 +1588,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__AccessCriteriaNftFailed + .Module__LM_PC_FundingPot__AccessCriteriaFailed .selector ) ); @@ -1641,7 +1641,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__AccessCriteriaMerkleFailed + .Module__LM_PC_FundingPot__AccessCriteriaFailed .selector ) ); @@ -1690,7 +1690,7 @@ contract LM_PC_FundingPot_v1_Test is ModuleTest { vm.expectRevert( abi.encodeWithSelector( ILM_PC_FundingPot_v1 - .Module__LM_PC_FundingPot__AccessCriteriaListFailed + .Module__LM_PC_FundingPot__AccessCriteriaFailed .selector ) ); From c3bda895e128ba56af9612b4c697bd80a4f8aa24 Mon Sep 17 00:00:00 2001 From: Zuhaib Mohammed Date: Thu, 19 Jun 2025 19:22:28 +0530 Subject: [PATCH 11/11] fix: contract size fix 3: if condition --- src/modules/logicModule/LM_PC_FundingPot_v1.sol | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/modules/logicModule/LM_PC_FundingPot_v1.sol b/src/modules/logicModule/LM_PC_FundingPot_v1.sol index e7ed9537d..f01b74df1 100644 --- a/src/modules/logicModule/LM_PC_FundingPot_v1.sol +++ b/src/modules/logicModule/LM_PC_FundingPot_v1.sol @@ -987,7 +987,17 @@ contract LM_PC_FundingPot_v1 is roundId_, accessCriteriaId_, merkleProof_, user_ ); - + if ( + !isEligible + && ( + accessCriteria.accessCriteriaType == AccessCriteriaType.NFT + || accessCriteria.accessCriteriaType + == AccessCriteriaType.MERKLE + || accessCriteria.accessCriteriaType == AccessCriteriaType.LIST + ) + ) { + revert Module__LM_PC_FundingPot__AccessCriteriaFailed(); + } } /// @notice Validates and adjusts the contribution amount considering caps and unspent capacity.