mirror of
https://github.com/logos-messaging/logos-messaging-rlnv2-contract.git
synced 2026-04-28 22:43:08 +00:00
improve terminology consistency in Membership
This commit is contained in:
parent
4b3f608bee
commit
ad92298a0c
@ -11,98 +11,100 @@ 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
|
||||
/// @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
|
||||
/// @notice Membership expiration term (T in the spec)
|
||||
uint32 public expirationTerm;
|
||||
|
||||
/// @notice Membership grace period
|
||||
uint32 public gracePeriod;
|
||||
/// @notice Membership grace period (G in the spec)
|
||||
uint32 public gracePeriodDuration;
|
||||
|
||||
/// @notice balances available to withdraw
|
||||
/// @notice deposit balances available to withdraw // FIXME: are balances unavailable for withdrawal stored
|
||||
/// elsewhere?
|
||||
mapping(address holder => mapping(address token => uint256 balance)) public balancesToWithdraw;
|
||||
|
||||
/// @notice Total rate limit of all memberships in the tree
|
||||
uint256 public totalRateLimitPerEpoch;
|
||||
/// @notice 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 memberships;
|
||||
mapping(uint256 idCommitment => MembershipInfo membership) public memberships;
|
||||
|
||||
/// @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 expired memberships (can be erased)
|
||||
uint32[] public availableExpiredMembershipsIndices;
|
||||
|
||||
struct MembershipInfo {
|
||||
/// @notice amount of the token used to acquire this membership
|
||||
uint256 amount;
|
||||
/// @notice amount of the token used to make the deposit 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;
|
||||
uint32 gracePeriodDuration;
|
||||
/// @notice the membership rate limit
|
||||
uint32 rateLimit;
|
||||
/// @notice the index of the member in the membership set
|
||||
/// @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
|
||||
/// to not extend it // FIXME: expired or erased?
|
||||
/// @param idCommitment the idCommitment of the 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 membershipRateLimit, uint32 index);
|
||||
/// @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
|
||||
/// @notice Emitted when a membership in its grace period is 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 merkle tree
|
||||
/// @param newExpirationDate the new expiration date of this membership
|
||||
event MemberExtended(uint256 idCommitment, uint32 membershipRateLimit, uint32 index, uint256 newExpirationDate);
|
||||
/// @param index the index of the membership in the membership set
|
||||
/// @param newExpirationTime the new expiration timestamp of this membership
|
||||
event MembershipExtended(uint256 idCommitment, uint32 membershipRateLimit, uint32 index, uint256 newExpirationTime);
|
||||
|
||||
/// @dev contract initializer
|
||||
/// @param _priceCalculator Address of an instance of IPriceCalculator
|
||||
/// @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
|
||||
/// @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 _expirationTerm Expiration term of each membership
|
||||
/// @param _gracePeriodDuration Grace period duration for each membership
|
||||
function __MembershipUpgradeable_init(
|
||||
address _priceCalculator,
|
||||
uint32 _maxTotalRateLimit,
|
||||
uint32 _minRateLimitPerMembership,
|
||||
uint32 _maxRateLimitPerMembership,
|
||||
uint32 _minMembershipRateLimit,
|
||||
uint32 _maxMembershipRateLimit,
|
||||
uint32 _expirationTerm,
|
||||
uint32 _gracePeriod
|
||||
uint32 _gracePeriodDuration
|
||||
)
|
||||
internal
|
||||
onlyInitializing
|
||||
@ -110,61 +112,61 @@ abstract contract MembershipUpgradeable is Initializable {
|
||||
__MembershipUpgradeable_init_unchained(
|
||||
_priceCalculator,
|
||||
_maxTotalRateLimit,
|
||||
_minRateLimitPerMembership,
|
||||
_maxRateLimitPerMembership,
|
||||
_minMembershipRateLimit,
|
||||
_maxMembershipRateLimit,
|
||||
_expirationTerm,
|
||||
_gracePeriod
|
||||
_gracePeriodDuration
|
||||
);
|
||||
}
|
||||
|
||||
function __MembershipUpgradeable_init_unchained(
|
||||
address _priceCalculator,
|
||||
uint32 _maxTotalRateLimit,
|
||||
uint32 _minRateLimitPerMembership,
|
||||
uint32 _maxRateLimitPerMembership,
|
||||
uint32 _minMembershipRateLimit,
|
||||
uint32 _maxMembershipRateLimit,
|
||||
uint32 _expirationTerm,
|
||||
uint32 _gracePeriod
|
||||
uint32 _gracePeriodDuration
|
||||
)
|
||||
internal
|
||||
onlyInitializing
|
||||
{
|
||||
require(_maxTotalRateLimit >= maxRateLimitPerMembership);
|
||||
require(_maxRateLimitPerMembership > minRateLimitPerMembership);
|
||||
require(_minRateLimitPerMembership > 0);
|
||||
require(_expirationTerm > 0);
|
||||
require(_maxTotalRateLimit >= maxMembershipRateLimit);
|
||||
require(_maxMembershipRateLimit > minMembershipRateLimit); // FIXME: > or >=?
|
||||
require(_minMembershipRateLimit > 0);
|
||||
require(_expirationTerm > 0); // FIXME: also _gracePeriodDuration > 0?
|
||||
|
||||
priceCalculator = IPriceCalculator(_priceCalculator);
|
||||
maxTotalRateLimit = _maxTotalRateLimit;
|
||||
maxRateLimitPerMembership = _maxRateLimitPerMembership;
|
||||
minRateLimitPerMembership = _minRateLimitPerMembership;
|
||||
maxMembershipRateLimit = _maxMembershipRateLimit;
|
||||
minMembershipRateLimit = _minMembershipRateLimit;
|
||||
expirationTerm = _expirationTerm;
|
||||
gracePeriod = _gracePeriod;
|
||||
gracePeriodDuration = _gracePeriodDuration;
|
||||
}
|
||||
|
||||
/// @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`
|
||||
/// @notice Checks if a membership rate limit is valid. This does not take into account whether the total
|
||||
/// memberships have reached already the `maxTotalRateLimit` // FIXME: clarify
|
||||
/// @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;
|
||||
return membershipRateLimit >= minMembershipRateLimit && membershipRateLimit <= maxMembershipRateLimit;
|
||||
}
|
||||
|
||||
/// @dev acquire a membership and trasnfer the fees to the contract
|
||||
/// @dev acquire a membership and trasnfer the fees to the contract // FIXME: fees == deposit?
|
||||
/// @param _sender address of the owner of the new membership
|
||||
/// @param _idCommitment the idcommitment of the new membership
|
||||
/// @param _idCommitment the idCommitment of the new membership
|
||||
/// @param _rateLimit the membership rate limit
|
||||
/// @return index the index in the merkle tree
|
||||
/// @return reuseIndex indicates whether a new leaf is being used or if using an existing leaf in the merkle tree
|
||||
/// @return index the index in the membership set
|
||||
/// @return indexReused indicates whether using a new Merkle tree leaf or an existing one
|
||||
function _acquireMembership(
|
||||
address _sender,
|
||||
uint256 _idCommitment,
|
||||
uint32 _rateLimit
|
||||
)
|
||||
internal
|
||||
returns (uint32 index, bool reuseIndex)
|
||||
returns (uint32 index, bool indexReused)
|
||||
{
|
||||
(address token, uint256 amount) = priceCalculator.calculate(_rateLimit);
|
||||
(index, reuseIndex) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount);
|
||||
(index, indexReused) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount);
|
||||
_transferFees(_sender, token, amount);
|
||||
}
|
||||
|
||||
@ -173,147 +175,159 @@ abstract contract MembershipUpgradeable is Initializable {
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// 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: rename to holder?
|
||||
/// @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 reuseIndex 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 reuseIndex)
|
||||
returns (uint32 index, bool indexReused)
|
||||
{
|
||||
if (_rateLimit < minRateLimitPerMembership || _rateLimit > maxRateLimitPerMembership) {
|
||||
if (_rateLimit < minMembershipRateLimit || _rateLimit > maxMembershipRateLimit) {
|
||||
revert InvalidRateLimit();
|
||||
}
|
||||
|
||||
// Determine if we exceed the total rate limit
|
||||
totalRateLimitPerEpoch += _rateLimit;
|
||||
if (totalRateLimitPerEpoch > maxTotalRateLimit) {
|
||||
revert ExceedAvailableMaxRateLimitPerEpoch(); // List is empty or can't
|
||||
totalRateLimit += _rateLimit;
|
||||
if (totalRateLimit > maxTotalRateLimit) {
|
||||
revert ExceededMaxTotalRateLimit();
|
||||
}
|
||||
|
||||
// Reuse available slots from previously removed expired memberships
|
||||
(index, reuseIndex) = _nextIndex();
|
||||
// Reuse available slots from previously removed (FIXME: clarify "removed") expired memberships
|
||||
(index, indexReused) = _getFreeIndex();
|
||||
|
||||
memberships[_idCommitment] = MembershipInfo({
|
||||
holder: _sender,
|
||||
gracePeriodStartDate: block.timestamp + uint256(expirationTerm),
|
||||
gracePeriod: gracePeriod,
|
||||
gracePeriodStartTimestamp: block.timestamp + uint256(expirationTerm),
|
||||
gracePeriodDuration: gracePeriodDuration,
|
||||
token: _token,
|
||||
amount: _amount,
|
||||
depositAmount: _depositAmount,
|
||||
rateLimit: _rateLimit,
|
||||
index: index
|
||||
});
|
||||
}
|
||||
|
||||
/// @dev reuse available slots from previously removed expired memberships
|
||||
/// @return index index to use
|
||||
/// @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;
|
||||
/// @dev Get a free index (possibly from reusing a slot of an expired membership)
|
||||
/// @return index index to be used for another membership registration
|
||||
/// @return indexReused indicates whether index comes form reusing a slot of an expired membership
|
||||
function _getFreeIndex() internal returns (uint32 index, bool indexReused) {
|
||||
// Reuse available slots from previously removed (FIXME: clarify "removed") expired memberships
|
||||
uint256 arrLen = availableExpiredMembershipsIndices.length;
|
||||
if (arrLen != 0) {
|
||||
index = availableExpiredIndices[arrLen - 1];
|
||||
availableExpiredIndices.pop();
|
||||
reuseIndex = true;
|
||||
index = availableExpiredMembershipsIndices[arrLen - 1];
|
||||
availableExpiredMembershipsIndices.pop();
|
||||
indexReused = true;
|
||||
} else {
|
||||
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 = memberships[_idCommitment];
|
||||
MembershipInfo storage membership = memberships[_idCommitment];
|
||||
|
||||
if (!_isGracePeriod(mdetails.gracePeriodStartDate, mdetails.gracePeriod)) {
|
||||
if (!_isInGracePeriodNow(membership.gracePeriodStartTimestamp, membership.gracePeriodDuration)) {
|
||||
revert NotInGracePeriod(_idCommitment);
|
||||
}
|
||||
|
||||
if (_sender != mdetails.holder) revert NotHolder(_idCommitment);
|
||||
if (_sender != membership.holder) revert AttemptedExtensionByNonHolder(_idCommitment); // FIXME: turn into a
|
||||
// modifier?
|
||||
// FIXME: see spec: should extension depend on the current block.timestamp?
|
||||
uint256 newGracePeriodStartTimestamp = block.timestamp + uint256(expirationTerm);
|
||||
|
||||
uint256 gracePeriodStartDate = block.timestamp + uint256(expirationTerm);
|
||||
membership.gracePeriodStartTimestamp = newGracePeriodStartTimestamp;
|
||||
membership.gracePeriodDuration = gracePeriodDuration; // FIXME: redundant: just assigns old value
|
||||
|
||||
mdetails.gracePeriodStartDate = gracePeriodStartDate;
|
||||
mdetails.gracePeriod = gracePeriod;
|
||||
|
||||
emit MemberExtended(_idCommitment, mdetails.rateLimit, 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 = memberships[_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 = memberships[_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) {
|
||||
/// @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 _isInGracePeriodNow(
|
||||
uint256 _gracePeriodStartTimestamp,
|
||||
uint32 _gracePeriodDuration
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
uint256 blockTimestamp = block.timestamp;
|
||||
return
|
||||
blockTimestamp >= _gracePeriodStartDate && blockTimestamp <= _gracePeriodStartDate + uint256(_gracePeriod);
|
||||
return blockTimestamp >= _gracePeriodStartTimestamp
|
||||
&& blockTimestamp <= _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 = memberships[_idCommitment];
|
||||
return _isGracePeriod(m.gracePeriodStartDate, m.gracePeriod);
|
||||
function isInGracePeriodNow(uint256 _idCommitment) public view returns (bool) {
|
||||
MembershipInfo memory membership = memberships[_idCommitment];
|
||||
return _isInGracePeriodNow(membership.gracePeriodStartTimestamp, membership.gracePeriodDuration);
|
||||
}
|
||||
|
||||
/// @dev Erase 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 _eraseMembership(address _sender, uint256 _idCommitment, MembershipInfo memory _membership) internal {
|
||||
bool membershipExpired = _isExpired(_membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration);
|
||||
bool isInGracePeriodAndOwned = // FIXME: separate into two checks? cf. short-circuit
|
||||
_isInGracePeriodNow(_membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration)
|
||||
&& _membership.holder == _sender;
|
||||
// FIXME: we already had a non-holder check: reuse it here as a modifier
|
||||
if (!membershipExpired && !isInGracePeriodAndOwned) revert CantEraseMembership(_idCommitment);
|
||||
|
||||
if (!membershipExpired && !isGracePeriodAndOwned) revert CantEraseMembership(_idCommitment);
|
||||
|
||||
emit MemberExpired(_idCommitment, _mdetails.rateLimit, _mdetails.index);
|
||||
emit MembershipExpired(_idCommitment, _membership.rateLimit, _membership.index);
|
||||
|
||||
// Move balance from expired membership to holder balance
|
||||
balancesToWithdraw[_mdetails.holder][_mdetails.token] += _mdetails.amount;
|
||||
balancesToWithdraw[_membership.holder][_membership.token] += _membership.depositAmount;
|
||||
|
||||
// Deduct the expired membership rate limit
|
||||
totalRateLimitPerEpoch -= _mdetails.rateLimit;
|
||||
totalRateLimit -= _membership.rateLimit;
|
||||
|
||||
availableExpiredIndices.push(_mdetails.index);
|
||||
// Note: the Merkle tree data will be erased lazily later // FIXME: when?
|
||||
availableExpiredMembershipsIndices.push(_membership.index);
|
||||
|
||||
delete memberships[_idCommitment];
|
||||
}
|
||||
|
||||
/// @dev Withdraw any available 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");
|
||||
|
||||
|
||||
@ -62,15 +62,15 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
/// @dev contract initializer
|
||||
/// @param _priceCalculator Address of an instance of IPriceCalculator
|
||||
/// @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 _minMembershipRateLimit Minimum rate limit of one membership
|
||||
/// @param _maxMembershipRateLimit Maximum rate limit of one membership
|
||||
/// @param _expirationTerm Membership expiration term
|
||||
/// @param _gracePeriod Membership grace period
|
||||
function initialize(
|
||||
address _priceCalculator,
|
||||
uint32 _maxTotalRateLimit,
|
||||
uint32 _minRateLimitPerMembership,
|
||||
uint32 _maxRateLimitPerMembership,
|
||||
uint32 _minMembershipRateLimit,
|
||||
uint32 _maxMembershipRateLimit,
|
||||
uint32 _expirationTerm,
|
||||
uint32 _gracePeriod
|
||||
)
|
||||
@ -82,8 +82,8 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
__MembershipUpgradeable_init(
|
||||
_priceCalculator,
|
||||
_maxTotalRateLimit,
|
||||
_minRateLimitPerMembership,
|
||||
_maxRateLimitPerMembership,
|
||||
_minMembershipRateLimit,
|
||||
_maxMembershipRateLimit,
|
||||
_expirationTerm,
|
||||
_gracePeriod
|
||||
);
|
||||
@ -137,10 +137,10 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
if (membershipExists(idCommitment)) revert DuplicateIdCommitment();
|
||||
|
||||
uint32 index;
|
||||
bool reuseIndex;
|
||||
(index, reuseIndex) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
|
||||
bool indexReused;
|
||||
(index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
|
||||
|
||||
_register(idCommitment, rateLimit, index, reuseIndex);
|
||||
_register(idCommitment, rateLimit, index, indexReused);
|
||||
}
|
||||
|
||||
/// @notice Register a membership
|
||||
@ -166,23 +166,23 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
}
|
||||
|
||||
uint32 index;
|
||||
bool reuseIndex;
|
||||
(index, reuseIndex) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
|
||||
bool indexReused;
|
||||
(index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
|
||||
|
||||
_register(idCommitment, rateLimit, index, reuseIndex);
|
||||
_register(idCommitment, rateLimit, index, indexReused);
|
||||
}
|
||||
|
||||
/// @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
|
||||
/// @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 reuseIndex) internal {
|
||||
function _register(uint256 idCommitment, uint32 rateLimit, uint32 index, bool indexReused) internal {
|
||||
if (nextFreeIndex >= MAX_MEMBERSHIP_SET_SIZE) revert FullMembershipSet();
|
||||
|
||||
uint256 rateCommitment = PoseidonT3.hash([idCommitment, rateLimit]);
|
||||
if (reuseIndex) {
|
||||
if (indexReused) {
|
||||
LazyIMT.update(merkleTree, rateCommitment, index);
|
||||
} else {
|
||||
LazyIMT.insert(merkleTree, rateCommitment);
|
||||
@ -241,7 +241,8 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
/// 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++) { // FIXME: not DRY: see register()
|
||||
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);
|
||||
@ -264,23 +265,23 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
|
||||
/// @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);
|
||||
function setMaxTotalRateLimit(uint32 _maxTotalRateLimit) external onlyOwner {
|
||||
require(_maxTotalRateLimit >= maxMembershipRateLimit);
|
||||
maxTotalRateLimit = _maxTotalRateLimit;
|
||||
}
|
||||
|
||||
/// @notice Set the maximum rate limit of one membership
|
||||
/// @param _maxRateLimitPerMembership new maximum rate limit per membership (messages per epoch)
|
||||
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 minimum rate limit per membership (messages per epoch)
|
||||
function setMinRateLimitPerMembership(uint32 _minRateLimitPerMembership) external onlyOwner {
|
||||
require(_minRateLimitPerMembership > 0); // FIXME: we must also check here that min rate <= max rate
|
||||
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 expiration term for new memberships (expiration dates of existing memberships don't change)
|
||||
@ -292,7 +293,8 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
|
||||
|
||||
/// @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;
|
||||
function setGracePeriod(uint32 _gracePeriod) external onlyOwner {
|
||||
// FIXME: shall we check that _gracePeriod > 0?
|
||||
gracePeriodDuration = _gracePeriod;
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ 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 membershipRateLimit = 2;
|
||||
@ -59,8 +59,7 @@ 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 fetchedMembershipRateLimit2, uint32 index2, uint256 rateCommitment2) =
|
||||
w.getMembershipInfo(idCommitment);
|
||||
(uint32 fetchedMembershipRateLimit2, uint32 index2, uint256 rateCommitment2) = w.getMembershipInfo(idCommitment);
|
||||
assertEq(fetchedMembershipRateLimit2, membershipRateLimit);
|
||||
assertEq(index2, 0);
|
||||
assertEq(rateCommitment2, rateCommitment);
|
||||
@ -97,8 +96,8 @@ contract WakuRlnV2Test is Test {
|
||||
vm.pauseGasMetering();
|
||||
uint256 idCommitment = 2;
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
uint256 minMembershipRateLimit = w.minRateLimitPerMembership();
|
||||
uint256 maxMembershipRateLimit = w.maxRateLimitPerMembership();
|
||||
uint256 minMembershipRateLimit = w.minMembershipRateLimit();
|
||||
uint256 maxMembershipRateLimit = w.maxMembershipRateLimit();
|
||||
vm.assume(membershipRateLimit >= minMembershipRateLimit && membershipRateLimit <= maxMembershipRateLimit);
|
||||
vm.assume(w.isValidMembershipRateLimit(membershipRateLimit));
|
||||
vm.resumeGasMetering();
|
||||
@ -115,7 +114,7 @@ contract WakuRlnV2Test is Test {
|
||||
assertEq(fetchedRateCommitment, rateCommitment);
|
||||
|
||||
assertEq(token.balanceOf(address(w)), price);
|
||||
assertEq(w.totalRateLimitPerEpoch(), membershipRateLimit);
|
||||
assertEq(w.totalRateLimit(), membershipRateLimit);
|
||||
}
|
||||
|
||||
function test__LinearPriceCalculation(uint32 membershipRateLimit) external view {
|
||||
@ -129,8 +128,8 @@ contract WakuRlnV2Test is Test {
|
||||
|
||||
function test__InvalidTokenAmount(uint256 idCommitment, uint32 membershipRateLimit) external {
|
||||
vm.pauseGasMetering();
|
||||
uint256 minMembershipRateLimit = w.minRateLimitPerMembership();
|
||||
uint256 maxMembershipRateLimit = w.maxRateLimitPerMembership();
|
||||
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);
|
||||
@ -176,8 +175,8 @@ contract WakuRlnV2Test is Test {
|
||||
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);
|
||||
@ -191,21 +190,21 @@ contract WakuRlnV2Test is Test {
|
||||
uint256 idCommitment = 2;
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.assume(
|
||||
membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership()
|
||||
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
|
||||
);
|
||||
vm.assume(w.isValidMembershipRateLimit(membershipRateLimit));
|
||||
vm.resumeGasMetering();
|
||||
|
||||
token.approve(address(w), price);
|
||||
w.register(idCommitment, membershipRateLimit);
|
||||
(, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment);
|
||||
(, uint256 gracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment);
|
||||
|
||||
assertFalse(w.isGracePeriod(idCommitment));
|
||||
assertFalse(w.isInGracePeriodNow(idCommitment));
|
||||
assertFalse(w.isExpired(idCommitment));
|
||||
|
||||
vm.warp(gracePeriodStartDate);
|
||||
vm.warp(gracePeriodStartTimestamp);
|
||||
|
||||
assertTrue(w.isGracePeriod(idCommitment));
|
||||
assertTrue(w.isInGracePeriodNow(idCommitment));
|
||||
assertFalse(w.isExpired(idCommitment));
|
||||
|
||||
uint256[] memory commitmentsToExtend = new uint256[](1);
|
||||
@ -214,18 +213,18 @@ 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]));
|
||||
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);
|
||||
emit MembershipUpgradeable.MembershipExtended(idCommitment, 0, 0, 0);
|
||||
w.extendMemberships(commitmentsToExtend);
|
||||
|
||||
(, uint256 newGracePeriodStartDate,,,,,) = w.memberships(idCommitment);
|
||||
(, uint256 newgracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment);
|
||||
|
||||
assertEq(block.timestamp + uint256(w.expirationTerm()), newGracePeriodStartDate);
|
||||
assertFalse(w.isGracePeriod(idCommitment));
|
||||
assertEq(block.timestamp + uint256(w.expirationTerm()), newgracePeriodStartTimestamp);
|
||||
assertFalse(w.isInGracePeriodNow(idCommitment));
|
||||
assertFalse(w.isExpired(idCommitment));
|
||||
|
||||
// Attempt to extend a non grace period membership
|
||||
@ -241,31 +240,31 @@ contract WakuRlnV2Test is Test {
|
||||
uint256 idCommitment = 2;
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.assume(
|
||||
membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership()
|
||||
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
|
||||
);
|
||||
vm.assume(w.isValidMembershipRateLimit(membershipRateLimit));
|
||||
vm.resumeGasMetering();
|
||||
|
||||
token.approve(address(w), price);
|
||||
w.register(idCommitment, membershipRateLimit);
|
||||
uint256 ogExpirationDate = w.expirationDate(idCommitment);
|
||||
(, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment);
|
||||
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);
|
||||
emit MembershipUpgradeable.MembershipExtended(idCommitment, 0, 0, 0);
|
||||
w.extendMemberships(commitmentsToExtend);
|
||||
|
||||
(, uint256 newGracePeriodStartDate, uint32 newGracePeriod,,,,) = w.memberships(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 membershipRateLimit) external {
|
||||
@ -273,7 +272,7 @@ contract WakuRlnV2Test is Test {
|
||||
uint256 idCommitment = 2;
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.assume(
|
||||
membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership()
|
||||
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
|
||||
);
|
||||
vm.assume(w.isValidMembershipRateLimit(membershipRateLimit));
|
||||
vm.resumeGasMetering();
|
||||
@ -281,25 +280,25 @@ contract WakuRlnV2Test is Test {
|
||||
token.approve(address(w), price);
|
||||
w.register(idCommitment, membershipRateLimit);
|
||||
|
||||
(, uint256 fetchedGracePeriodStartDate, uint32 fetchedGracePeriod,,,,) = w.memberships(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.isInGracePeriodNow(idCommitment));
|
||||
assertTrue(w.isExpired(idCommitment));
|
||||
}
|
||||
|
||||
function test__ValidRegistrationWithEraseList() external {
|
||||
vm.pauseGasMetering();
|
||||
vm.startPrank(w.owner());
|
||||
w.setMinRateLimitPerMembership(20);
|
||||
w.setMaxRateLimitPerMembership(100);
|
||||
w.setmaxTotalRateLimit(100);
|
||||
w.setMinMembershipRateLimit(20);
|
||||
w.setMaxMembershipRateLimit(100);
|
||||
w.setMaxTotalRateLimit(100);
|
||||
vm.stopPrank();
|
||||
vm.resumeGasMetering();
|
||||
|
||||
@ -309,23 +308,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 membership is active
|
||||
(, uint256 gracePeriodStartDate,,,,,) = w.memberships(5);
|
||||
vm.warp(gracePeriodStartDate - 1);
|
||||
(, 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.isInGracePeriodNow(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,11 +339,11 @@ 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
|
||||
@ -370,9 +369,9 @@ contract WakuRlnV2Test is Test {
|
||||
function test__RegistrationWhenMaxRateLimitIsReached() external {
|
||||
vm.pauseGasMetering();
|
||||
vm.startPrank(w.owner());
|
||||
w.setMinRateLimitPerMembership(1);
|
||||
w.setMaxRateLimitPerMembership(5);
|
||||
w.setmaxTotalRateLimit(5);
|
||||
w.setMinMembershipRateLimit(1);
|
||||
w.setMaxMembershipRateLimit(5);
|
||||
w.setMaxTotalRateLimit(5);
|
||||
vm.stopPrank();
|
||||
vm.resumeGasMetering();
|
||||
|
||||
@ -396,7 +395,7 @@ contract WakuRlnV2Test is Test {
|
||||
membershipRateLimit = 2;
|
||||
(, price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
token.approve(address(w), price);
|
||||
vm.expectRevert(abi.encodeWithSelector(ExceedAvailableMaxRateLimitPerEpoch.selector));
|
||||
vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector));
|
||||
w.register(3, membershipRateLimit);
|
||||
|
||||
// Should register succesfully
|
||||
@ -409,7 +408,7 @@ contract WakuRlnV2Test is Test {
|
||||
membershipRateLimit = 1;
|
||||
(, price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
token.approve(address(w), price);
|
||||
vm.expectRevert(abi.encodeWithSelector(ExceedAvailableMaxRateLimitPerEpoch.selector));
|
||||
vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector));
|
||||
w.register(4, membershipRateLimit);
|
||||
}
|
||||
|
||||
@ -428,34 +427,34 @@ contract WakuRlnV2Test is Test {
|
||||
}
|
||||
|
||||
// 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.availableExpiredMembershipsIndices(i));
|
||||
}
|
||||
|
||||
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.availableExpiredMembershipsIndices(expectedindexReusedPos);
|
||||
token.approve(address(w), price);
|
||||
w.register(idCommitment, 20);
|
||||
(,,,, index,,) = w.memberships(idCommitment);
|
||||
assertEq(expectedIndex, index);
|
||||
// Should have been removed from the list
|
||||
vm.expectRevert();
|
||||
w.availableExpiredIndices(expectedReusedIndexPos);
|
||||
w.availableExpiredMembershipsIndices(expectedindexReusedPos);
|
||||
// Should not have been affected
|
||||
assertEq(currnextCommitmentIndex, w.nextFreeIndex());
|
||||
}
|
||||
|
||||
// No indexes should be available for reuse
|
||||
vm.expectRevert();
|
||||
w.availableExpiredIndices(0);
|
||||
w.availableExpiredMembershipsIndices(0);
|
||||
|
||||
// Should use a new index since we got rid of all available indexes
|
||||
token.approve(address(w), price);
|
||||
@ -470,7 +469,7 @@ contract WakuRlnV2Test is Test {
|
||||
uint256 idCommitment = 2;
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.assume(
|
||||
membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership()
|
||||
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
|
||||
);
|
||||
vm.assume(w.isValidMembershipRateLimit(membershipRateLimit));
|
||||
vm.resumeGasMetering();
|
||||
@ -484,8 +483,8 @@ contract WakuRlnV2Test is Test {
|
||||
}
|
||||
|
||||
// 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,9 +498,9 @@ 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;
|
||||
@ -514,8 +513,8 @@ contract WakuRlnV2Test is Test {
|
||||
|
||||
// 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.memberships(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,7 +524,7 @@ contract WakuRlnV2Test is Test {
|
||||
function test__RemoveAllExpiredMemberships(uint32 idCommitmentsLength) external {
|
||||
vm.pauseGasMetering();
|
||||
vm.assume(idCommitmentsLength > 1 && idCommitmentsLength <= 100);
|
||||
uint32 membershipRateLimit = w.minRateLimitPerMembership();
|
||||
uint32 membershipRateLimit = w.minMembershipRateLimit();
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.resumeGasMetering();
|
||||
|
||||
@ -537,8 +536,8 @@ contract WakuRlnV2Test is Test {
|
||||
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,7 +546,7 @@ 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);
|
||||
@ -568,7 +567,7 @@ contract WakuRlnV2Test is Test {
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
token.mint(address(this), price);
|
||||
vm.assume(
|
||||
membershipRateLimit >= w.minRateLimitPerMembership() && membershipRateLimit <= w.maxRateLimitPerMembership()
|
||||
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
|
||||
);
|
||||
vm.assume(w.isValidMembershipRateLimit(membershipRateLimit));
|
||||
vm.resumeGasMetering();
|
||||
@ -576,9 +575,9 @@ contract WakuRlnV2Test is Test {
|
||||
token.approve(address(w), price);
|
||||
w.register(idCommitment, membershipRateLimit);
|
||||
|
||||
(, uint256 gracePeriodStartDate,,,,,) = w.memberships(idCommitment);
|
||||
(, uint256 gracePeriodStartTimestamp,,,,,) = w.memberships(idCommitment);
|
||||
|
||||
vm.warp(gracePeriodStartDate);
|
||||
vm.warp(gracePeriodStartTimestamp);
|
||||
|
||||
uint256[] memory commitmentsToErase = new uint256[](1);
|
||||
commitmentsToErase[0] = idCommitment;
|
||||
@ -604,7 +603,7 @@ contract WakuRlnV2Test is Test {
|
||||
function test__InvalidRegistration__DuplicateIdCommitment() external {
|
||||
vm.pauseGasMetering();
|
||||
uint256 idCommitment = 2;
|
||||
uint32 membershipRateLimit = w.minRateLimitPerMembership();
|
||||
uint32 membershipRateLimit = w.minMembershipRateLimit();
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.resumeGasMetering();
|
||||
|
||||
@ -664,7 +663,7 @@ contract WakuRlnV2Test is Test {
|
||||
function test__ValidPaginationQuery__OneElement() external {
|
||||
vm.pauseGasMetering();
|
||||
uint256 idCommitment = 1;
|
||||
uint32 membershipRateLimit = w.minRateLimitPerMembership();
|
||||
uint32 membershipRateLimit = w.minMembershipRateLimit();
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
vm.resumeGasMetering();
|
||||
|
||||
@ -679,7 +678,7 @@ contract WakuRlnV2Test is Test {
|
||||
function test__ValidPaginationQuery(uint32 idCommitmentsLength) external {
|
||||
vm.pauseGasMetering();
|
||||
vm.assume(idCommitmentsLength > 0 && idCommitmentsLength <= 100);
|
||||
uint32 membershipRateLimit = w.minRateLimitPerMembership();
|
||||
uint32 membershipRateLimit = w.minMembershipRateLimit();
|
||||
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
|
||||
|
||||
for (uint256 i = 0; i < idCommitmentsLength; i++) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user