chore: improve terminology consistency

This commit is contained in:
Sergei Tikhomirov 2024-09-24 10:52:33 +02:00
parent 4fdcdbc73c
commit 4b3f608bee
No known key found for this signature in database
GPG Key ID: 6A1F8ED9D6538027
3 changed files with 324 additions and 324 deletions

View File

@ -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.

View File

@ -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;
}
}

View File

@ -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);
}
}