-
Notifications
You must be signed in to change notification settings - Fork 21
Good Collective bulk add members #311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
… in contracts and SDK, including gas estimation and tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes - here's some feedback:
- In both
UBIPool.addMembersandDirectPaymentsPool.addMembers, consider replacing the genericrevert("Length mismatch")with a named custom error (e.g.error LENGTH_MISMATCH();) for gas savings and consistency with the other custom errors. - In
estimateBulkAddMembersGasin the SDK, you computegasPerMemberasgasEstimate.div(members.length); it would be safer to explicitly handle themembers.length === 0case to avoid division by zero and to return a well-definedrecommendedBatchSizefor empty input. - The new
addMembersfunctions onDirectPaymentsFactoryandUBIPoolFactoryare not invoked by the new bulk add paths (which still go through_grantRole→addMember); if the intent is to centralize duplicate-prevention at the factory level, consider wiring the pools to calladdMembersfor bulk updates or clarifying why both variants are needed.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In both `UBIPool.addMembers` and `DirectPaymentsPool.addMembers`, consider replacing the generic `revert("Length mismatch")` with a named custom error (e.g. `error LENGTH_MISMATCH();`) for gas savings and consistency with the other custom errors.
- In `estimateBulkAddMembersGas` in the SDK, you compute `gasPerMember` as `gasEstimate.div(members.length)`; it would be safer to explicitly handle the `members.length === 0` case to avoid division by zero and to return a well-defined `recommendedBatchSize` for empty input.
- The new `addMembers` functions on `DirectPaymentsFactory` and `UBIPoolFactory` are not invoked by the new bulk add paths (which still go through `_grantRole` → `addMember`); if the intent is to centralize duplicate-prevention at the factory level, consider wiring the pools to call `addMembers` for bulk updates or clarifying why both variants are needed.
## Individual Comments
### Comment 1
<location> `packages/sdk-js/src/goodcollective/goodcollective.ts:855-864` </location>
<code_context>
+ const pool = poolType === 'ubi' ? this.ubipool.attach(poolAddress) : this.pool.attach(poolAddress);
+
+ // Estimate gas for the transaction
+ const gasEstimate = await pool.estimateGas.addMembers(members, extraData);
+
+ // Get current gas price
+ const gasPrice = await pool.provider.getGasPrice();
+
+ // Calculate native token required
+ const nativeTokenRequired = gasEstimate.mul(gasPrice);
+
+ // Calculate recommended batch size based on gas estimate
+ // Assuming block gas limit of 30M and targeting 50% usage for safety
+ const targetGasLimit = 15000000;
+ const gasPerMember = gasEstimate.div(members.length);
+ const recommendedBatchSize = Math.min(200, Math.floor(targetGasLimit / gasPerMember.toNumber()));
+
+ return {
</code_context>
<issue_to_address>
**issue (bug_risk):** Guard against empty members array and avoid BigNumber.toNumber() for gas arithmetic.
`members.length === 0` will cause `gasEstimate.div(members.length)` to throw. Also, `gasPerMember.toNumber()` risks exceeding JS’s safe integer range for large gas values. Consider short‑circuiting the empty‑array case (e.g., return zeros and batch size 0), and keep calculations in `BigNumber` until the end (e.g., `targetGasLimitBN.div(gasPerMember)` then clamp before converting to a JS number).
</issue_to_address>
### Comment 2
<location> `packages/sdk-js/src/goodcollective/goodcollective.ts:867` </location>
<code_context>
+ // Assuming block gas limit of 30M and targeting 50% usage for safety
+ const targetGasLimit = 15000000;
+ const gasPerMember = gasEstimate.div(members.length);
+ const recommendedBatchSize = Math.min(200, Math.floor(targetGasLimit / gasPerMember.toNumber()));
+
+ return {
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Avoid duplicating the MAX_BATCH_SIZE constant value in the SDK to prevent drift.
The SDK currently hardcodes `200` when calculating `recommendedBatchSize`, while the contracts define `MAX_BATCH_SIZE = 200`. If the contract limit changes, the SDK will become inconsistent. Consider deriving this value from the contract (e.g., a view/static property) or centralizing the constant in the SDK so it stays in sync.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Good Collective bulk add members
🚨 Report Summary
For more details view the full report in OpenZeppelin Code Inspector |
… pools with bulk updates and error handling improvements
packages/contracts/contracts/DirectPayments/DirectPaymentsPool.sol
Outdated
Show resolved
Hide resolved
packages/contracts/contracts/DirectPayments/DirectPaymentsPool.sol
Outdated
Show resolved
Hide resolved
packages/contracts/contracts/DirectPayments/DirectPaymentsPool.sol
Outdated
Show resolved
Hide resolved
packages/contracts/test/DirectPayments/DirectPayments.bulkMembers.test.ts
Show resolved
Hide resolved
packages/contracts/test/DirectPayments/DirectPayments.bulkMembers.test.ts
Outdated
Show resolved
Hide resolved
- Simplified factory addMembers() to inline logic instead of calling external functions - Removed BATCH_TOO_LARGE guards - gas management is now caller's responsibility - Added MANAGER_ROLE access control to pool addMembers() methods - Removed _grantMemberRoleWithoutFactory() helper functions - Consolidated SDK methods into single addPoolMembers() with poolType parameter - Updated tests to remove obsolete double-counting and batch size checks - Fixed SDK TypeScript error in gas estimation function BREAKING CHANGE: SDK addDirectPaymentsPoolMembers() and addUBIPoolMembers() methods removed in favor of consolidated addPoolMembers(poolType) method
| ); | ||
| event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards); | ||
| event NOT_MEMBER_OR_WHITELISTED_OR_LIMITS(address contributer); | ||
| event MemberAdded(address indexed member); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for this event. the grantrole emits an event
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EmekaManuel what about this?
| if (added) { | ||
| emit MemberAdded(members[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need
packages/contracts/test/DirectPayments/DirectPayments.bulkMembers.test.ts
Outdated
Show resolved
Hide resolved
…pools - Consolidated member addition logic in addMembers() functions to improve readability and maintainability. - Removed redundant event emissions and replaced them with role grants for better event handling. - Updated tests to reflect changes in event verification and member addition processes. - Adjusted SDK methods to align with the new member addition structure, enhancing usability.
|
kindly review @sirpy |
packages/contracts/contracts/DirectPayments/DirectPaymentsPool.sol
Outdated
Show resolved
Hide resolved
packages/contracts/contracts/DirectPayments/DirectPaymentsPool.sol
Outdated
Show resolved
Hide resolved
packages/contracts/test/DirectPayments/DirectPayments.bulkMembers.test.ts
Show resolved
Hide resolved
|
@EmekaManuel please go over previous comments. |
|
@EmekaManuel ping |
sirpy
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @EmekaManuel
This has been inactive for over two weeks.
You could be removed from this bounty if you don't complete it.
|
@L03TJ3 CC |
|
@sirpy, yes, agree, let's give it till Thursday. |
so sorry @L03TJ3 Lewis and @sirpy, been sick for a while, just recovering. Let me take a look and address this now |
…yments and UBI pools fixing contract build error - Updated addMember functions in DirectPaymentsFactory, UBIPool, and UBIPoolFactory contracts from external to public visibility to enhance accessibility. - This change allows for more flexible member addition while maintaining existing access control mechanisms.
…ctPayments and UBI pools - Updated for-loops in addMembers functions to remove unnecessary unchecked increment statements, enhancing code clarity and maintainability. - This change streamlines the member addition process while preserving existing functionality.
…setup logic - Introduced reusable setup functions for DirectPayments tests to streamline test initialization and improve maintainability. - Updated test cases to utilize the new setup functions, reducing redundancy and enhancing clarity. - Adjusted member validation mocks to ensure accurate testing of member addition scenarios.
|
|
||
| function addMembers(address[] calldata members) external onlyPool { | ||
| for (uint i = 0; i < members.length; ) { | ||
| addMember(members[i]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure this will work, because addmember had modifier onlypool
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not using standard for loop
| ); | ||
| event NFTClaimed(uint256 indexed tokenId, uint256 totalRewards); | ||
| event NOT_MEMBER_OR_WHITELISTED_OR_LIMITS(address contributer); | ||
| event MemberAdded(address indexed member); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@EmekaManuel what about this?
Bulk Member Addition for DirectPayments and UBI Pools
#307
Description
This PR implements bulk member addition functionality for both DirectPayments and UBI pools, enabling efficient batch operations for adding multiple members in a single transaction. This significantly reduces gas costs and improves the onboarding experience when working with large member lists.
Summary of Changes
🧩 Smart Contracts
DirectPaymentsPool & UBIPool
Added a new function:
Includes:
uniquenessValidatormembersValidatorMemberAddedevent emitted for each successful additionMAX_BATCH_SIZE = 200enforced to avoid gas-limit issuesDirectPaymentsFactory & UBIPoolFactory
Added:
Functionality includes:
memberPoolsregistry for efficient lookupsMemberAddedevents at the factory level📦 SDK (packages/sdk-js)
Added three new
GoodCollectiveSDKmethods:addDirectPaymentsPoolMembers()– Add multiple DirectPayments pool membersaddUBIPoolMembers()– Add multiple UBI pool membersestimateBulkAddMembersGas()– Estimate gas + recommend batch sizesTests
Comprehensive test suites for both pool types:
DirectPayments.bulkMembers.test.tsUBIPool.bulkMembers.test.tsCoverage includes:
MAX_BATCH_SIZE = 200)Key Features
Breaking Changes
None.
This feature is fully additive and does not modify existing behavior.
How Has This Been Tested?
🧪 Automated Unit Tests
DirectPayments.bulkMembers.test.ts– 10 test casesUBIPool.bulkMembers.test.ts– 10 test cases (including UBI-specific logic)Coverage Includes:
Test Execution:
🧪 Manual Testing