Skip to content

Commit 5e6ae75

Browse files
authored
test: added test on addMembers() (#17)
* completed addMembers() * completed removeMember()
1 parent 903681d commit 5e6ae75

File tree

2 files changed

+69
-25
lines changed

2 files changed

+69
-25
lines changed

src/SemaphoreMSAValidator.sol

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ contract SemaphoreMSAValidator is ERC7579ValidatorBase {
3131
}
3232

3333
// Errors
34-
error CannotRemoveOwner();
35-
error InvalidCommitment();
36-
error InvalidThreshold();
37-
error MaxMemberReached();
34+
error MemberCntReachesThreshold(address account);
35+
error InvalidCommitment(address account);
36+
error InvalidThreshold(address account);
37+
error MaxMemberReached(address account);
3838
error CommitmentsNotUnique();
3939
error MemberNotExists(address account, uint256 cmt);
4040
error IsMemberAlready(address acount, uint256 cmt);
@@ -54,7 +54,7 @@ contract SemaphoreMSAValidator is ERC7579ValidatorBase {
5454
// Events
5555
event ModuleInitialized(address indexed account);
5656
event ModuleUninitialized(address indexed account);
57-
event AddedMember(address indexed, uint256 indexed commitment);
57+
event AddedMembers(address indexed, uint256 indexed length);
5858
event RemovedMember(address indexed, uint256 indexed commitment);
5959
event ThresholdSet(address indexed account, uint8 indexed threshold);
6060
event InitiatedTx(address indexed account, uint256 indexed seq, bytes32 indexed txHash);
@@ -116,14 +116,14 @@ contract SemaphoreMSAValidator is ERC7579ValidatorBase {
116116
uint256[] memory cmts = cmtBytes.convertToCmts();
117117

118118
// Check the relation between threshold and ownersLen are valid
119-
if (cmts.length > MAX_MEMBERS) revert MaxMemberReached();
120-
if (cmts.length < threshold) revert InvalidThreshold();
119+
if (cmts.length > MAX_MEMBERS) revert MaxMemberReached(account);
120+
if (cmts.length < threshold) revert InvalidThreshold(account);
121121

122122
// Check no duplicate commitment and no `0`
123123
cmts.insertionSort();
124124
if (!cmts.isSortedAndUniquified()) revert CommitmentsNotUnique();
125125
(bool found,) = cmts.searchSorted(uint256(0));
126-
if (found) revert InvalidCommitment();
126+
if (found) revert InvalidCommitment(account);
127127

128128
// Completed all checks by this point. Write to the storage.
129129
thresholds[account] = threshold;
@@ -159,41 +159,44 @@ contract SemaphoreMSAValidator is ERC7579ValidatorBase {
159159

160160
function setThreshold(uint8 newThreshold) external moduleInstalled {
161161
address account = msg.sender;
162-
if (newThreshold == 0 || newThreshold > memberCount(account)) revert InvalidThreshold();
162+
if (newThreshold == 0 || newThreshold > memberCount(account)) {
163+
revert InvalidThreshold(account);
164+
}
163165

164166
thresholds[account] = newThreshold;
165167
emit ThresholdSet(account, newThreshold);
166168
}
167169

168-
function addMember(uint256 cmt) external moduleInstalled {
170+
function addMembers(uint256[] calldata cmts) external moduleInstalled {
169171
address account = msg.sender;
170-
// 0. check the module is initialized for the acct
171-
// 1. check newOwner != 0
172-
// 2. check ownerCount < MAX_MEMBERS
173-
// 3. cehck owner not existed yet
174-
if (cmt == uint256(0)) revert InvalidCommitment();
175-
if (memberCount(account) == MAX_MEMBERS) revert MaxMemberReached();
176-
177172
uint256 groupId = groupMapping[account];
178173

179-
if (groups.hasMember(groupId, cmt)) revert IsMemberAlready(account, cmt);
174+
if (memberCount(account) + cmts.length > MAX_MEMBERS) revert MaxMemberReached(account);
180175

181-
semaphore.addMember(groupId, cmt);
176+
for (uint256 i = 0; i < cmts.length; ++i) {
177+
if (cmts[i] == uint256(0)) revert InvalidCommitment(account);
178+
if (groups.hasMember(groupId, cmts[i])) revert IsMemberAlready(account, cmts[i]);
179+
}
182180

183-
emit AddedMember(account, cmt);
181+
semaphore.addMembers(groupId, cmts);
182+
emit AddedMembers(account, cmts.length);
184183
}
185184

186-
function removeMember(uint256 cmt) external moduleInstalled {
185+
function removeMember(
186+
uint256 cmt,
187+
uint256[] calldata merkleProofSiblings
188+
)
189+
external
190+
moduleInstalled
191+
{
187192
address account = msg.sender;
188193

189-
if (memberCount(account) == thresholds[account]) revert CannotRemoveOwner();
194+
if (memberCount(account) == thresholds[account]) revert MemberCntReachesThreshold(account);
190195

191196
uint256 groupId = groupMapping[account];
192197
if (!groups.hasMember(groupId, cmt)) revert MemberNotExists(account, cmt);
193198

194-
//TODO: add the 3rd param: merkleProofSiblings. Now I set it to 0 to make it passes the
195-
// compiler
196-
semaphore.removeMember(groupId, cmt, new uint256[](0));
199+
semaphore.removeMember(groupId, cmt, merkleProofSiblings);
197200

198201
emit RemovedMember(account, cmt);
199202
}

test/SemaphoreMSAValidator.t.sol

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,47 @@ contract SemaphoreValidatorUnitTest is RhinestoneModuleKit, Test {
209209
assertEq(validationData, VALIDATION_SUCCESS);
210210
}
211211

212+
function test_addMembers() public setupSmartAcctWithMembersThreshold(1, 1) {
213+
Identity newIdentity = $users[1].identity;
214+
uint256 newCommitment = newIdentity.commitment();
215+
216+
// Compose the userOp
217+
PackedUserOperation memory userOp = getEmptyUserOperation();
218+
userOp.sender = smartAcct.account;
219+
userOp.callData = getTestUserOpCallData(
220+
0,
221+
address(semaphoreValidator),
222+
abi.encodeWithSelector(SemaphoreMSAValidator.initiateTx.selector)
223+
);
224+
bytes32 userOpHash = bytes32(keccak256("userOpHash"));
225+
userOp.signature = newIdentity.signHash(userOpHash);
226+
227+
// expecting the vm to revert
228+
vm.expectRevert(
229+
abi.encodeWithSelector(
230+
SemaphoreMSAValidator.MemberNotExists.selector, smartAcct.account, newCommitment
231+
)
232+
);
233+
semaphoreValidator.validateUserOp(userOp, userOpHash);
234+
235+
// Now we add the new member
236+
uint256[] memory newMembers = new uint256[](1);
237+
newMembers[0] = newCommitment;
238+
239+
vm.prank(smartAcct.account);
240+
semaphoreValidator.addMembers(newMembers);
241+
242+
// Test: the userOp should pass
243+
uint256 validationData = ERC7579ValidatorBase.ValidationData.unwrap(
244+
semaphoreValidator.validateUserOp(userOp, userOpHash)
245+
);
246+
assertEq(validationData, VALIDATION_SUCCESS);
247+
}
248+
249+
function test_removeMember() public setupSmartAcctWithMembersThreshold(2, 1) {
250+
revert("to be implemented");
251+
}
252+
212253
function _getSemaphoreValidatorUserOpData(
213254
Identity id,
214255
bytes memory callData,

0 commit comments

Comments
 (0)