diff --git a/src/Membership.sol b/src/Membership.sol index 8792015..a27045c 100644 --- a/src/Membership.sol +++ b/src/Membership.sol @@ -29,7 +29,7 @@ abstract contract MembershipUpgradeable is Initializable { IPriceCalculator public priceCalculator; /// @notice Maximum total rate limit of all memberships in the tree - uint32 public maxTotalRateLimitPerEpoch; + uint32 public maxTotalRateLimit; /// @notice Maximum rate limit of one membership uint32 public maxRateLimitPerMembership; @@ -50,10 +50,10 @@ abstract contract MembershipUpgradeable is Initializable { uint256 public totalRateLimitPerEpoch; /// @notice List of registered memberships - mapping(uint256 idCommitment => MembershipInfo member) public members; + mapping(uint256 idCommitment => MembershipInfo member) public memberships; - /// @notice The index on the merkle tree for the next member to be registered - uint32 public nextCommitmentIndex; + /// @notice The index in the membership set for the next membership to be registered + uint32 public nextFreeIndex; /// @notice track available indices that are available due to expired memberships being removed uint32[] public availableExpiredIndices; @@ -65,9 +65,9 @@ abstract contract MembershipUpgradeable is Initializable { uint256 gracePeriodStartDate; /// @notice duration of the grace period uint32 gracePeriod; - /// @notice the user message limit of each member - uint32 userMessageLimit; - /// @notice the index of the member in the set + /// @notice the membership rate limit + uint32 rateLimit; + /// @notice the index of the member in the membership set uint32 index; /// @notice address of the owner of this membership address holder; @@ -78,27 +78,27 @@ abstract contract MembershipUpgradeable is Initializable { /// @notice Emitted when a membership is erased due to having exceeded the grace period or the owner having chosen /// to not extend it /// @param idCommitment the idCommitment of the member - /// @param userMessageLimit the rate limit of this membership + /// @param membershipRateLimit the rate limit of this membership /// @param index the index of the membership in the merkle tree - event MemberExpired(uint256 idCommitment, uint32 userMessageLimit, uint32 index); + event MemberExpired(uint256 idCommitment, uint32 membershipRateLimit, uint32 index); /// @notice Emitted when a membership in grace period is extended /// @param idCommitment the idCommitment of the member - /// @param userMessageLimit the rate limit of this membership + /// @param membershipRateLimit the rate limit of this membership /// @param index the index of the membership in the merkle tree /// @param newExpirationDate the new expiration date of this membership - event MemberExtended(uint256 idCommitment, uint32 userMessageLimit, uint32 index, uint256 newExpirationDate); + event MemberExtended(uint256 idCommitment, uint32 membershipRateLimit, uint32 index, uint256 newExpirationDate); /// @dev contract initializer /// @param _priceCalculator Address of an instance of IPriceCalculator - /// @param _maxTotalRateLimitPerEpoch Maximum total rate limit of all memberships in the tree + /// @param _maxTotalRateLimit Maximum total rate limit of all memberships in the tree /// @param _minRateLimitPerMembership Minimum rate limit of one membership /// @param _maxRateLimitPerMembership Maximum rate limit of one membership /// @param _expirationTerm Membership expiration term /// @param _gracePeriod Membership grace period function __MembershipUpgradeable_init( address _priceCalculator, - uint32 _maxTotalRateLimitPerEpoch, + uint32 _maxTotalRateLimit, uint32 _minRateLimitPerMembership, uint32 _maxRateLimitPerMembership, uint32 _expirationTerm, @@ -109,7 +109,7 @@ abstract contract MembershipUpgradeable is Initializable { { __MembershipUpgradeable_init_unchained( _priceCalculator, - _maxTotalRateLimitPerEpoch, + _maxTotalRateLimit, _minRateLimitPerMembership, _maxRateLimitPerMembership, _expirationTerm, @@ -119,7 +119,7 @@ abstract contract MembershipUpgradeable is Initializable { function __MembershipUpgradeable_init_unchained( address _priceCalculator, - uint32 _maxTotalRateLimitPerEpoch, + uint32 _maxTotalRateLimit, uint32 _minRateLimitPerMembership, uint32 _maxRateLimitPerMembership, uint32 _expirationTerm, @@ -128,43 +128,43 @@ abstract contract MembershipUpgradeable is Initializable { internal onlyInitializing { - require(_maxTotalRateLimitPerEpoch >= maxRateLimitPerMembership); + require(_maxTotalRateLimit >= maxRateLimitPerMembership); require(_maxRateLimitPerMembership > minRateLimitPerMembership); require(_minRateLimitPerMembership > 0); require(_expirationTerm > 0); priceCalculator = IPriceCalculator(_priceCalculator); - maxTotalRateLimitPerEpoch = _maxTotalRateLimitPerEpoch; + maxTotalRateLimit = _maxTotalRateLimit; maxRateLimitPerMembership = _maxRateLimitPerMembership; minRateLimitPerMembership = _minRateLimitPerMembership; expirationTerm = _expirationTerm; gracePeriod = _gracePeriod; } - /// @notice Checks if a user message limit is valid. This does not take into account whether we the total - /// memberships have reached already the `maxTotalRateLimitPerEpoch` - /// @param userMessageLimit The user message limit - /// @return true if the user message limit is valid, false otherwise - function isValidUserMessageLimit(uint32 userMessageLimit) external view returns (bool) { - return userMessageLimit >= minRateLimitPerMembership && userMessageLimit <= maxRateLimitPerMembership; + /// @notice Checks if a membership rate limit is valid. This does not take into account whether we the total + /// memberships have reached already the `maxTotalRateLimit` + /// @param membershipRateLimit The membership rate limit + /// @return true if the membership rate limit is valid, false otherwise + function isValidMembershipRateLimit(uint32 membershipRateLimit) external view returns (bool) { + return membershipRateLimit >= minRateLimitPerMembership && membershipRateLimit <= maxRateLimitPerMembership; } /// @dev acquire a membership and trasnfer the fees to the contract /// @param _sender address of the owner of the new membership /// @param _idCommitment the idcommitment of the new membership - /// @param _rateLimit the user message limit + /// @param _rateLimit the membership rate limit /// @return index the index in the merkle tree - /// @return reusedIndex indicates whether a new leaf is being used or if using an existing leaf in the merkle tree + /// @return reuseIndex indicates whether a new leaf is being used or if using an existing leaf in the merkle tree function _acquireMembership( address _sender, uint256 _idCommitment, uint32 _rateLimit ) internal - returns (uint32 index, bool reusedIndex) + returns (uint32 index, bool reuseIndex) { (address token, uint256 amount) = priceCalculator.calculate(_rateLimit); - (index, reusedIndex) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount); + (index, reuseIndex) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount); _transferFees(_sender, token, amount); } @@ -177,11 +177,11 @@ abstract contract MembershipUpgradeable is Initializable { /// slots helds by the membership /// @param _sender holder of the membership. Generally `msg.sender` /// @param _idCommitment IDCommitment - /// @param _rateLimit User message limit + /// @param _rateLimit membership rate limit /// @param _token Address of the token used to acquire the membership /// @param _amount Amount of the token used to acquire the membership /// @return index membership index on the merkle tree - /// @return reusedIndex indicates whether the index returned was a reused slot on the tree or not + /// @return reuseIndex indicates whether the index returned was a reused slot on the tree or not function _setupMembershipDetails( address _sender, uint256 _idCommitment, @@ -190,7 +190,7 @@ abstract contract MembershipUpgradeable is Initializable { uint256 _amount ) internal - returns (uint32 index, bool reusedIndex) + returns (uint32 index, bool reuseIndex) { if (_rateLimit < minRateLimitPerMembership || _rateLimit > maxRateLimitPerMembership) { revert InvalidRateLimit(); @@ -198,36 +198,36 @@ abstract contract MembershipUpgradeable is Initializable { // Determine if we exceed the total rate limit totalRateLimitPerEpoch += _rateLimit; - if (totalRateLimitPerEpoch > maxTotalRateLimitPerEpoch) { + if (totalRateLimitPerEpoch > maxTotalRateLimit) { revert ExceedAvailableMaxRateLimitPerEpoch(); // List is empty or can't } // Reuse available slots from previously removed expired memberships - (index, reusedIndex) = _nextIndex(); + (index, reuseIndex) = _nextIndex(); - members[_idCommitment] = MembershipInfo({ + memberships[_idCommitment] = MembershipInfo({ holder: _sender, gracePeriodStartDate: block.timestamp + uint256(expirationTerm), gracePeriod: gracePeriod, token: _token, amount: _amount, - userMessageLimit: _rateLimit, + rateLimit: _rateLimit, index: index }); } /// @dev reuse available slots from previously removed expired memberships /// @return index index to use - /// @return reusedIndex indicates whether it is reusing an existing index, or using a new one - function _nextIndex() internal returns (uint32 index, bool reusedIndex) { + /// @return reuseIndex indicates whether it is reusing an existing index, or using a new one + function _nextIndex() internal returns (uint32 index, bool reuseIndex) { // Reuse available slots from previously removed expired memberships uint256 arrLen = availableExpiredIndices.length; if (arrLen != 0) { index = availableExpiredIndices[arrLen - 1]; availableExpiredIndices.pop(); - reusedIndex = true; + reuseIndex = true; } else { - index = nextCommitmentIndex; + index = nextFreeIndex; } } @@ -235,7 +235,7 @@ abstract contract MembershipUpgradeable is Initializable { /// @param _sender the address of the holder of the membership /// @param _idCommitment the idCommitment of the membership function _extendMembership(address _sender, uint256 _idCommitment) public { - MembershipInfo storage mdetails = members[_idCommitment]; + MembershipInfo storage mdetails = memberships[_idCommitment]; if (!_isGracePeriod(mdetails.gracePeriodStartDate, mdetails.gracePeriod)) { revert NotInGracePeriod(_idCommitment); @@ -248,7 +248,7 @@ abstract contract MembershipUpgradeable is Initializable { mdetails.gracePeriodStartDate = gracePeriodStartDate; mdetails.gracePeriod = gracePeriod; - emit MemberExtended(_idCommitment, mdetails.userMessageLimit, mdetails.index, gracePeriodStartDate); + emit MemberExtended(_idCommitment, mdetails.rateLimit, mdetails.index, gracePeriodStartDate); } /// @dev Determine whether a timestamp is considered to be expired or not after exceeding the grace period @@ -261,14 +261,14 @@ abstract contract MembershipUpgradeable is Initializable { /// @notice Determine if a membership is expired (has exceeded the grace period) /// @param _idCommitment the idCommitment of the membership function isExpired(uint256 _idCommitment) public view returns (bool) { - MembershipInfo memory m = members[_idCommitment]; + MembershipInfo memory m = memberships[_idCommitment]; return _isExpired(m.gracePeriodStartDate, m.gracePeriod); } /// @notice Returns the timestamp on which a membership can be considered expired /// @param _idCommitment the idCommitment of the membership function expirationDate(uint256 _idCommitment) public view returns (uint256) { - MembershipInfo memory m = members[_idCommitment]; + MembershipInfo memory m = memberships[_idCommitment]; return m.gracePeriodStartDate + uint256(m.gracePeriod) + 1; } @@ -284,11 +284,11 @@ abstract contract MembershipUpgradeable is Initializable { /// @notice Determine if a membership is in grace period /// @param _idCommitment the idCommitment of the membership function isGracePeriod(uint256 _idCommitment) public view returns (bool) { - MembershipInfo memory m = members[_idCommitment]; + MembershipInfo memory m = memberships[_idCommitment]; return _isGracePeriod(m.gracePeriodStartDate, m.gracePeriod); } - /// @dev Remove expired memberships or owned memberships in grace period. + /// @dev Erase expired memberships or owned memberships in grace period. /// @param _sender address of the sender of transaction (will be used to check memberships in grace period) /// @param _idCommitment IDCommitment of the membership to erase function _eraseMembership(address _sender, uint256 _idCommitment, MembershipInfo memory _mdetails) internal { @@ -298,17 +298,17 @@ abstract contract MembershipUpgradeable is Initializable { if (!membershipExpired && !isGracePeriodAndOwned) revert CantEraseMembership(_idCommitment); - emit MemberExpired(_idCommitment, _mdetails.userMessageLimit, _mdetails.index); + emit MemberExpired(_idCommitment, _mdetails.rateLimit, _mdetails.index); // Move balance from expired membership to holder balance balancesToWithdraw[_mdetails.holder][_mdetails.token] += _mdetails.amount; // Deduct the expired membership rate limit - totalRateLimitPerEpoch -= _mdetails.userMessageLimit; + totalRateLimitPerEpoch -= _mdetails.rateLimit; availableExpiredIndices.push(_mdetails.index); - delete members[_idCommitment]; + delete memberships[_idCommitment]; } /// @dev Withdraw any available balance in tokens after a membership is erased. diff --git a/src/WakuRlnV2.sol b/src/WakuRlnV2.sol index a4ce1ff..8d1c55a 100644 --- a/src/WakuRlnV2.sol +++ b/src/WakuRlnV2.sol @@ -11,17 +11,17 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils import { MembershipUpgradeable } from "./Membership.sol"; import { IPriceCalculator } from "./IPriceCalculator.sol"; -/// The tree is full -error FullTree(); +/// The membership set is full +error FullMembershipSet(); -/// Member is already registered +/// A membership with this idCommitment is already registered error DuplicateIdCommitment(); /// Invalid idCommitment error InvalidIdCommitment(uint256 idCommitment); -/// Invalid userMessageLimit -error InvalidUserMessageLimit(uint32 messageLimit); +/// Invalid membership rate limit // FIXME: this is not used - remove? +error InvalidMembershipRateLimit(uint32 rateLimit); /// Invalid pagination query error InvalidPaginationQuery(uint256 startIndex, uint256 endIndex); @@ -31,27 +31,27 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M uint256 public constant Q = 21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617; - /// @notice The depth of the merkle tree - uint8 public constant DEPTH = 20; + /// @notice The depth of the Merkle tree that stores rate commitments of memberships + uint8 public constant MERKLE_TREE_DEPTH = 20; - /// @notice The size of the merkle tree, i.e 2^depth - uint32 public SET_SIZE; + /// @notice The maximum membership set size is the size of the Merkle tree (2 ^ depth) + uint32 public MAX_MEMBERSHIP_SET_SIZE; - /// @notice the deployed block number + /// @notice The block number at which this contract was deployed uint32 public deployedBlockNumber; - /// @notice the stored imt data - LazyIMTData public imtData; + /// @notice The Merkle tree that stores rate commitments of memberships + LazyIMTData public merkleTree; - /// Emitted when a new member is added to the set - /// @param rateCommitment the rateCommitment of the member - /// @param index The index of the member in the set - event MemberRegistered(uint256 rateCommitment, uint32 index); + /// Emitted when a new membership is added to the membership set + /// @param rateCommitment The rateCommitment of the membership + /// @param index The index of the membership in the membership set + event MembershipRegistered(uint256 rateCommitment, uint32 index); /// @notice the modifier to check if the idCommitment is valid - /// @param idCommitment The idCommitment of the member + /// @param idCommitment The idCommitment of the membership modifier onlyValidIdCommitment(uint256 idCommitment) { - if (!isValidCommitment(idCommitment)) revert InvalidIdCommitment(idCommitment); + if (!isValidIdCommitment(idCommitment)) revert InvalidIdCommitment(idCommitment); _; } @@ -61,14 +61,14 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M /// @dev contract initializer /// @param _priceCalculator Address of an instance of IPriceCalculator - /// @param _maxTotalRateLimitPerEpoch Maximum total rate limit of all memberships in the tree + /// @param _maxTotalRateLimit Maximum total rate limit of all memberships FIXME: clarify: excl expired? /// @param _minRateLimitPerMembership Minimum rate limit of one membership /// @param _maxRateLimitPerMembership Maximum rate limit of one membership /// @param _expirationTerm Membership expiration term /// @param _gracePeriod Membership grace period function initialize( address _priceCalculator, - uint32 _maxTotalRateLimitPerEpoch, + uint32 _maxTotalRateLimit, uint32 _minRateLimitPerMembership, uint32 _maxRateLimitPerMembership, uint32 _expirationTerm, @@ -81,176 +81,176 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M __UUPSUpgradeable_init(); __MembershipUpgradeable_init( _priceCalculator, - _maxTotalRateLimitPerEpoch, + _maxTotalRateLimit, _minRateLimitPerMembership, _maxRateLimitPerMembership, _expirationTerm, _gracePeriod ); - SET_SIZE = uint32(1 << DEPTH); + MAX_MEMBERSHIP_SET_SIZE = uint32(1 << MERKLE_TREE_DEPTH); deployedBlockNumber = uint32(block.number); - LazyIMT.init(imtData, DEPTH); - nextCommitmentIndex = 0; + LazyIMT.init(merkleTree, MERKLE_TREE_DEPTH); + nextFreeIndex = 0; } function _authorizeUpgrade(address newImplementation) internal override onlyOwner { } // solhint-disable-line - /// @notice Checks if a commitment is valid - /// @param idCommitment The idCommitment of the member - /// @return true if the commitment is valid, false otherwise - function isValidCommitment(uint256 idCommitment) public pure returns (bool) { + /// @notice Checks if an idCommitment is valid + /// @param idCommitment The idCommitment of the membership + /// @return true if the idCommitment is valid, false otherwise + function isValidIdCommitment(uint256 idCommitment) public pure returns (bool) { return idCommitment != 0 && idCommitment < Q; } - /// @notice Returns the rateCommitment of a member - /// @param index The index of the member - /// @return The rateCommitment of the member - function indexToCommitment(uint32 index) internal view returns (uint256) { - return imtData.elements[LazyIMT.indexForElement(0, index)]; + /// @notice Returns the rateCommitment of a membership at a given index + /// @param index The index of the membership in the membership set + /// @return The rateCommitment of the membership + function getRateCommmitment(uint32 index) internal view returns (uint256) { + return merkleTree.elements[LazyIMT.indexForElement(0, index)]; } - /// @notice Returns the metadata of a member - /// @param idCommitment The idCommitment of the member - /// @return The metadata of the member (userMessageLimit, index, rateCommitment) - function idCommitmentToMetadata(uint256 idCommitment) public view returns (uint32, uint32, uint256) { - MembershipInfo memory mdetails = members[idCommitment]; - // we cannot call indexToCommitment for 0 index if the member doesn't exist - if (mdetails.userMessageLimit == 0) { + /// @notice Returns the membership info (rate limit, index, rateCommitment) by its idCommitment + /// @param idCommitment The idCommitment of the membership + /// @return The membership info (rateLimit, index, rateCommitment) + function getMembershipInfo(uint256 idCommitment) public view returns (uint32, uint32, uint256) { + MembershipInfo memory membership = memberships[idCommitment]; + // we cannot call getRateCommmitment for 0 index if the membership doesn't exist + if (membership.rateLimit == 0) { return (0, 0, 0); } - return (mdetails.userMessageLimit, mdetails.index, indexToCommitment(mdetails.index)); + return (membership.rateLimit, membership.index, getRateCommmitment(membership.index)); } - /// @notice Checks if a member exists - /// @param idCommitment The idCommitment of the member - /// @return true if the member exists, false otherwise - function memberExists(uint256 idCommitment) public view returns (bool) { - (,, uint256 rateCommitment) = idCommitmentToMetadata(idCommitment); + /// @notice Checks if a membership exists + /// @param idCommitment The idCommitment of the membership + /// @return true if the membership exists, false otherwise + function membershipExists(uint256 idCommitment) public view returns (bool) { + (,, uint256 rateCommitment) = getMembershipInfo(idCommitment); return rateCommitment != 0; } - /// @notice Allows a user to register as a member - /// @param idCommitment The idCommitment of the member - /// @param userMessageLimit The message limit of the member - function register(uint256 idCommitment, uint32 userMessageLimit) external onlyValidIdCommitment(idCommitment) { - if (memberExists(idCommitment)) revert DuplicateIdCommitment(); + /// @notice Register a membership + /// @param idCommitment The idCommitment of the new membership + /// @param rateLimit The rate limit of the new membership + function register(uint256 idCommitment, uint32 rateLimit) external onlyValidIdCommitment(idCommitment) { + if (membershipExists(idCommitment)) revert DuplicateIdCommitment(); uint32 index; - bool reusedIndex; - (index, reusedIndex) = _acquireMembership(_msgSender(), idCommitment, userMessageLimit); + bool reuseIndex; + (index, reuseIndex) = _acquireMembership(_msgSender(), idCommitment, rateLimit); - _register(idCommitment, userMessageLimit, index, reusedIndex); + _register(idCommitment, rateLimit, index, reuseIndex); } - /// @notice Allows a user to register as a member - /// @param idCommitment The idCommitment of the member - /// @param userMessageLimit The message limit of the member - /// @param membershipsToErase List of expired idCommitments to erase + /// @notice Register a membership + /// @param idCommitment The idCommitment of the new membership + /// @param rateLimit The rate limit of the new membership + /// @param idCommitmentsToErase List of idCommitments of expired memberships to erase function register( uint256 idCommitment, - uint32 userMessageLimit, - uint256[] calldata membershipsToErase + uint32 rateLimit, + uint256[] calldata idCommitmentsToErase ) external onlyValidIdCommitment(idCommitment) { - if (memberExists(idCommitment)) revert DuplicateIdCommitment(); + if (membershipExists(idCommitment)) revert DuplicateIdCommitment(); - for (uint256 i = 0; i < membershipsToErase.length; i++) { - uint256 idCommitmentToErase = membershipsToErase[i]; - MembershipInfo memory mdetails = members[idCommitmentToErase]; - if (mdetails.userMessageLimit == 0) revert InvalidIdCommitment(idCommitmentToErase); - _eraseMembership(_msgSender(), idCommitmentToErase, mdetails); - LazyIMT.update(imtData, 0, mdetails.index); + for (uint256 i = 0; i < idCommitmentsToErase.length; i++) { + uint256 idCommitmentToErase = idCommitmentsToErase[i]; + MembershipInfo memory membershipToErase = memberships[idCommitmentToErase]; + if (membershipToErase.rateLimit == 0) revert InvalidIdCommitment(idCommitmentToErase); + _eraseMembership(_msgSender(), idCommitmentToErase, membershipToErase); + LazyIMT.update(merkleTree, 0, membershipToErase.index); } uint32 index; - bool reusedIndex; - (index, reusedIndex) = _acquireMembership(_msgSender(), idCommitment, userMessageLimit); + bool reuseIndex; + (index, reuseIndex) = _acquireMembership(_msgSender(), idCommitment, rateLimit); - _register(idCommitment, userMessageLimit, index, reusedIndex); + _register(idCommitment, rateLimit, index, reuseIndex); } - /// @dev Registers a member - /// @param idCommitment The idCommitment of the member - /// @param userMessageLimit The message limit of the member - /// @param index Indicates the index in the merkle tree - /// @param reusedIndex indicates whether we're inserting a new element in the merkle tree or updating a existing - /// leaf - function _register(uint256 idCommitment, uint32 userMessageLimit, uint32 index, bool reusedIndex) internal { - if (nextCommitmentIndex >= SET_SIZE) revert FullTree(); + /// @dev Registers a membership + /// @param idCommitment The idCommitment of the membership + /// @param rateLimit The rate limit of the membership + /// @param index The index of the membership in the membership set + /// @param reuseIndex Indicates whether we're inserting a new element in the Merkle tree or updating a existing + /// element + function _register(uint256 idCommitment, uint32 rateLimit, uint32 index, bool reuseIndex) internal { + if (nextFreeIndex >= MAX_MEMBERSHIP_SET_SIZE) revert FullMembershipSet(); - uint256 rateCommitment = PoseidonT3.hash([idCommitment, userMessageLimit]); - if (reusedIndex) { - LazyIMT.update(imtData, rateCommitment, index); + uint256 rateCommitment = PoseidonT3.hash([idCommitment, rateLimit]); + if (reuseIndex) { + LazyIMT.update(merkleTree, rateCommitment, index); } else { - LazyIMT.insert(imtData, rateCommitment); - nextCommitmentIndex += 1; + LazyIMT.insert(merkleTree, rateCommitment); + nextFreeIndex += 1; } - emit MemberRegistered(rateCommitment, index); + emit MembershipRegistered(rateCommitment, index); } - /// @notice Returns the commitments of a range of members - /// @param startIndex The start index of the range - /// @param endIndex The end index of the range - /// @return The commitments of the members - function getCommitments(uint32 startIndex, uint32 endIndex) public view returns (uint256[] memory) { + /// @notice Returns the rateCommitments of memberships within an index range + /// @param startIndex The start index of the range (inclusive) + /// @param endIndex The end index of the range (inclusive) + /// @return The rateCommitments of the memberships + function getRateCommitmentsInRange(uint32 startIndex, uint32 endIndex) public view returns (uint256[] memory) { if (startIndex > endIndex) revert InvalidPaginationQuery(startIndex, endIndex); - if (endIndex > nextCommitmentIndex) revert InvalidPaginationQuery(startIndex, endIndex); + if (endIndex > nextFreeIndex) revert InvalidPaginationQuery(startIndex, endIndex); //FIXME: should it be >=? - uint256[] memory commitments = new uint256[](endIndex - startIndex + 1); + uint256[] memory rateCommitments = new uint256[](endIndex - startIndex + 1); for (uint32 i = startIndex; i <= endIndex; i++) { - commitments[i - startIndex] = indexToCommitment(i); + rateCommitments[i - startIndex] = getRateCommmitment(i); } - return commitments; + return rateCommitments; } - /// @notice Returns the root of the IMT - /// @return The root of the IMT + /// @notice Returns the root of the Merkle tree that stores rate commitments of memberships + /// @return The root of the Merkle tree that stores rate commitments of memberships function root() external view returns (uint256) { - return LazyIMT.root(imtData, DEPTH); + return LazyIMT.root(merkleTree, MERKLE_TREE_DEPTH); } - /// @notice Returns the merkle proof elements of a given membership - /// @param index The index of the member - /// @return The merkle proof elements of the member - function merkleProofElements(uint40 index) public view returns (uint256[DEPTH] memory) { - uint256[DEPTH] memory castedProof; - uint256[] memory proof = LazyIMT.merkleProofElements(imtData, index, DEPTH); - for (uint8 i = 0; i < DEPTH; i++) { - castedProof[i] = proof[i]; + /// @notice Returns the Merkle proof that a given membership is in the membership set + /// @param index The index of the membership + /// @return The Merkle proof (an array of MERKLE_TREE_DEPTH elements) + function getMerkleProof(uint40 index) public view returns (uint256[MERKLE_TREE_DEPTH] memory) { + uint256[] memory dynamicSizeProof = LazyIMT.merkleProofElements(merkleTree, index, MERKLE_TREE_DEPTH); + uint256[MERKLE_TREE_DEPTH] memory fixedSizeProof; + for (uint8 i = 0; i < MERKLE_TREE_DEPTH; i++) { + fixedSizeProof[i] = dynamicSizeProof[i]; } - return castedProof; + return fixedSizeProof; } - /// @notice Extend a membership expiration date. Memberships must be on grace period - /// @param idCommitments list of idcommitments - function extend(uint256[] calldata idCommitments) external { + /// @notice Extend a grace-period membership + /// @param idCommitments list of idCommitments of memberships to extend + function extendMemberships(uint256[] calldata idCommitments) external { for (uint256 i = 0; i < idCommitments.length; i++) { - uint256 idCommitment = idCommitments[i]; - _extendMembership(_msgSender(), idCommitment); + uint256 idCommitmentToExtend = idCommitments[i]; + _extendMembership(_msgSender(), idCommitmentToExtend); } } - /// @notice Remove expired memberships or owned memberships in grace period. - /// The user can determine offchain which expired memberships slots - /// are available, and proceed to free them. - /// This is also used to erase memberships in grace period if they're - /// held by the sender. The sender can then withdraw the tokens. - /// @param idCommitments list of idcommitments of the memberships + /// @notice Erase expired memberships or owned grace-period memberships + /// The user can select expired memberships offchain, + /// and proceed to erase them. + /// This function is also used to erase the user's own grace-period memberships. + /// The user (i.e. the transaction sender) can then withdraw the deposited tokens. + /// @param idCommitments list of idCommitments of the memberships to erase function eraseMemberships(uint256[] calldata idCommitments) external { - for (uint256 i = 0; i < idCommitments.length; i++) { - uint256 idCommitment = idCommitments[i]; - MembershipInfo memory mdetails = members[idCommitment]; - if (mdetails.userMessageLimit == 0) revert InvalidIdCommitment(idCommitment); - _eraseMembership(_msgSender(), idCommitment, mdetails); - LazyIMT.update(imtData, 0, mdetails.index); + for (uint256 i = 0; i < idCommitments.length; i++) { // FIXME: not DRY: see register() + uint256 idCommitmentToErase = idCommitments[i]; + MembershipInfo memory membershipToErase = memberships[idCommitmentToErase]; + if (membershipToErase.rateLimit == 0) revert InvalidIdCommitment(idCommitmentToErase); + _eraseMembership(_msgSender(), idCommitmentToErase, membershipToErase); + LazyIMT.update(merkleTree, 0, membershipToErase.index); } } - /// @notice Withdraw any available balance in tokens after a membership is erased. + /// @notice Withdraw any available deposit balance in tokens after a membership is erased. /// @param token The address of the token to withdraw. Use 0x000...000 to withdraw ETH function withdraw(address token) external { _withdraw(_msgSender(), token); @@ -262,37 +262,37 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M priceCalculator = IPriceCalculator(_priceCalculator); } - /// @notice Set the maximum total rate limit of all memberships in the tree - /// @param _maxTotalRateLimitPerEpoch new value - function setMaxTotalRateLimitPerEpoch(uint32 _maxTotalRateLimitPerEpoch) external onlyOwner { - require(_maxTotalRateLimitPerEpoch >= maxRateLimitPerMembership); - maxTotalRateLimitPerEpoch = _maxTotalRateLimitPerEpoch; + /// @notice Set the maximum total rate limit of all (FIXME: excl expired?) memberships in the membership set + /// @param _maxTotalRateLimit new maximum total rate limit (messages per epoch) + function setmaxTotalRateLimit(uint32 _maxTotalRateLimit) external onlyOwner { + require(_maxTotalRateLimit >= maxRateLimitPerMembership); + maxTotalRateLimit = _maxTotalRateLimit; } /// @notice Set the maximum rate limit of one membership - /// @param _maxRateLimitPerMembership new value + /// @param _maxRateLimitPerMembership new maximum rate limit per membership (messages per epoch) function setMaxRateLimitPerMembership(uint32 _maxRateLimitPerMembership) external onlyOwner { require(_maxRateLimitPerMembership >= minRateLimitPerMembership); maxRateLimitPerMembership = _maxRateLimitPerMembership; } /// @notice Set the minimum rate limit of one membership - /// @param _minRateLimitPerMembership new value + /// @param _minRateLimitPerMembership new minimum rate limit per membership (messages per epoch) function setMinRateLimitPerMembership(uint32 _minRateLimitPerMembership) external onlyOwner { - require(_minRateLimitPerMembership > 0); + require(_minRateLimitPerMembership > 0); // FIXME: we must also check here that min rate <= max rate minRateLimitPerMembership = _minRateLimitPerMembership; } - /// @notice Set the membership expiration term - /// @param _expirationTerm new value + /// @notice Set the expiration term for new memberships (expiration dates of existing memberships don't change) + /// @param _expirationTerm new expiration term function setExpirationTerm(uint32 _expirationTerm) external onlyOwner { require(_expirationTerm > 0); expirationTerm = _expirationTerm; } - /// @notice Set the membership grace period - /// @param _gracePeriod new value - function setGracePeriod(uint32 _gracePeriod) external onlyOwner { + /// @notice Set the grace period for new memberships (grace periods of existing memberships don't change) + /// @param _gracePeriod new grace period term + function setGracePeriod(uint32 _gracePeriod) external onlyOwner { // FIXME: shall we check that _gracePeriod > 0? gracePeriod = _gracePeriod; } } diff --git a/test/WakuRlnV2.t.sol b/test/WakuRlnV2.t.sol index b178f51..3adeee5 100644 --- a/test/WakuRlnV2.t.sol +++ b/test/WakuRlnV2.t.sol @@ -40,16 +40,16 @@ contract WakuRlnV2Test is Test { w.setMinRateLimitPerMembership(2); uint256 idCommitment = 2; - uint32 userMessageLimit = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = 2; + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); vm.pauseGasMetering(); - assertEq(w.nextCommitmentIndex(), 1); - assertEq(w.memberExists(idCommitment), true); - (,,, uint32 fetchedUserMessageLimit, uint32 index, address holder,) = w.members(idCommitment); - assertEq(fetchedUserMessageLimit, userMessageLimit); + assertEq(w.nextFreeIndex(), 1); + assertEq(w.membershipExists(idCommitment), true); + (,,, uint32 fetchedMembershipRateLimit, uint32 index, address holder,) = w.memberships(idCommitment); + assertEq(fetchedMembershipRateLimit, membershipRateLimit); assertEq(holder, address(this)); assertEq(index, 0); // kats from zerokit @@ -59,12 +59,12 @@ contract WakuRlnV2Test is Test { w.root(), 13_801_897_483_540_040_307_162_267_952_866_411_686_127_372_014_953_358_983_481_592_640_000_001_877_295 ); - (uint32 fetchedUserMessageLimit2, uint32 index2, uint256 rateCommitment2) = - w.idCommitmentToMetadata(idCommitment); - assertEq(fetchedUserMessageLimit2, userMessageLimit); + (uint32 fetchedMembershipRateLimit2, uint32 index2, uint256 rateCommitment2) = + w.getMembershipInfo(idCommitment); + assertEq(fetchedMembershipRateLimit2, membershipRateLimit); assertEq(index2, 0); assertEq(rateCommitment2, rateCommitment); - uint256[20] memory proof = w.merkleProofElements(0); + uint256[20] memory proof = w.getMerkleProof(0); uint256[20] memory expectedProof = [ 0, 14_744_269_619_966_411_208_579_211_824_598_458_697_587_494_354_926_760_081_771_325_075_741_142_829_156, @@ -93,58 +93,58 @@ contract WakuRlnV2Test is Test { vm.resumeGasMetering(); } - function test__ValidRegistration(uint32 userMessageLimit) external { + function test__ValidRegistration(uint32 membershipRateLimit) external { vm.pauseGasMetering(); uint256 idCommitment = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); - uint256 minUserMessageLimit = w.minRateLimitPerMembership(); - uint256 maxUserMessageLimit = w.maxRateLimitPerMembership(); - vm.assume(userMessageLimit >= minUserMessageLimit && userMessageLimit <= maxUserMessageLimit); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); + uint256 minMembershipRateLimit = w.minRateLimitPerMembership(); + uint256 maxMembershipRateLimit = w.maxRateLimitPerMembership(); + vm.assume(membershipRateLimit >= minMembershipRateLimit && membershipRateLimit <= maxMembershipRateLimit); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); - assertEq(w.memberExists(idCommitment), false); + assertEq(w.membershipExists(idCommitment), false); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); - uint256 rateCommitment = PoseidonT3.hash([idCommitment, userMessageLimit]); + w.register(idCommitment, membershipRateLimit); + uint256 rateCommitment = PoseidonT3.hash([idCommitment, membershipRateLimit]); - (uint32 fetchedUserMessageLimit, uint32 index, uint256 fetchedRateCommitment) = - w.idCommitmentToMetadata(idCommitment); - assertEq(fetchedUserMessageLimit, userMessageLimit); + (uint32 fetchedMembershipRateLimit, uint32 index, uint256 fetchedRateCommitment) = + w.getMembershipInfo(idCommitment); + assertEq(fetchedMembershipRateLimit, membershipRateLimit); assertEq(index, 0); assertEq(fetchedRateCommitment, rateCommitment); assertEq(token.balanceOf(address(w)), price); - assertEq(w.totalRateLimitPerEpoch(), userMessageLimit); + assertEq(w.totalRateLimitPerEpoch(), membershipRateLimit); } - function test__LinearPriceCalculation(uint32 userMessageLimit) external view { + function test__LinearPriceCalculation(uint32 membershipRateLimit) external view { IPriceCalculator priceCalculator = w.priceCalculator(); uint256 pricePerMessagePerPeriod = LinearPriceCalculator(address(priceCalculator)).pricePerMessagePerEpoch(); assertNotEq(pricePerMessagePerPeriod, 0); - uint256 expectedPrice = uint256(userMessageLimit) * pricePerMessagePerPeriod; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint256 expectedPrice = uint256(membershipRateLimit) * pricePerMessagePerPeriod; + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); assertEq(price, expectedPrice); } - function test__InvalidTokenAmount(uint256 idCommitment, uint32 userMessageLimit) external { + function test__InvalidTokenAmount(uint256 idCommitment, uint32 membershipRateLimit) external { vm.pauseGasMetering(); - uint256 minUserMessageLimit = w.minRateLimitPerMembership(); - uint256 maxUserMessageLimit = w.maxRateLimitPerMembership(); - vm.assume(userMessageLimit >= minUserMessageLimit && userMessageLimit <= maxUserMessageLimit); - vm.assume(w.isValidCommitment(idCommitment) && w.isValidUserMessageLimit(userMessageLimit)); - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint256 minMembershipRateLimit = w.minRateLimitPerMembership(); + uint256 maxMembershipRateLimit = w.maxRateLimitPerMembership(); + vm.assume(membershipRateLimit >= minMembershipRateLimit && membershipRateLimit <= maxMembershipRateLimit); + vm.assume(w.isValidIdCommitment(idCommitment) && w.isValidMembershipRateLimit(membershipRateLimit)); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); token.approve(address(w), price - 1); vm.expectRevert(bytes("ERC20: insufficient allowance")); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); } function test__IdCommitmentToMetadata__DoesntExist() external view { uint256 idCommitment = 2; - (uint32 userMessageLimit, uint32 index, uint256 rateCommitment) = w.idCommitmentToMetadata(idCommitment); - assertEq(userMessageLimit, 0); + (uint32 membershipRateLimit, uint32 index, uint256 rateCommitment) = w.getMembershipInfo(idCommitment); + assertEq(membershipRateLimit, 0); assertEq(index, 0); assertEq(rateCommitment, 0); } @@ -152,25 +152,25 @@ contract WakuRlnV2Test is Test { function test__InvalidRegistration__InvalidIdCommitment__Zero() external { vm.pauseGasMetering(); uint256 idCommitment = 0; - uint32 userMessageLimit = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = 2; + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); token.approve(address(w), price); vm.expectRevert(abi.encodeWithSelector(InvalidIdCommitment.selector, 0)); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); } function test__InvalidRegistration__InvalidIdCommitment__LargerThanField() external { vm.pauseGasMetering(); - uint32 userMessageLimit = 20; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = 20; + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); uint256 idCommitment = w.Q() + 1; token.approve(address(w), price); vm.expectRevert(abi.encodeWithSelector(InvalidIdCommitment.selector, idCommitment)); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); } function test__InvalidRegistration__InvalidUserMessageLimit__MinMax() external { @@ -186,19 +186,19 @@ contract WakuRlnV2Test is Test { w.register(idCommitment, invalidMax); } - function test__ValidRegistrationExtend(uint32 userMessageLimit) external { + function test__ValidRegistrationExtend(uint32 membershipRateLimit) external { vm.pauseGasMetering(); uint256 idCommitment = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.assume( - userMessageLimit >= w.minRateLimitPerMembership() && userMessageLimit <= w.maxRateLimitPerMembership() + membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership() ); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); - (, uint256 gracePeriodStartDate,,,,,) = w.members(idCommitment); + w.register(idCommitment, membershipRateLimit); + (, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment); assertFalse(w.isGracePeriod(idCommitment)); assertFalse(w.isExpired(idCommitment)); @@ -215,14 +215,14 @@ contract WakuRlnV2Test is Test { address randomAddress = vm.addr(block.timestamp); vm.prank(randomAddress); vm.expectRevert(abi.encodeWithSelector(NotHolder.selector, commitmentsToExtend[0])); - w.extend(commitmentsToExtend); + w.extendMemberships(commitmentsToExtend); // Attempt to extend the membership (but now we are the owner) vm.expectEmit(true, false, false, false); // only check the first parameter of the event (the idCommitment) emit MembershipUpgradeable.MemberExtended(idCommitment, 0, 0, 0); - w.extend(commitmentsToExtend); + w.extendMemberships(commitmentsToExtend); - (, uint256 newGracePeriodStartDate,,,,,) = w.members(idCommitment); + (, uint256 newGracePeriodStartDate,,,,,) = w.memberships(idCommitment); assertEq(block.timestamp + uint256(w.expirationTerm()), newGracePeriodStartDate); assertFalse(w.isGracePeriod(idCommitment)); @@ -230,26 +230,26 @@ contract WakuRlnV2Test is Test { // Attempt to extend a non grace period membership token.approve(address(w), price); - w.register(idCommitment + 1, userMessageLimit); + w.register(idCommitment + 1, membershipRateLimit); commitmentsToExtend[0] = idCommitment + 1; vm.expectRevert(abi.encodeWithSelector(NotInGracePeriod.selector, commitmentsToExtend[0])); - w.extend(commitmentsToExtend); + w.extendMemberships(commitmentsToExtend); } - function test__ValidRegistrationExtendSingleMembership(uint32 userMessageLimit) external { + function test__ValidRegistrationExtendSingleMembership(uint32 membershipRateLimit) external { vm.pauseGasMetering(); uint256 idCommitment = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.assume( - userMessageLimit >= w.minRateLimitPerMembership() && userMessageLimit <= w.maxRateLimitPerMembership() + membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership() ); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); uint256 ogExpirationDate = w.expirationDate(idCommitment); - (, uint256 gracePeriodStartDate,,,,,) = w.members(idCommitment); + (, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment); vm.warp(gracePeriodStartDate); @@ -259,29 +259,29 @@ contract WakuRlnV2Test is Test { // Extend the membership vm.expectEmit(true, false, false, false); // only check the first parameter of the event (the idCommitment) emit MembershipUpgradeable.MemberExtended(idCommitment, 0, 0, 0); - w.extend(commitmentsToExtend); + w.extendMemberships(commitmentsToExtend); - (, uint256 newGracePeriodStartDate, uint32 newGracePeriod,,,,) = w.members(idCommitment); + (, uint256 newGracePeriodStartDate, uint32 newGracePeriod,,,,) = w.memberships(idCommitment); uint256 expectedExpirationDate = newGracePeriodStartDate + uint256(newGracePeriod) + 1; uint256 expirationDate = w.expirationDate(idCommitment); assertEq(expectedExpirationDate, expirationDate); assertTrue(expectedExpirationDate > ogExpirationDate); } - function test__ValidRegistrationExpiry(uint32 userMessageLimit) external { + function test__ValidRegistrationExpiry(uint32 membershipRateLimit) external { vm.pauseGasMetering(); uint256 idCommitment = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.assume( - userMessageLimit >= w.minRateLimitPerMembership() && userMessageLimit <= w.maxRateLimitPerMembership() + membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership() ); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); - (, uint256 fetchedGracePeriodStartDate, uint32 fetchedGracePeriod,,,,) = w.members(idCommitment); + (, uint256 fetchedGracePeriodStartDate, uint32 fetchedGracePeriod,,,,) = w.memberships(idCommitment); uint256 expectedExpirationDate = fetchedGracePeriodStartDate + uint256(fetchedGracePeriod) + 1; uint256 expirationDate = w.expirationDate(idCommitment); @@ -299,7 +299,7 @@ contract WakuRlnV2Test is Test { vm.startPrank(w.owner()); w.setMinRateLimitPerMembership(20); w.setMaxRateLimitPerMembership(100); - w.setMaxTotalRateLimitPerEpoch(100); + w.setmaxTotalRateLimit(100); vm.stopPrank(); vm.resumeGasMetering(); @@ -312,8 +312,8 @@ contract WakuRlnV2Test is Test { vm.warp(w.expirationDate(i)); } - // Time travel to a point in which the last commitment is active - (, uint256 gracePeriodStartDate,,,,,) = w.members(5); + // Time travel to a point in which the last membership is active + (, uint256 gracePeriodStartDate,,,,,) = w.memberships(5); vm.warp(gracePeriodStartDate - 1); // Ensure that this is the case @@ -349,17 +349,17 @@ contract WakuRlnV2Test is Test { // Ensure that the chosen memberships were erased and others unaffected address holder; - (,,,,, holder,) = w.members(1); + (,,,,, holder,) = w.memberships(1); assertEq(holder, address(0)); - (,,,,, holder,) = w.members(2); + (,,,,, holder,) = w.memberships(2); assertEq(holder, address(0)); - (,,,,, holder,) = w.members(3); + (,,,,, holder,) = w.memberships(3); assertEq(holder, address(this)); - (,,,,, holder,) = w.members(4); + (,,,,, holder,) = w.memberships(4); assertEq(holder, address(0)); - (,,,,, holder,) = w.members(5); + (,,,,, holder,) = w.memberships(5); assertEq(holder, address(this)); - (,,,,, holder,) = w.members(6); + (,,,,, holder,) = w.memberships(6); assertEq(holder, address(this)); // The balance available for withdrawal should match the amount of the expired membership @@ -372,45 +372,45 @@ contract WakuRlnV2Test is Test { vm.startPrank(w.owner()); w.setMinRateLimitPerMembership(1); w.setMaxRateLimitPerMembership(5); - w.setMaxTotalRateLimitPerEpoch(5); + w.setmaxTotalRateLimit(5); vm.stopPrank(); vm.resumeGasMetering(); - bool isValid = w.isValidUserMessageLimit(6); + bool isValid = w.isValidMembershipRateLimit(6); assertFalse(isValid); // Exceeds the max rate limit per user - uint32 userMessageLimit = 10; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = 10; + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); token.approve(address(w), price); vm.expectRevert(abi.encodeWithSelector(InvalidRateLimit.selector)); - w.register(1, userMessageLimit); + w.register(1, membershipRateLimit); // Should register succesfully - userMessageLimit = 4; - (, price) = w.priceCalculator().calculate(userMessageLimit); + membershipRateLimit = 4; + (, price) = w.priceCalculator().calculate(membershipRateLimit); token.approve(address(w), price); - w.register(2, userMessageLimit); + w.register(2, membershipRateLimit); // Exceeds the rate limit - userMessageLimit = 2; - (, price) = w.priceCalculator().calculate(userMessageLimit); + membershipRateLimit = 2; + (, price) = w.priceCalculator().calculate(membershipRateLimit); token.approve(address(w), price); vm.expectRevert(abi.encodeWithSelector(ExceedAvailableMaxRateLimitPerEpoch.selector)); - w.register(3, userMessageLimit); + w.register(3, membershipRateLimit); // Should register succesfully - userMessageLimit = 1; - (, price) = w.priceCalculator().calculate(userMessageLimit); + membershipRateLimit = 1; + (, price) = w.priceCalculator().calculate(membershipRateLimit); token.approve(address(w), price); - w.register(3, userMessageLimit); + w.register(3, membershipRateLimit); // We ran out of rate limit again - userMessageLimit = 1; - (, price) = w.priceCalculator().calculate(userMessageLimit); + membershipRateLimit = 1; + (, price) = w.priceCalculator().calculate(membershipRateLimit); token.approve(address(w), price); vm.expectRevert(abi.encodeWithSelector(ExceedAvailableMaxRateLimitPerEpoch.selector)); - w.register(4, userMessageLimit); + w.register(4, membershipRateLimit); } function test__indexReuse_eraseMemberships(uint32 idCommitmentsLength) external { @@ -422,8 +422,8 @@ contract WakuRlnV2Test is Test { for (uint256 i = 1; i <= idCommitmentsLength; i++) { token.approve(address(w), price); w.register(i, 20); - (,,,, index,,) = w.members(i); - assertEq(index, w.nextCommitmentIndex() - 1); + (,,,, index,,) = w.memberships(i); + assertEq(index, w.nextFreeIndex() - 1); commitmentsToErase[i - 1] = i; } @@ -437,20 +437,20 @@ contract WakuRlnV2Test is Test { assertEq(i, w.availableExpiredIndices(i)); } - uint32 currnextCommitmentIndex = w.nextCommitmentIndex(); + uint32 currnextCommitmentIndex = w.nextFreeIndex(); for (uint256 i = 1; i <= idCommitmentsLength; i++) { uint256 idCommitment = i + 10; uint256 expectedReusedIndexPos = idCommitmentsLength - i; uint32 expectedIndex = w.availableExpiredIndices(expectedReusedIndexPos); token.approve(address(w), price); w.register(idCommitment, 20); - (,,,, index,,) = w.members(idCommitment); + (,,,, index,,) = w.memberships(idCommitment); assertEq(expectedIndex, index); // Should have been removed from the list vm.expectRevert(); w.availableExpiredIndices(expectedReusedIndexPos); // Should not have been affected - assertEq(currnextCommitmentIndex, w.nextCommitmentIndex()); + assertEq(currnextCommitmentIndex, w.nextFreeIndex()); } // No indexes should be available for reuse @@ -460,25 +460,25 @@ contract WakuRlnV2Test is Test { // Should use a new index since we got rid of all available indexes token.approve(address(w), price); w.register(100, 20); - (,,,, index,,) = w.members(100); + (,,,, index,,) = w.memberships(100); assertEq(index, currnextCommitmentIndex); - assertEq(currnextCommitmentIndex + 1, w.nextCommitmentIndex()); + assertEq(currnextCommitmentIndex + 1, w.nextFreeIndex()); } - function test__RemoveExpiredMemberships(uint32 userMessageLimit) external { + function test__RemoveExpiredMemberships(uint32 membershipRateLimit) external { vm.pauseGasMetering(); uint256 idCommitment = 2; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.assume( - userMessageLimit >= w.minRateLimitPerMembership() && userMessageLimit <= w.maxRateLimitPerMembership() + membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership() ); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); uint256 time = block.timestamp; for (uint256 i = 0; i < 5; i++) { token.approve(address(w), price); - w.register(idCommitment + i, userMessageLimit); + w.register(idCommitment + i, membershipRateLimit); time += 100; vm.warp(time); } @@ -506,15 +506,15 @@ contract WakuRlnV2Test is Test { address holder; - (,,,,, holder,) = w.members(idCommitment + 1); + (,,,,, holder,) = w.memberships(idCommitment + 1); assertEq(holder, address(0)); - (,,,,, holder,) = w.members(idCommitment + 2); + (,,,,, holder,) = w.memberships(idCommitment + 2); assertEq(holder, address(0)); // Attempting to call erase when some of the commitments can't be erased yet // idCommitment can be erased (in grace period), but idCommitment + 4 is still active - (, uint256 gracePeriodStartDate,,,,,) = w.members(idCommitment + 4); + (, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment + 4); vm.warp(gracePeriodStartDate - 1); commitmentsToErase[0] = idCommitment; commitmentsToErase[1] = idCommitment + 4; @@ -525,14 +525,14 @@ contract WakuRlnV2Test is Test { function test__RemoveAllExpiredMemberships(uint32 idCommitmentsLength) external { vm.pauseGasMetering(); vm.assume(idCommitmentsLength > 1 && idCommitmentsLength <= 100); - uint32 userMessageLimit = w.minRateLimitPerMembership(); - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = w.minRateLimitPerMembership(); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); uint256 time = block.timestamp; for (uint256 i = 1; i <= idCommitmentsLength; i++) { token.approve(address(w), price); - w.register(i, userMessageLimit); + w.register(i, membershipRateLimit); time += 100; vm.warp(time); } @@ -554,29 +554,29 @@ contract WakuRlnV2Test is Test { // Erased memberships are gone! for (uint256 i = 0; i < commitmentsToErase.length; i++) { - (,,, uint32 fetchedUserMessageLimit,,,) = w.members(commitmentsToErase[i]); - assertEq(fetchedUserMessageLimit, 0); + (,,, uint32 fetchedMembershipRateLimit,,,) = w.memberships(commitmentsToErase[i]); + assertEq(fetchedMembershipRateLimit, 0); } } - function test__WithdrawToken(uint32 userMessageLimit) external { + function test__WithdrawToken(uint32 membershipRateLimit) external { vm.pauseGasMetering(); uint256 idCommitment = 2; LinearPriceCalculator priceCalculator = LinearPriceCalculator(address(w.priceCalculator())); vm.prank(priceCalculator.owner()); priceCalculator.setTokenAndPrice(address(token), 5 wei); - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); token.mint(address(this), price); vm.assume( - userMessageLimit >= w.minRateLimitPerMembership() && userMessageLimit <= w.maxRateLimitPerMembership() + membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership() ); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); - (, uint256 gracePeriodStartDate,,,,,) = w.members(idCommitment); + (, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment); vm.warp(gracePeriodStartDate); @@ -604,29 +604,29 @@ contract WakuRlnV2Test is Test { function test__InvalidRegistration__DuplicateIdCommitment() external { vm.pauseGasMetering(); uint256 idCommitment = 2; - uint32 userMessageLimit = w.minRateLimitPerMembership(); - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = w.minRateLimitPerMembership(); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); token.approve(address(w), price); vm.expectRevert(DuplicateIdCommitment.selector); - w.register(idCommitment, userMessageLimit); + w.register(idCommitment, membershipRateLimit); } function test__InvalidRegistration__FullTree() external { vm.pauseGasMetering(); - uint32 userMessageLimit = 20; - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = 20; + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); // we progress the tree to the last leaf /*| Name | Type | Slot | Offset | Bytes | |---------------------|-----------------------------------------------------|------|--------|-------| - | nextCommitmentIndex | uint32 | 256 | 0 | 4 | */ + | nextFreeIndex | uint32 | 256 | 0 | 4 | */ /* Pro tip: to easily find the storage slot of a variable, without having to calculate the storage layout @@ -644,54 +644,54 @@ contract WakuRlnV2Test is Test { If the storage layout changes, update the next line accordingly */ - // we set nextCommitmentIndex to 4294967295 (1 << 20) = 0x00100000 + // we set nextFreeIndex to 4294967295 (1 << 20) = 0x00100000 vm.store(address(w), bytes32(uint256(256)), 0x0000000000000000000000000000000000000000000000000000000000100000); token.approve(address(w), price); - vm.expectRevert(FullTree.selector); - w.register(1, userMessageLimit); + vm.expectRevert(FullMembershipSet.selector); + w.register(1, membershipRateLimit); } function test__InvalidPaginationQuery__StartIndexGTEndIndex() external { vm.expectRevert(abi.encodeWithSelector(InvalidPaginationQuery.selector, 1, 0)); - w.getCommitments(1, 0); + w.getRateCommitmentsInRange(1, 0); } function test__InvalidPaginationQuery__EndIndexGTnextCommitmentIndex() external { vm.expectRevert(abi.encodeWithSelector(InvalidPaginationQuery.selector, 0, 2)); - w.getCommitments(0, 2); + w.getRateCommitmentsInRange(0, 2); } function test__ValidPaginationQuery__OneElement() external { vm.pauseGasMetering(); uint256 idCommitment = 1; - uint32 userMessageLimit = w.minRateLimitPerMembership(); - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = w.minRateLimitPerMembership(); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); - uint256[] memory commitments = w.getCommitments(0, 0); + w.register(idCommitment, membershipRateLimit); + uint256[] memory commitments = w.getRateCommitmentsInRange(0, 0); assertEq(commitments.length, 1); - uint256 rateCommitment = PoseidonT3.hash([idCommitment, userMessageLimit]); + uint256 rateCommitment = PoseidonT3.hash([idCommitment, membershipRateLimit]); assertEq(commitments[0], rateCommitment); } function test__ValidPaginationQuery(uint32 idCommitmentsLength) external { vm.pauseGasMetering(); vm.assume(idCommitmentsLength > 0 && idCommitmentsLength <= 100); - uint32 userMessageLimit = w.minRateLimitPerMembership(); - (, uint256 price) = w.priceCalculator().calculate(userMessageLimit); + uint32 membershipRateLimit = w.minRateLimitPerMembership(); + (, uint256 price) = w.priceCalculator().calculate(membershipRateLimit); for (uint256 i = 0; i < idCommitmentsLength; i++) { token.approve(address(w), price); - w.register(i + 1, userMessageLimit); + w.register(i + 1, membershipRateLimit); } vm.resumeGasMetering(); - uint256[] memory commitments = w.getCommitments(0, idCommitmentsLength); + uint256[] memory commitments = w.getRateCommitmentsInRange(0, idCommitmentsLength); assertEq(commitments.length, idCommitmentsLength + 1); for (uint256 i = 0; i < idCommitmentsLength; i++) { - uint256 rateCommitment = PoseidonT3.hash([i + 1, userMessageLimit]); + uint256 rateCommitment = PoseidonT3.hash([i + 1, membershipRateLimit]); assertEq(commitments[i], rateCommitment); } }