diff --git a/src/Membership.sol b/src/Membership.sol index 8792015..ea2769c 100644 --- a/src/Membership.sol +++ b/src/Membership.sol @@ -11,316 +11,353 @@ error InvalidRateLimit(); // It's not possible to acquire the rate limit due to exceeding the expected limits // even after attempting to erase expired memberships -error ExceedAvailableMaxRateLimitPerEpoch(); +error ExceededMaxTotalRateLimit(); -// This membership is not in grace period yet +// This membership is not in grace period yet // FIXME: yet or also already? error NotInGracePeriod(uint256 idCommitment); // The sender is not the holder of the membership -error NotHolder(uint256 idCommitment); +error AttemptedExtensionByNonHolder(uint256 idCommitment); -// This membership cannot be erased (either it is not expired or not in grace period and/or not the owner) +// This membership cannot be erased (either it is not expired or not in grace period and/or not the owner) // FIXME: +// separate into two errors? error CantEraseMembership(uint256 idCommitment); abstract contract MembershipUpgradeable is Initializable { using SafeERC20 for IERC20; /// @notice Address of the Price Calculator used to calculate the price of a new membership - IPriceCalculator public priceCalculator; + IPriceCalculator public priceCalculator; // FIXME: naming: price vs deposit? - /// @notice Maximum total rate limit of all memberships in the tree - uint32 public maxTotalRateLimitPerEpoch; + /// @notice Maximum total rate limit of all memberships in the membership set (messages per epoch) + uint32 public maxTotalRateLimit; /// @notice Maximum rate limit of one membership - uint32 public maxRateLimitPerMembership; + uint32 public maxMembershipRateLimit; /// @notice Minimum rate limit of one membership - uint32 public minRateLimitPerMembership; + uint32 public minMembershipRateLimit; - /// @notice Membership billing period - uint32 public expirationTerm; + /// @notice Membership active period duration (A in the spec) + uint32 public activeStateDuration; - /// @notice Membership grace period - uint32 public gracePeriod; + /// @notice Membership grace period duration (G in the spec) + uint32 public gracePeriodDuration; - /// @notice balances available to withdraw - mapping(address holder => mapping(address token => uint256 balance)) public balancesToWithdraw; + /// @notice deposits available for withdrawal + /// Deposits unavailable for withdrawal are stored in MembershipInfo. + mapping(address holder => mapping(address token => uint256 balance)) public depositsToWithdraw; - /// @notice Total rate limit of all memberships in the tree - uint256 public totalRateLimitPerEpoch; + /// @notice Current total rate limit of all memberships in the membership set (messages per epoch) + uint256 public totalRateLimit; - /// @notice List of registered memberships - mapping(uint256 idCommitment => MembershipInfo member) public members; + /// @notice List of memberships in the membership set + mapping(uint256 idCommitment => MembershipInfo membership) 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; + /// @notice indices of memberships (expired or grace-period marked for erasure) that can be reused + uint32[] public reusableIndicesOfErasedMemberships; struct MembershipInfo { - /// @notice amount of the token used to acquire this membership - uint256 amount; + /// @notice deposit amount (in tokens) to register this membership + uint256 depositAmount; /// @notice timestamp of when the grace period starts for this membership - uint256 gracePeriodStartDate; + uint256 gracePeriodStartTimestamp; /// @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 + uint32 gracePeriodDuration; // FIXME: does each membership need to store it if it's a global constant? + /// @notice the membership rate limit + uint32 rateLimit; + /// @notice the index of the membership in the membership set uint32 index; - /// @notice address of the owner of this membership + /// @notice address of the holder of this membership address holder; - /// @notice token used to acquire this membership + /// @notice token used to make the deposit to register this membership address token; } - /// @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 index the index of the membership in the merkle tree - event MemberExpired(uint256 idCommitment, uint32 userMessageLimit, uint32 index); + /// @notice Emitted when a membership is expired (exceeded its grace period and not extended) + /// @param idCommitment the idCommitment of the membership + /// @param membershipRateLimit the rate limit of this membership + /// @param index the index of the membership in the membership set + event MembershipExpired(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 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); + /// @notice Emitted when a membership is erased by its holder during grace period + /// @param idCommitment the idCommitment of the membership + /// @param membershipRateLimit the rate limit of this membership + /// @param index the index of the membership in the membership set + event MembershipErased(uint256 idCommitment, uint32 membershipRateLimit, uint32 index); + + /// @notice Emitted when a membership in its grace period is extended (i.e., is back to Active state) + /// @param idCommitment the idCommitment of the membership + /// @param membershipRateLimit the rate limit of this membership + /// @param index the index of the membership in the membership set + /// @param newGracePeriodStartTimestamp the new grace period start timestamp of this membership + event MembershipExtended( + uint256 idCommitment, uint32 membershipRateLimit, uint32 index, uint256 newGracePeriodStartTimestamp + ); /// @dev contract initializer /// @param _priceCalculator Address of an instance of IPriceCalculator - /// @param _maxTotalRateLimitPerEpoch 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 + /// @param _maxTotalRateLimit Maximum total rate limit of all memberships in the membership set + /// @param _minMembershipRateLimit Minimum rate limit of each membership + /// @param _maxMembershipRateLimit Maximum rate limit of each membership + /// @param _activeStateDuration Active state duration of each membership + /// @param _gracePeriodDuration Grace period duration of each membership function __MembershipUpgradeable_init( address _priceCalculator, - uint32 _maxTotalRateLimitPerEpoch, - uint32 _minRateLimitPerMembership, - uint32 _maxRateLimitPerMembership, - uint32 _expirationTerm, - uint32 _gracePeriod + uint32 _maxTotalRateLimit, + uint32 _minMembershipRateLimit, + uint32 _maxMembershipRateLimit, + uint32 _activeStateDuration, + uint32 _gracePeriodDuration ) internal onlyInitializing { __MembershipUpgradeable_init_unchained( _priceCalculator, - _maxTotalRateLimitPerEpoch, - _minRateLimitPerMembership, - _maxRateLimitPerMembership, - _expirationTerm, - _gracePeriod + _maxTotalRateLimit, + _minMembershipRateLimit, + _maxMembershipRateLimit, + _activeStateDuration, + _gracePeriodDuration ); } function __MembershipUpgradeable_init_unchained( address _priceCalculator, - uint32 _maxTotalRateLimitPerEpoch, - uint32 _minRateLimitPerMembership, - uint32 _maxRateLimitPerMembership, - uint32 _expirationTerm, - uint32 _gracePeriod + uint32 _maxTotalRateLimit, + uint32 _minMembershipRateLimit, + uint32 _maxMembershipRateLimit, + uint32 _activeStateDuration, + uint32 _gracePeriodDuration ) internal onlyInitializing { - require(_maxTotalRateLimitPerEpoch >= maxRateLimitPerMembership); - require(_maxRateLimitPerMembership > minRateLimitPerMembership); - require(_minRateLimitPerMembership > 0); - require(_expirationTerm > 0); + require(0 < _minMembershipRateLimit); + require(_minMembershipRateLimit <= _maxMembershipRateLimit); // FIXME: < or <=? + require(_maxMembershipRateLimit <= _maxTotalRateLimit); + require(_activeStateDuration > 0); // FIXME: also _gracePeriodDuration > 0? priceCalculator = IPriceCalculator(_priceCalculator); - maxTotalRateLimitPerEpoch = _maxTotalRateLimitPerEpoch; - maxRateLimitPerMembership = _maxRateLimitPerMembership; - minRateLimitPerMembership = _minRateLimitPerMembership; - expirationTerm = _expirationTerm; - gracePeriod = _gracePeriod; + maxTotalRateLimit = _maxTotalRateLimit; + minMembershipRateLimit = _minMembershipRateLimit; + maxMembershipRateLimit = _maxMembershipRateLimit; + activeStateDuration = _activeStateDuration; + gracePeriodDuration = _gracePeriodDuration; } - /// @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 rate limit is within the allowed bounds + /// @param rateLimit The rate limit + /// @return true if the rate limit is within the allowed bounds, false otherwise + function isValidMembershipRateLimit(uint32 rateLimit) public view returns (bool) { + return minMembershipRateLimit <= rateLimit && rateLimit <= maxMembershipRateLimit; } - /// @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 - /// @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 + /// @dev acquire a membership and trasnfer the deposit to the contract + /// @param _sender address of the holder of the new membership // FIXME: keeper? + /// @param _idCommitment the idCommitment of the new membership + /// @param _rateLimit the membership rate limit + /// @return index the index of the new membership in the membership set + /// @return indexReused true if the index was reused, false otherwise function _acquireMembership( address _sender, uint256 _idCommitment, uint32 _rateLimit ) internal - returns (uint32 index, bool reusedIndex) + returns (uint32 index, bool indexReused) { + if (!isValidMembershipRateLimit(_rateLimit)) { + revert InvalidRateLimit(); + } (address token, uint256 amount) = priceCalculator.calculate(_rateLimit); - (index, reusedIndex) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount); - _transferFees(_sender, token, amount); + (index, indexReused) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount); + _transferDepositToContract(_sender, token, amount); } - function _transferFees(address _from, address _token, uint256 _amount) internal { + // FIXME: do we need this as a separate function? (it's not called anywhere else) + function _transferDepositToContract(address _from, address _token, uint256 _amount) internal { IERC20(_token).safeTransferFrom(_from, address(this), _amount); } /// @dev Setup a new membership. If there are not enough remaining rate limit to acquire - /// a new membership, it will attempt to erase existing memberships and reuse one of the - /// slots helds by the membership - /// @param _sender holder of the membership. Generally `msg.sender` - /// @param _idCommitment IDCommitment - /// @param _rateLimit User message limit + /// a new membership, it will attempt to erase existing expired memberships + /// and reuse one of their slots + /// @param _sender holder of the membership. Generally `msg.sender` // FIXME: keeper? + /// @param _idCommitment idCommitment + /// @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 + /// @param _depositAmount Amount of the tokens used to acquire the membership + /// @return index membership index in the membership set + /// @return indexReused indicates whether the index returned was a reused slot on the tree or not function _setupMembershipDetails( address _sender, uint256 _idCommitment, uint32 _rateLimit, address _token, - uint256 _amount + uint256 _depositAmount ) internal - returns (uint32 index, bool reusedIndex) + returns (uint32 index, bool indexReused) { - if (_rateLimit < minRateLimitPerMembership || _rateLimit > maxRateLimitPerMembership) { - revert InvalidRateLimit(); - } - // Determine if we exceed the total rate limit - totalRateLimitPerEpoch += _rateLimit; - if (totalRateLimitPerEpoch > maxTotalRateLimitPerEpoch) { - revert ExceedAvailableMaxRateLimitPerEpoch(); // List is empty or can't + totalRateLimit += _rateLimit; + if (totalRateLimit > maxTotalRateLimit) { + revert ExceededMaxTotalRateLimit(); } - // Reuse available slots from previously removed expired memberships - (index, reusedIndex) = _nextIndex(); + // FIXME: check if we even need to reuse an expired membership? - members[_idCommitment] = MembershipInfo({ - holder: _sender, - gracePeriodStartDate: block.timestamp + uint256(expirationTerm), - gracePeriod: gracePeriod, + // Reuse available expired memberships + (index, indexReused) = _getFreeIndex(); + + // FIXME: we must check that the rate limit of the reused membership is sufficient + // otherwise, the total rate limit may become too high + + memberships[_idCommitment] = MembershipInfo({ + holder: _sender, // FIXME: keeper? + gracePeriodStartTimestamp: block.timestamp + uint256(activeStateDuration), + gracePeriodDuration: gracePeriodDuration, token: _token, - amount: _amount, - userMessageLimit: _rateLimit, + depositAmount: _depositAmount, + 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) { - // Reuse available slots from previously removed expired memberships - uint256 arrLen = availableExpiredIndices.length; - if (arrLen != 0) { - index = availableExpiredIndices[arrLen - 1]; - availableExpiredIndices.pop(); - reusedIndex = true; + /// @dev Get a free index (possibly from reusing an index of an erased membership) + /// @return index index to be used for another membership registration + /// @return indexReused indicates whether index comes form reusing a slot of an erased membership + function _getFreeIndex() internal returns (uint32 index, bool indexReused) { + // Reuse the last membership marked as reusable + uint256 numIndices = reusableIndicesOfErasedMemberships.length; + if (numIndices != 0) { + index = reusableIndicesOfErasedMemberships[numIndices - 1]; + reusableIndicesOfErasedMemberships.pop(); + indexReused = true; } else { - index = nextCommitmentIndex; + index = nextFreeIndex; } } - /// @dev Extend a membership expiration date. Membership must be on grace period + /// @dev Extend the expiration date of a grace-period membership /// @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 membership = memberships[_idCommitment]; - if (!_isGracePeriod(mdetails.gracePeriodStartDate, mdetails.gracePeriod)) { + if (!_isInGracePeriod(membership.gracePeriodStartTimestamp, membership.gracePeriodDuration)) { revert NotInGracePeriod(_idCommitment); } + // FIXME: turn into a modifier? + if (_sender != membership.holder) revert AttemptedExtensionByNonHolder(_idCommitment); + // FIXME: see spec: should extension depend on the current block.timestamp? + uint256 newGracePeriodStartTimestamp = block.timestamp + uint256(activeStateDuration); - if (_sender != mdetails.holder) revert NotHolder(_idCommitment); + membership.gracePeriodStartTimestamp = newGracePeriodStartTimestamp; + membership.gracePeriodDuration = gracePeriodDuration; // FIXME: redundant: just assigns old value - uint256 gracePeriodStartDate = block.timestamp + uint256(expirationTerm); - - mdetails.gracePeriodStartDate = gracePeriodStartDate; - mdetails.gracePeriod = gracePeriod; - - emit MemberExtended(_idCommitment, mdetails.userMessageLimit, mdetails.index, gracePeriodStartDate); + emit MembershipExtended( + _idCommitment, membership.rateLimit, membership.index, membership.gracePeriodStartTimestamp + ); } - /// @dev Determine whether a timestamp is considered to be expired or not after exceeding the grace period - /// @param _gracePeriodStartDate timestamp in which the grace period starts - /// @param _gracePeriod duration of the grace period - function _isExpired(uint256 _gracePeriodStartDate, uint32 _gracePeriod) internal view returns (bool) { - return block.timestamp > _gracePeriodStartDate + uint256(_gracePeriod); + /// @dev Determine whether a grace period has passed (the membership is expired) + /// @param _gracePeriodStartTimestamp timestamp in which the grace period starts + /// @param _gracePeriodDuration duration of the grace period + function _isExpired(uint256 _gracePeriodStartTimestamp, uint32 _gracePeriodDuration) internal view returns (bool) { + return block.timestamp > _gracePeriodStartTimestamp + uint256(_gracePeriodDuration); } - /// @notice Determine if a membership is expired (has exceeded the grace period) + /// @notice Determine if a membership is expired /// @param _idCommitment the idCommitment of the membership function isExpired(uint256 _idCommitment) public view returns (bool) { - MembershipInfo memory m = members[_idCommitment]; - return _isExpired(m.gracePeriodStartDate, m.gracePeriod); + MembershipInfo memory membership = memberships[_idCommitment]; + return _isExpired(membership.gracePeriodStartTimestamp, membership.gracePeriodDuration); } /// @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]; - return m.gracePeriodStartDate + uint256(m.gracePeriod) + 1; + function membershipExpirationTimestamp(uint256 _idCommitment) public view returns (uint256) { + MembershipInfo memory membership = memberships[_idCommitment]; + return membership.gracePeriodStartTimestamp + uint256(membership.gracePeriodDuration) + 1; } - /// @dev Determine whether a timestamp is considered to be in grace period or not - /// @param _gracePeriodStartDate timestamp in which the grace period starts - /// @param _gracePeriod duration of the grace period - function _isGracePeriod(uint256 _gracePeriodStartDate, uint32 _gracePeriod) internal view returns (bool) { - uint256 blockTimestamp = block.timestamp; - return - blockTimestamp >= _gracePeriodStartDate && blockTimestamp <= _gracePeriodStartDate + uint256(_gracePeriod); + /// @dev Determine whether the current timestamp is in a given grace period + /// @param _gracePeriodStartTimestamp timestamp in which the grace period starts + /// @param _gracePeriodDuration duration of the grace period + function _isInGracePeriod( + uint256 _gracePeriodStartTimestamp, + uint32 _gracePeriodDuration + ) + internal + view + returns (bool) + { + uint256 timeNow = block.timestamp; + return ( + _gracePeriodStartTimestamp <= timeNow + && timeNow <= _gracePeriodStartTimestamp + uint256(_gracePeriodDuration) + ); } - /// @notice Determine if a membership is in grace period + /// @notice Determine if a membership is in grace period now /// @param _idCommitment the idCommitment of the membership - function isGracePeriod(uint256 _idCommitment) public view returns (bool) { - MembershipInfo memory m = members[_idCommitment]; - return _isGracePeriod(m.gracePeriodStartDate, m.gracePeriod); + function isInGracePeriod(uint256 _idCommitment) public view returns (bool) { + MembershipInfo memory membership = memberships[_idCommitment]; + return _isInGracePeriod(membership.gracePeriodStartTimestamp, membership.gracePeriodDuration); } - /// @dev Remove expired memberships or owned memberships in grace period. + /// @dev Erase expired memberships or owned grace-period memberships. /// @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 { - bool membershipExpired = _isExpired(_mdetails.gracePeriodStartDate, _mdetails.gracePeriod); - bool isGracePeriodAndOwned = - _isGracePeriod(_mdetails.gracePeriodStartDate, _mdetails.gracePeriod) && _mdetails.holder == _sender; + /// @param _idCommitment idCommitment of the membership to erase + function _eraseMembershipAndSaveSlotToReuse( + address _sender, + uint256 _idCommitment, + MembershipInfo memory _membership + ) + internal + { + bool membershipExpired = _isExpired(_membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration); + bool membershipIsInGracePeriodAndHeld = _isInGracePeriod( + _membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration + ) && _membership.holder == _sender; + // FIXME: we already had a non-holder check: reuse it here as a modifier? + if (!membershipExpired && !membershipIsInGracePeriodAndHeld) revert CantEraseMembership(_idCommitment); - if (!membershipExpired && !isGracePeriodAndOwned) revert CantEraseMembership(_idCommitment); + // Move deposit balance from the membership to be erased to holder deposit balance + depositsToWithdraw[_membership.holder][_membership.token] += _membership.depositAmount; - emit MemberExpired(_idCommitment, _mdetails.userMessageLimit, _mdetails.index); + // Deduct the rate limit of this membership from the total rate limit + totalRateLimit -= _membership.rateLimit; - // Move balance from expired membership to holder balance - balancesToWithdraw[_mdetails.holder][_mdetails.token] += _mdetails.amount; + // Mark this membership as reusable + reusableIndicesOfErasedMemberships.push(_membership.index); - // Deduct the expired membership rate limit - totalRateLimitPerEpoch -= _mdetails.userMessageLimit; + // Erase this membership from the memberships mapping + // Note: the Merkle tree data will be erased when the index is reused + delete memberships[_idCommitment]; - availableExpiredIndices.push(_mdetails.index); - - delete members[_idCommitment]; + if (membershipExpired) { + emit MembershipExpired(_idCommitment, _membership.rateLimit, _membership.index); + } + emit MembershipErased(_idCommitment, _membership.rateLimit, _membership.index); } - /// @dev Withdraw any available balance in tokens after a membership is erased. + /// @dev Withdraw any available deposit balance in tokens after a membership is erased. /// @param _sender the address of the owner of the tokens - /// @param _token the address of the token to withdraw. + /// @param _token the address of the token to withdraw function _withdraw(address _sender, address _token) internal { require(_token != address(0), "ETH is not allowed"); - uint256 amount = balancesToWithdraw[_sender][_token]; - require(amount > 0, "Insufficient balance"); + uint256 amount = depositsToWithdraw[_sender][_token]; + require(amount > 0, "Insufficient deposit balance"); - balancesToWithdraw[_sender][_token] = 0; + depositsToWithdraw[_sender][_token] = 0; IERC20(_token).safeTransfer(_sender, amount); } diff --git a/src/WakuRlnV2.sol b/src/WakuRlnV2.sol index a4ce1ff..70eace6 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,17 +61,17 @@ 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 _minRateLimitPerMembership Minimum rate limit of one membership - /// @param _maxRateLimitPerMembership Maximum rate limit of one membership - /// @param _expirationTerm Membership expiration term + /// @param _maxTotalRateLimit Maximum total rate limit of all memberships FIXME: clarify: excl expired? + /// @param _minMembershipRateLimit Minimum rate limit of one membership + /// @param _maxMembershipRateLimit Maximum rate limit of one membership + /// @param _activeStateDuration Membership expiration term /// @param _gracePeriod Membership grace period function initialize( address _priceCalculator, - uint32 _maxTotalRateLimitPerEpoch, - uint32 _minRateLimitPerMembership, - uint32 _maxRateLimitPerMembership, - uint32 _expirationTerm, + uint32 _maxTotalRateLimit, + uint32 _minMembershipRateLimit, + uint32 _maxMembershipRateLimit, + uint32 _activeStateDuration, uint32 _gracePeriod ) public @@ -81,177 +81,183 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M __UUPSUpgradeable_init(); __MembershipUpgradeable_init( _priceCalculator, - _maxTotalRateLimitPerEpoch, - _minRateLimitPerMembership, - _maxRateLimitPerMembership, - _expirationTerm, + _maxTotalRateLimit, + _minMembershipRateLimit, + _maxMembershipRateLimit, + _activeStateDuration, _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) { + // FIXME: turn into modifier? + if (membershipExists(idCommitment)) revert DuplicateIdCommitment(); uint32 index; - bool reusedIndex; - (index, reusedIndex) = _acquireMembership(_msgSender(), idCommitment, userMessageLimit); + bool indexReused; + (index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit); - _register(idCommitment, userMessageLimit, index, reusedIndex); + _register(idCommitment, rateLimit, index, indexReused); } - /// @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(); + // FIXME: turn into modifier? + 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); + // FIXME: extract in a separate function? + for (uint256 i = 0; i < idCommitmentsToErase.length; i++) { + uint256 idCommitmentToErase = idCommitmentsToErase[i]; + MembershipInfo memory membershipToErase = memberships[idCommitmentToErase]; + if (membershipToErase.rateLimit == 0) revert InvalidIdCommitment(idCommitmentToErase); + _eraseMembershipAndSaveSlotToReuse(_msgSender(), idCommitmentToErase, membershipToErase); + LazyIMT.update(merkleTree, 0, membershipToErase.index); } + // FIXME: code repeats cf. register() uint32 index; - bool reusedIndex; - (index, reusedIndex) = _acquireMembership(_msgSender(), idCommitment, userMessageLimit); + bool indexReused; + (index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit); - _register(idCommitment, userMessageLimit, index, reusedIndex); + _register(idCommitment, rateLimit, index, indexReused); } - /// @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 indexReused 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 indexReused) internal { + // FIXME: check this earlier, e.g. as a modifier to register() functions? + 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 (indexReused) { + 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); + // FIXME: not DRY: see register() + uint256 idCommitmentToErase = idCommitments[i]; + MembershipInfo memory membershipToErase = memberships[idCommitmentToErase]; + if (membershipToErase.rateLimit == 0) revert InvalidIdCommitment(idCommitmentToErase); + _eraseMembershipAndSaveSlotToReuse(_msgSender(), idCommitmentToErase, membershipToErase); + LazyIMT.update(merkleTree, 0, membershipToErase.index); } } - /// @notice Withdraw any available balance in tokens after a membership is erased. - /// @param token The address of the token to withdraw. Use 0x000...000 to withdraw ETH + /// @notice Withdraw any available deposit balance in tokens after a membership is erased. + /// @param token The address of the token to withdraw function withdraw(address token) external { _withdraw(_msgSender(), token); } @@ -262,37 +268,38 @@ 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 >= maxMembershipRateLimit); + maxTotalRateLimit = _maxTotalRateLimit; } /// @notice Set the maximum rate limit of one membership - /// @param _maxRateLimitPerMembership new value - function setMaxRateLimitPerMembership(uint32 _maxRateLimitPerMembership) external onlyOwner { - require(_maxRateLimitPerMembership >= minRateLimitPerMembership); - maxRateLimitPerMembership = _maxRateLimitPerMembership; + /// @param _maxMembershipRateLimit new maximum rate limit per membership (messages per epoch) + function setMaxMembershipRateLimit(uint32 _maxMembershipRateLimit) external onlyOwner { + require(_maxMembershipRateLimit >= minMembershipRateLimit); + maxMembershipRateLimit = _maxMembershipRateLimit; } /// @notice Set the minimum rate limit of one membership - /// @param _minRateLimitPerMembership new value - function setMinRateLimitPerMembership(uint32 _minRateLimitPerMembership) external onlyOwner { - require(_minRateLimitPerMembership > 0); - minRateLimitPerMembership = _minRateLimitPerMembership; + /// @param _minMembershipRateLimit new minimum rate limit per membership (messages per epoch) + function setMinMembershipRateLimit(uint32 _minMembershipRateLimit) external onlyOwner { + require(_minMembershipRateLimit > 0); // FIXME: we must also check here that min rate <= max rate + minMembershipRateLimit = _minMembershipRateLimit; } - /// @notice Set the membership expiration term - /// @param _expirationTerm new value - function setExpirationTerm(uint32 _expirationTerm) external onlyOwner { - require(_expirationTerm > 0); - expirationTerm = _expirationTerm; + /// @notice Set the expiration term for new memberships (expiration dates of existing memberships don't change) + /// @param _activeStateDuration new expiration term + function setactiveStateDuration(uint32 _activeStateDuration) external onlyOwner { + require(_activeStateDuration > 0); + activeStateDuration = _activeStateDuration; } - /// @notice Set the membership grace period - /// @param _gracePeriod new value + /// @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 { - gracePeriod = _gracePeriod; + // FIXME: shall we check that _gracePeriod > 0? + gracePeriodDuration = _gracePeriod; } } diff --git a/test/WakuRlnV2.t.sol b/test/WakuRlnV2.t.sol index b178f51..71b205e 100644 --- a/test/WakuRlnV2.t.sol +++ b/test/WakuRlnV2.t.sol @@ -37,19 +37,19 @@ contract WakuRlnV2Test is Test { vm.pauseGasMetering(); // Merkle tree leaves are calculated using 2 as rateLimit vm.prank(w.owner()); - w.setMinRateLimitPerMembership(2); + w.setMinMembershipRateLimit(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.minMembershipRateLimit(); + uint256 maxMembershipRateLimit = w.maxMembershipRateLimit(); + 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.totalRateLimit(), 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.minMembershipRateLimit(); + uint256 maxMembershipRateLimit = w.maxMembershipRateLimit(); + 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,32 +152,32 @@ 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 { uint256 idCommitment = 2; - uint32 invalidMin = w.minRateLimitPerMembership() - 1; - uint32 invalidMax = w.maxRateLimitPerMembership() + 1; + uint32 invalidMin = w.minMembershipRateLimit() - 1; + uint32 invalidMax = w.maxMembershipRateLimit() + 1; vm.expectRevert(abi.encodeWithSelector(InvalidRateLimit.selector)); w.register(idCommitment, invalidMin); @@ -186,26 +186,26 @@ 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.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit() ); - 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 gracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment); - assertFalse(w.isGracePeriod(idCommitment)); + assertFalse(w.isInGracePeriod(idCommitment)); assertFalse(w.isExpired(idCommitment)); - vm.warp(gracePeriodStartDate); + vm.warp(gracePeriodStartTimestamp); - assertTrue(w.isGracePeriod(idCommitment)); + assertTrue(w.isInGracePeriod(idCommitment)); assertFalse(w.isExpired(idCommitment)); uint256[] memory commitmentsToExtend = new uint256[](1); @@ -214,92 +214,92 @@ contract WakuRlnV2Test is Test { // Attempt to extend the membership (but it is not owned by us) address randomAddress = vm.addr(block.timestamp); vm.prank(randomAddress); - vm.expectRevert(abi.encodeWithSelector(NotHolder.selector, commitmentsToExtend[0])); - w.extend(commitmentsToExtend); + vm.expectRevert(abi.encodeWithSelector(AttemptedExtensionByNonHolder.selector, commitmentsToExtend[0])); + 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); + emit MembershipUpgradeable.MembershipExtended(idCommitment, 0, 0, 0); + w.extendMemberships(commitmentsToExtend); - (, uint256 newGracePeriodStartDate,,,,,) = w.members(idCommitment); + (, uint256 newgracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment); - assertEq(block.timestamp + uint256(w.expirationTerm()), newGracePeriodStartDate); - assertFalse(w.isGracePeriod(idCommitment)); + assertEq(block.timestamp + uint256(w.activeStateDuration()), newgracePeriodStartTimestamp); + assertFalse(w.isInGracePeriod(idCommitment)); assertFalse(w.isExpired(idCommitment)); // 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.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit() ); - vm.assume(w.isValidUserMessageLimit(userMessageLimit)); + vm.assume(w.isValidMembershipRateLimit(membershipRateLimit)); vm.resumeGasMetering(); token.approve(address(w), price); - w.register(idCommitment, userMessageLimit); - uint256 ogExpirationDate = w.expirationDate(idCommitment); - (, uint256 gracePeriodStartDate,,,,,) = w.members(idCommitment); + w.register(idCommitment, membershipRateLimit); + uint256 ogExpirationTimestamp = w.membershipExpirationTimestamp(idCommitment); + (, uint256 gracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment); - vm.warp(gracePeriodStartDate); + vm.warp(gracePeriodStartTimestamp); uint256[] memory commitmentsToExtend = new uint256[](1); commitmentsToExtend[0] = idCommitment; // 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); + emit MembershipUpgradeable.MembershipExtended(idCommitment, 0, 0, 0); + w.extendMemberships(commitmentsToExtend); - (, uint256 newGracePeriodStartDate, uint32 newGracePeriod,,,,) = w.members(idCommitment); - uint256 expectedExpirationDate = newGracePeriodStartDate + uint256(newGracePeriod) + 1; - uint256 expirationDate = w.expirationDate(idCommitment); - assertEq(expectedExpirationDate, expirationDate); - assertTrue(expectedExpirationDate > ogExpirationDate); + (, uint256 newgracePeriodStartTimestamp, uint32 newGracePeriod,,,,) = w.memberships(idCommitment); + uint256 expectedExpirationTimestamp = newgracePeriodStartTimestamp + uint256(newGracePeriod) + 1; + uint256 membershipExpirationTimestamp = w.membershipExpirationTimestamp(idCommitment); + assertEq(expectedExpirationTimestamp, membershipExpirationTimestamp); + assertTrue(expectedExpirationTimestamp > ogExpirationTimestamp); } - 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.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit() ); - 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 fetchedgracePeriodStartTimestamp, uint32 fetchedGracePeriod,,,,) = w.memberships(idCommitment); - uint256 expectedExpirationDate = fetchedGracePeriodStartDate + uint256(fetchedGracePeriod) + 1; - uint256 expirationDate = w.expirationDate(idCommitment); + uint256 expectedExpirationTimestamp = fetchedgracePeriodStartTimestamp + uint256(fetchedGracePeriod) + 1; + uint256 membershipExpirationTimestamp = w.membershipExpirationTimestamp(idCommitment); - assertEq(expectedExpirationDate, expirationDate); + assertEq(expectedExpirationTimestamp, membershipExpirationTimestamp); - vm.warp(expirationDate); + vm.warp(membershipExpirationTimestamp); - assertFalse(w.isGracePeriod(idCommitment)); + assertFalse(w.isInGracePeriod(idCommitment)); assertTrue(w.isExpired(idCommitment)); } function test__ValidRegistrationWithEraseList() external { vm.pauseGasMetering(); vm.startPrank(w.owner()); - w.setMinRateLimitPerMembership(20); - w.setMaxRateLimitPerMembership(100); - w.setMaxTotalRateLimitPerEpoch(100); + w.setMinMembershipRateLimit(20); + w.setMaxMembershipRateLimit(100); + w.setMaxTotalRateLimit(100); vm.stopPrank(); vm.resumeGasMetering(); @@ -309,23 +309,23 @@ contract WakuRlnV2Test is Test { token.approve(address(w), priceA); w.register(i, 20); // Make sure they're expired - vm.warp(w.expirationDate(i)); + vm.warp(w.membershipExpirationTimestamp(i)); } - // Time travel to a point in which the last commitment is active - (, uint256 gracePeriodStartDate,,,,,) = w.members(5); - vm.warp(gracePeriodStartDate - 1); + // Time travel to a point in which the last membership is active + (, uint256 gracePeriodStartTimestamp,,,,,) = w.memberships(5); + vm.warp(gracePeriodStartTimestamp - 1); // Ensure that this is the case assertTrue(w.isExpired(4)); assertFalse(w.isExpired(5)); - assertFalse(w.isGracePeriod(5)); + assertFalse(w.isInGracePeriod(5)); (, uint256 priceB) = w.priceCalculator().calculate(60); token.approve(address(w), priceB); // Should fail. There's not enough free rate limit - vm.expectRevert(abi.encodeWithSelector(ExceedAvailableMaxRateLimitPerEpoch.selector)); + vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector)); w.register(6, 60); // Attempt to expire 3 commitments including one that can't be erased (the last one) @@ -340,77 +340,77 @@ contract WakuRlnV2Test is Test { // Attempt to expire 3 commitments that can be erased commitmentsToErase[2] = 4; vm.expectEmit(true, false, false, false); - emit MembershipUpgradeable.MemberExpired(1, 0, 0); + emit MembershipUpgradeable.MembershipExpired(1, 0, 0); vm.expectEmit(true, false, false, false); - emit MembershipUpgradeable.MemberExpired(2, 0, 0); + emit MembershipUpgradeable.MembershipExpired(2, 0, 0); vm.expectEmit(true, false, false, false); - emit MembershipUpgradeable.MemberExpired(4, 0, 0); + emit MembershipUpgradeable.MembershipExpired(4, 0, 0); w.register(6, 60, commitmentsToErase); // 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 - uint256 availableBalance = w.balancesToWithdraw(address(this), address(token)); + uint256 availableBalance = w.depositsToWithdraw(address(this), address(token)); assertEq(availableBalance, priceA * 3); } function test__RegistrationWhenMaxRateLimitIsReached() external { vm.pauseGasMetering(); vm.startPrank(w.owner()); - w.setMinRateLimitPerMembership(1); - w.setMaxRateLimitPerMembership(5); - w.setMaxTotalRateLimitPerEpoch(5); + w.setMinMembershipRateLimit(1); + w.setMaxMembershipRateLimit(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); + vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector)); + 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); + vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector)); + w.register(4, membershipRateLimit); } function test__indexReuse_eraseMemberships(uint32 idCommitmentsLength) external { @@ -422,70 +422,70 @@ 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; } // time travel to the moment we can erase all expired memberships - uint256 expirationDate = w.expirationDate(idCommitmentsLength); - vm.warp(expirationDate); + uint256 membershipExpirationTimestamp = w.membershipExpirationTimestamp(idCommitmentsLength); + vm.warp(membershipExpirationTimestamp); w.eraseMemberships(commitmentsToErase); // Verify that expired indices match what we expect for (uint32 i = 0; i < idCommitmentsLength; i++) { - assertEq(i, w.availableExpiredIndices(i)); + assertEq(i, w.reusableIndicesOfErasedMemberships(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); + uint256 expectedindexReusedPos = idCommitmentsLength - i; + uint32 expectedIndex = w.reusableIndicesOfErasedMemberships(expectedindexReusedPos); 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); + w.reusableIndicesOfErasedMemberships(expectedindexReusedPos); // Should not have been affected - assertEq(currnextCommitmentIndex, w.nextCommitmentIndex()); + assertEq(currnextCommitmentIndex, w.nextFreeIndex()); } // No indexes should be available for reuse vm.expectRevert(); - w.availableExpiredIndices(0); + w.reusableIndicesOfErasedMemberships(0); // 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.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit() ); - 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); } // Expiring the first 3 - uint256 expirationDate = w.expirationDate(idCommitment + 2); - vm.warp(expirationDate); + uint256 membershipExpirationTimestamp = w.membershipExpirationTimestamp(idCommitment + 2); + vm.warp(membershipExpirationTimestamp); for (uint256 i = 0; i < 5; i++) { if (i <= 2) { assertTrue(w.isExpired(idCommitment + i)); @@ -499,23 +499,23 @@ contract WakuRlnV2Test is Test { commitmentsToErase[1] = idCommitment + 2; vm.expectEmit(true, false, false, false); // only check the first parameter of the event (the idCommitment) - emit MembershipUpgradeable.MemberExpired(commitmentsToErase[0], 0, 0); + emit MembershipUpgradeable.MembershipExpired(commitmentsToErase[0], 0, 0); vm.expectEmit(true, false, false, false); // only check the first parameter of the event (the idCommitment) - emit MembershipUpgradeable.MemberExpired(commitmentsToErase[0], 0, 0); + emit MembershipUpgradeable.MembershipExpired(commitmentsToErase[0], 0, 0); w.eraseMemberships(commitmentsToErase); 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); - vm.warp(gracePeriodStartDate - 1); + (, uint256 gracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment + 4); + vm.warp(gracePeriodStartTimestamp - 1); commitmentsToErase[0] = idCommitment; commitmentsToErase[1] = idCommitment + 4; vm.expectRevert(abi.encodeWithSelector(CantEraseMembership.selector, idCommitment + 4)); @@ -525,20 +525,20 @@ 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.minMembershipRateLimit(); + (, 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); } - uint256 expirationDate = w.expirationDate(idCommitmentsLength); - vm.warp(expirationDate); + uint256 membershipExpirationTimestamp = w.membershipExpirationTimestamp(idCommitmentsLength); + vm.warp(membershipExpirationTimestamp); for (uint256 i = 1; i <= 5; i++) { assertTrue(w.isExpired(i)); } @@ -547,44 +547,44 @@ contract WakuRlnV2Test is Test { for (uint256 i = 0; i < idCommitmentsLength; i++) { commitmentsToErase[i] = i + 1; vm.expectEmit(true, false, false, false); // only check the first parameter of the event (the idCommitment) - emit MembershipUpgradeable.MemberExpired(i + 1, 0, 0); + emit MembershipUpgradeable.MembershipExpired(i + 1, 0, 0); } w.eraseMemberships(commitmentsToErase); // 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.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit() ); - 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 gracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment); - vm.warp(gracePeriodStartDate); + vm.warp(gracePeriodStartTimestamp); uint256[] memory commitmentsToErase = new uint256[](1); commitmentsToErase[0] = idCommitment; w.eraseMemberships(commitmentsToErase); - uint256 availableBalance = w.balancesToWithdraw(address(this), address(token)); + uint256 availableBalance = w.depositsToWithdraw(address(this), address(token)); assertEq(availableBalance, price); assertEq(token.balanceOf(address(w)), price); @@ -595,7 +595,7 @@ contract WakuRlnV2Test is Test { uint256 balanceAfterWithdraw = token.balanceOf(address(this)); - availableBalance = w.balancesToWithdraw(address(this), address(token)); + availableBalance = w.depositsToWithdraw(address(this), address(token)); assertEq(availableBalance, 0); assertEq(token.balanceOf(address(w)), 0); assertEq(balanceBeforeWithdraw + price, balanceAfterWithdraw); @@ -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.minMembershipRateLimit(); + (, 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.minMembershipRateLimit(); + (, 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.minMembershipRateLimit(); + (, 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); } }