refactor, minor fixes

This commit is contained in:
Sergei Tikhomirov 2024-09-27 20:24:03 +02:00
parent ce52272102
commit eedd9288f2
No known key found for this signature in database
GPG Key ID: 6A1F8ED9D6538027
3 changed files with 115 additions and 144 deletions

View File

@ -7,27 +7,26 @@ import { SafeERC20 } from "openzeppelin-contracts/contracts/token/ERC20/utils/Sa
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
// The specified rate limit was not correct or within the expected limits
error InvalidRateLimit();
error InvalidMembershipRateLimit();
// It's not possible to acquire the rate limit due to exceeding the expected limits
// even after attempting to erase expired memberships
error ExceededMaxTotalRateLimit();
// This membership is not in grace period yet // FIXME: yet or also already?
// This membership is not in grace period
error NotInGracePeriod(uint256 idCommitment);
// The sender is not the holder of the membership
error AttemptedExtensionByNonHolder(uint256 idCommitment);
// 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);
// This membership cannot be erased
error CannotEraseMembership(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; // FIXME: naming: price vs deposit?
IPriceCalculator public depositAmountCalculator;
/// @notice Maximum total rate limit of all memberships in the membership set (messages per epoch)
uint32 public maxTotalRateLimit;
@ -42,7 +41,7 @@ abstract contract MembershipUpgradeable is Initializable {
uint32 public activeStateDuration;
/// @notice Membership grace period duration (G in the spec)
uint32 public gracePeriodDuration;
uint32 public gracePeriodDurationForNewMemberships;
/// @notice deposits available for withdrawal
/// Deposits unavailable for withdrawal are stored in MembershipInfo.
@ -65,8 +64,8 @@ abstract contract MembershipUpgradeable is Initializable {
uint256 depositAmount;
/// @notice timestamp of when the grace period starts for this membership
uint256 gracePeriodStartTimestamp;
/// @notice duration of the grace period
uint32 gracePeriodDuration; // FIXME: does each membership need to store it if it's a global constant?
/// @notice duration of the grace period for this membership
uint32 gracePeriodDuration;
/// @notice the membership rate limit
uint32 rateLimit;
/// @notice the index of the membership in the membership set
@ -138,16 +137,17 @@ abstract contract MembershipUpgradeable is Initializable {
onlyInitializing
{
require(0 < _minMembershipRateLimit);
require(_minMembershipRateLimit <= _maxMembershipRateLimit); // FIXME: < or <=?
require(_minMembershipRateLimit <= _maxMembershipRateLimit);
require(_maxMembershipRateLimit <= _maxTotalRateLimit);
require(_activeStateDuration > 0); // FIXME: also _gracePeriodDuration > 0?
require(_activeStateDuration > 0);
// Note: grace period duration may be equal to zero
priceCalculator = IPriceCalculator(_priceCalculator);
depositAmountCalculator = IPriceCalculator(_priceCalculator);
maxTotalRateLimit = _maxTotalRateLimit;
minMembershipRateLimit = _minMembershipRateLimit;
maxMembershipRateLimit = _maxMembershipRateLimit;
activeStateDuration = _activeStateDuration;
gracePeriodDuration = _gracePeriodDuration;
gracePeriodDurationForNewMemberships = _gracePeriodDuration;
}
/// @notice Checks if a rate limit is within the allowed bounds
@ -171,69 +171,40 @@ abstract contract MembershipUpgradeable is Initializable {
internal
returns (uint32 index, bool indexReused)
{
// Check if the rate limit is valid
if (!isValidMembershipRateLimit(_rateLimit)) {
revert InvalidRateLimit();
revert InvalidMembershipRateLimit();
}
(address token, uint256 amount) = priceCalculator.calculate(_rateLimit);
(index, indexReused) = _setupMembershipDetails(_sender, _idCommitment, _rateLimit, token, amount);
_transferDepositToContract(_sender, token, amount);
}
// FIXME: do we need this as a separate function? (it's not called anywhere else)
function _transferDepositToContract(address _from, address _token, uint256 _amount) internal {
IERC20(_token).safeTransferFrom(_from, address(this), _amount);
}
/// @dev Setup a new membership. If there are not enough remaining rate limit to acquire
/// a new membership, it will attempt to erase existing expired memberships
/// and reuse one of their slots
/// @param _sender holder of the membership. Generally `msg.sender` // FIXME: keeper?
/// @param _idCommitment idCommitment
/// @param _rateLimit membership rate limit
/// @param _token Address of the token used to acquire the membership
/// @param _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 _depositAmount
)
internal
returns (uint32 index, bool indexReused)
{
// Determine if we exceed the total rate limit
totalRateLimit += _rateLimit;
if (totalRateLimit > maxTotalRateLimit) {
revert ExceededMaxTotalRateLimit();
}
// FIXME: check if we even need to reuse an expired membership?
(address token, uint256 depositAmount) = depositAmountCalculator.calculate(_rateLimit);
// Reuse available expired memberships
// Possibly reuse an index of an available erased membership
(index, indexReused) = _getFreeIndex();
// FIXME: we must check that the rate limit of the reused membership is sufficient
// otherwise, the total rate limit may become too high
memberships[_idCommitment] = MembershipInfo({
holder: _sender, // FIXME: keeper?
gracePeriodStartTimestamp: block.timestamp + uint256(activeStateDuration),
gracePeriodDuration: gracePeriodDuration,
token: _token,
depositAmount: _depositAmount,
gracePeriodDuration: gracePeriodDurationForNewMemberships,
token: token,
depositAmount: depositAmount,
rateLimit: _rateLimit,
index: index
});
IERC20(token).safeTransferFrom(_sender, address(this), depositAmount);
}
/// @dev Get a free index (possibly from reusing an index of an erased membership)
/// @return index index to be used for another membership registration
/// @return indexReused indicates whether index comes form reusing a slot of an erased membership
/// @return indexReused indicates whether index was reused from an erased membership
function _getFreeIndex() internal returns (uint32 index, bool indexReused) {
// Reuse the last membership marked as reusable
// Reuse the last erased membership
uint256 numIndices = reusableIndicesOfErasedMemberships.length;
if (numIndices != 0) {
index = reusableIndicesOfErasedMemberships[numIndices - 1];
@ -253,13 +224,13 @@ abstract contract MembershipUpgradeable is Initializable {
if (!_isInGracePeriod(membership.gracePeriodStartTimestamp, membership.gracePeriodDuration)) {
revert NotInGracePeriod(_idCommitment);
}
// FIXME: turn into a modifier?
if (_sender != membership.holder) revert AttemptedExtensionByNonHolder(_idCommitment);
// FIXME: see spec: should extension depend on the current block.timestamp?
uint256 newGracePeriodStartTimestamp = block.timestamp + uint256(activeStateDuration);
membership.gracePeriodStartTimestamp = newGracePeriodStartTimestamp;
membership.gracePeriodDuration = gracePeriodDuration; // FIXME: redundant: just assigns old value
emit MembershipExtended(
_idCommitment, membership.rateLimit, membership.index, membership.gracePeriodStartTimestamp
@ -323,11 +294,13 @@ abstract contract MembershipUpgradeable is Initializable {
internal
{
bool membershipExpired = _isExpired(_membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration);
bool membershipIsInGracePeriodAndHeld = _isInGracePeriod(
_membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration
) && _membership.holder == _sender;
// FIXME: we already had a non-holder check: reuse it here as a modifier?
if (!membershipExpired && !membershipIsInGracePeriodAndHeld) revert CantEraseMembership(_idCommitment);
bool membershipIsInGracePeriod =
_isInGracePeriod(_membership.gracePeriodStartTimestamp, _membership.gracePeriodDuration);
bool isHolder = (_membership.holder == _sender);
if (!membershipExpired && !(membershipIsInGracePeriod && isHolder)) {
revert CannotEraseMembership(_idCommitment);
}
// Move deposit balance from the membership to be erased to holder deposit balance
depositsToWithdraw[_membership.holder][_membership.token] += _membership.depositAmount;

View File

@ -11,18 +11,12 @@ import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils
import { MembershipUpgradeable } from "./Membership.sol";
import { IPriceCalculator } from "./IPriceCalculator.sol";
/// The membership set is full
error FullMembershipSet();
/// A membership with this idCommitment is already registered
error DuplicateIdCommitment();
/// Invalid idCommitment
error InvalidIdCommitment(uint256 idCommitment);
/// Invalid membership rate limit // FIXME: this is not used - remove?
error InvalidMembershipRateLimit(uint32 rateLimit);
/// Invalid pagination query
error InvalidPaginationQuery(uint256 startIndex, uint256 endIndex);
@ -55,13 +49,26 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
_;
}
/// @notice the modifier to check that the membership with this idCommitment doesn't already exist
/// @param idCommitment The idCommitment of the membership
modifier noDuplicateMembership(uint256 idCommitment) {
require(!membershipExists(idCommitment), "Duplicate idCommitment: membership already exists");
_;
}
/// @notice the modifier to check that the membership set is not full
modifier membershipSetNotFull() {
require(nextFreeIndex < MAX_MEMBERSHIP_SET_SIZE, "Membership set is full");
_;
}
constructor() {
_disableInitializers();
}
/// @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 _maxTotalRateLimit Maximum total rate limit of all memberships in the membership set
/// @param _minMembershipRateLimit Minimum rate limit of one membership
/// @param _maxMembershipRateLimit Maximum rate limit of one membership
/// @param _activeStateDuration Membership expiration term
@ -133,15 +140,16 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
/// @notice Register a membership
/// @param idCommitment The idCommitment of the new membership
/// @param rateLimit The rate limit of the new membership
function register(uint256 idCommitment, uint32 rateLimit) external onlyValidIdCommitment(idCommitment) {
// FIXME: turn into modifier?
if (membershipExists(idCommitment)) revert DuplicateIdCommitment();
uint32 index;
bool indexReused;
(index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
_register(idCommitment, rateLimit, index, indexReused);
function register(
uint256 idCommitment,
uint32 rateLimit
)
external
onlyValidIdCommitment(idCommitment)
noDuplicateMembership(idCommitment)
membershipSetNotFull
{
_register(idCommitment, rateLimit);
}
/// @notice Register a membership
@ -155,11 +163,16 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
)
external
onlyValidIdCommitment(idCommitment)
noDuplicateMembership(idCommitment)
membershipSetNotFull
{
// FIXME: turn into modifier?
if (membershipExists(idCommitment)) revert DuplicateIdCommitment();
_eraseMemberships(idCommitmentsToErase);
_register(idCommitment, rateLimit);
}
// FIXME: extract in a separate function?
/// @dev Erase memberships from the list of idCommitments
/// @param idCommitmentsToErase The idCommitments to erase
function _eraseMemberships(uint256[] calldata idCommitmentsToErase) internal {
for (uint256 i = 0; i < idCommitmentsToErase.length; i++) {
uint256 idCommitmentToErase = idCommitmentsToErase[i];
MembershipInfo memory membershipToErase = memberships[idCommitmentToErase];
@ -167,24 +180,15 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
_eraseMembershipAndSaveSlotToReuse(_msgSender(), idCommitmentToErase, membershipToErase);
LazyIMT.update(merkleTree, 0, membershipToErase.index);
}
// FIXME: code repeats cf. register()
uint32 index;
bool indexReused;
(index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
_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 indexReused Indicates whether we're inserting a new element in the Merkle tree or updating a existing
/// element
function _register(uint256 idCommitment, uint32 rateLimit, uint32 index, bool indexReused) internal {
// FIXME: check this earlier, e.g. as a modifier to register() functions?
if (nextFreeIndex >= MAX_MEMBERSHIP_SET_SIZE) revert FullMembershipSet();
function _register(uint256 idCommitment, uint32 rateLimit) internal {
uint32 index;
bool indexReused;
(index, indexReused) = _acquireMembership(_msgSender(), idCommitment, rateLimit);
uint256 rateCommitment = PoseidonT3.hash([idCommitment, rateLimit]);
if (indexReused) {
@ -246,14 +250,7 @@ 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()
uint256 idCommitmentToErase = idCommitments[i];
MembershipInfo memory membershipToErase = memberships[idCommitmentToErase];
if (membershipToErase.rateLimit == 0) revert InvalidIdCommitment(idCommitmentToErase);
_eraseMembershipAndSaveSlotToReuse(_msgSender(), idCommitmentToErase, membershipToErase);
LazyIMT.update(merkleTree, 0, membershipToErase.index);
}
_eraseMemberships(idCommitments);
}
/// @notice Withdraw any available deposit balance in tokens after a membership is erased.
@ -264,11 +261,11 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
/// @notice Set the address of the price calculator
/// @param _priceCalculator new price calculator address
function setPriceCalculator(address _priceCalculator) external onlyOwner {
priceCalculator = IPriceCalculator(_priceCalculator);
function setDepositAmountCalculator(address _priceCalculator) external onlyOwner {
depositAmountCalculator = IPriceCalculator(_priceCalculator);
}
/// @notice Set the maximum total rate limit of all (FIXME: excl expired?) memberships in the membership set
/// @notice Set the maximum total rate limit of all memberships in the membership set
/// @param _maxTotalRateLimit new maximum total rate limit (messages per epoch)
function setMaxTotalRateLimit(uint32 _maxTotalRateLimit) external onlyOwner {
require(_maxTotalRateLimit >= maxMembershipRateLimit);
@ -285,7 +282,8 @@ contract WakuRlnV2 is Initializable, Ownable2StepUpgradeable, UUPSUpgradeable, M
/// @notice Set the minimum rate limit of one membership
/// @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
require(_minMembershipRateLimit > 0);
require(_minMembershipRateLimit <= maxMembershipRateLimit);
minMembershipRateLimit = _minMembershipRateLimit;
}
@ -299,7 +297,7 @@ 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?
gracePeriodDuration = _gracePeriod;
// Note: grace period duration may be equal to zero
gracePeriodDurationForNewMemberships = _gracePeriod;
}
}

View File

@ -41,7 +41,7 @@ contract WakuRlnV2Test is Test {
uint256 idCommitment = 2;
uint32 membershipRateLimit = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
token.approve(address(w), price);
w.register(idCommitment, membershipRateLimit);
@ -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);
@ -96,7 +95,7 @@ contract WakuRlnV2Test is Test {
function test__ValidRegistration(uint32 membershipRateLimit) external {
vm.pauseGasMetering();
uint256 idCommitment = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
uint256 minMembershipRateLimit = w.minMembershipRateLimit();
uint256 maxMembershipRateLimit = w.maxMembershipRateLimit();
vm.assume(membershipRateLimit >= minMembershipRateLimit && membershipRateLimit <= maxMembershipRateLimit);
@ -119,11 +118,12 @@ contract WakuRlnV2Test is Test {
}
function test__LinearPriceCalculation(uint32 membershipRateLimit) external view {
IPriceCalculator priceCalculator = w.priceCalculator();
uint256 pricePerMessagePerPeriod = LinearPriceCalculator(address(priceCalculator)).pricePerMessagePerEpoch();
IPriceCalculator depositAmountCalculator = w.depositAmountCalculator();
uint256 pricePerMessagePerPeriod =
LinearPriceCalculator(address(depositAmountCalculator)).pricePerMessagePerEpoch();
assertNotEq(pricePerMessagePerPeriod, 0);
uint256 expectedPrice = uint256(membershipRateLimit) * pricePerMessagePerPeriod;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
assertEq(price, expectedPrice);
}
@ -133,7 +133,7 @@ contract WakuRlnV2Test is Test {
uint256 maxMembershipRateLimit = w.maxMembershipRateLimit();
vm.assume(membershipRateLimit >= minMembershipRateLimit && membershipRateLimit <= maxMembershipRateLimit);
vm.assume(w.isValidIdCommitment(idCommitment) && w.isValidMembershipRateLimit(membershipRateLimit));
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
token.approve(address(w), price - 1);
@ -153,7 +153,7 @@ contract WakuRlnV2Test is Test {
vm.pauseGasMetering();
uint256 idCommitment = 0;
uint32 membershipRateLimit = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
token.approve(address(w), price);
@ -164,7 +164,7 @@ contract WakuRlnV2Test is Test {
function test__InvalidRegistration__InvalidIdCommitment__LargerThanField() external {
vm.pauseGasMetering();
uint32 membershipRateLimit = 20;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
uint256 idCommitment = w.Q() + 1;
@ -179,17 +179,17 @@ contract WakuRlnV2Test is Test {
uint32 invalidMin = w.minMembershipRateLimit() - 1;
uint32 invalidMax = w.maxMembershipRateLimit() + 1;
vm.expectRevert(abi.encodeWithSelector(InvalidRateLimit.selector));
vm.expectRevert(abi.encodeWithSelector(InvalidMembershipRateLimit.selector));
w.register(idCommitment, invalidMin);
vm.expectRevert(abi.encodeWithSelector(InvalidRateLimit.selector));
vm.expectRevert(abi.encodeWithSelector(InvalidMembershipRateLimit.selector));
w.register(idCommitment, invalidMax);
}
function test__ValidRegistrationExtend(uint32 membershipRateLimit) external {
vm.pauseGasMetering();
uint256 idCommitment = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.assume(
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
);
@ -239,7 +239,7 @@ contract WakuRlnV2Test is Test {
function test__ValidRegistrationExtendSingleMembership(uint32 membershipRateLimit) external {
vm.pauseGasMetering();
uint256 idCommitment = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.assume(
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
);
@ -271,7 +271,7 @@ contract WakuRlnV2Test is Test {
function test__ValidRegistrationExpiry(uint32 membershipRateLimit) external {
vm.pauseGasMetering();
uint256 idCommitment = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.assume(
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
);
@ -303,7 +303,7 @@ contract WakuRlnV2Test is Test {
vm.stopPrank();
vm.resumeGasMetering();
(, uint256 priceA) = w.priceCalculator().calculate(20);
(, uint256 priceA) = w.depositAmountCalculator().calculate(20);
for (uint256 i = 1; i <= 5; i++) {
token.approve(address(w), priceA);
@ -321,7 +321,7 @@ contract WakuRlnV2Test is Test {
assertFalse(w.isExpired(5));
assertFalse(w.isInGracePeriod(5));
(, uint256 priceB) = w.priceCalculator().calculate(60);
(, uint256 priceB) = w.depositAmountCalculator().calculate(60);
token.approve(address(w), priceB);
// Should fail. There's not enough free rate limit
@ -334,7 +334,7 @@ contract WakuRlnV2Test is Test {
commitmentsToErase[1] = 2;
commitmentsToErase[2] = 5; // This one is still active
token.approve(address(w), priceB);
vm.expectRevert(abi.encodeWithSelector(CantEraseMembership.selector, 5));
vm.expectRevert(abi.encodeWithSelector(CannotEraseMembership.selector, 5));
w.register(6, 60, commitmentsToErase);
// Attempt to expire 3 commitments that can be erased
@ -381,33 +381,33 @@ contract WakuRlnV2Test is Test {
// Exceeds the max rate limit per user
uint32 membershipRateLimit = 10;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
token.approve(address(w), price);
vm.expectRevert(abi.encodeWithSelector(InvalidRateLimit.selector));
vm.expectRevert(abi.encodeWithSelector(InvalidMembershipRateLimit.selector));
w.register(1, membershipRateLimit);
// Should register succesfully
membershipRateLimit = 4;
(, price) = w.priceCalculator().calculate(membershipRateLimit);
(, price) = w.depositAmountCalculator().calculate(membershipRateLimit);
token.approve(address(w), price);
w.register(2, membershipRateLimit);
// Exceeds the rate limit
membershipRateLimit = 2;
(, price) = w.priceCalculator().calculate(membershipRateLimit);
(, price) = w.depositAmountCalculator().calculate(membershipRateLimit);
token.approve(address(w), price);
vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector));
w.register(3, membershipRateLimit);
// Should register succesfully
membershipRateLimit = 1;
(, price) = w.priceCalculator().calculate(membershipRateLimit);
(, price) = w.depositAmountCalculator().calculate(membershipRateLimit);
token.approve(address(w), price);
w.register(3, membershipRateLimit);
// We ran out of rate limit again
membershipRateLimit = 1;
(, price) = w.priceCalculator().calculate(membershipRateLimit);
(, price) = w.depositAmountCalculator().calculate(membershipRateLimit);
token.approve(address(w), price);
vm.expectRevert(abi.encodeWithSelector(ExceededMaxTotalRateLimit.selector));
w.register(4, membershipRateLimit);
@ -416,7 +416,7 @@ contract WakuRlnV2Test is Test {
function test__indexReuse_eraseMemberships(uint32 idCommitmentsLength) external {
vm.assume(idCommitmentsLength > 0 && idCommitmentsLength < 50);
(, uint256 price) = w.priceCalculator().calculate(20);
(, uint256 price) = w.depositAmountCalculator().calculate(20);
uint32 index;
uint256[] memory commitmentsToErase = new uint256[](idCommitmentsLength);
for (uint256 i = 1; i <= idCommitmentsLength; i++) {
@ -468,7 +468,7 @@ contract WakuRlnV2Test is Test {
function test__RemoveExpiredMemberships(uint32 membershipRateLimit) external {
vm.pauseGasMetering();
uint256 idCommitment = 2;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.assume(
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
);
@ -518,7 +518,7 @@ contract WakuRlnV2Test is Test {
vm.warp(gracePeriodStartTimestamp - 1);
commitmentsToErase[0] = idCommitment;
commitmentsToErase[1] = idCommitment + 4;
vm.expectRevert(abi.encodeWithSelector(CantEraseMembership.selector, idCommitment + 4));
vm.expectRevert(abi.encodeWithSelector(CannotEraseMembership.selector, idCommitment + 4));
w.eraseMemberships(commitmentsToErase);
}
@ -526,7 +526,7 @@ contract WakuRlnV2Test is Test {
vm.pauseGasMetering();
vm.assume(idCommitmentsLength > 1 && idCommitmentsLength <= 100);
uint32 membershipRateLimit = w.minMembershipRateLimit();
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
uint256 time = block.timestamp;
@ -562,10 +562,10 @@ contract WakuRlnV2Test is Test {
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(membershipRateLimit);
LinearPriceCalculator depositAmountCalculator = LinearPriceCalculator(address(w.depositAmountCalculator()));
vm.prank(depositAmountCalculator.owner());
depositAmountCalculator.setTokenAndPrice(address(token), 5 wei);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
token.mint(address(this), price);
vm.assume(
membershipRateLimit >= w.minMembershipRateLimit() && membershipRateLimit <= w.maxMembershipRateLimit()
@ -605,21 +605,21 @@ contract WakuRlnV2Test is Test {
vm.pauseGasMetering();
uint256 idCommitment = 2;
uint32 membershipRateLimit = w.minMembershipRateLimit();
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
token.approve(address(w), price);
w.register(idCommitment, membershipRateLimit);
token.approve(address(w), price);
vm.expectRevert(DuplicateIdCommitment.selector);
vm.expectRevert(bytes("Duplicate idCommitment: membership already exists"));
w.register(idCommitment, membershipRateLimit);
}
function test__InvalidRegistration__FullTree() external {
vm.pauseGasMetering();
uint32 membershipRateLimit = 20;
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
// we progress the tree to the last leaf
@ -647,7 +647,7 @@ contract WakuRlnV2Test is Test {
// we set nextFreeIndex to 4294967295 (1 << 20) = 0x00100000
vm.store(address(w), bytes32(uint256(256)), 0x0000000000000000000000000000000000000000000000000000000000100000);
token.approve(address(w), price);
vm.expectRevert(FullMembershipSet.selector);
vm.expectRevert(bytes("Membership set is full"));
w.register(1, membershipRateLimit);
}
@ -665,7 +665,7 @@ contract WakuRlnV2Test is Test {
vm.pauseGasMetering();
uint256 idCommitment = 1;
uint32 membershipRateLimit = w.minMembershipRateLimit();
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
vm.resumeGasMetering();
token.approve(address(w), price);
@ -680,7 +680,7 @@ contract WakuRlnV2Test is Test {
vm.pauseGasMetering();
vm.assume(idCommitmentsLength > 0 && idCommitmentsLength <= 100);
uint32 membershipRateLimit = w.minMembershipRateLimit();
(, uint256 price) = w.priceCalculator().calculate(membershipRateLimit);
(, uint256 price) = w.depositAmountCalculator().calculate(membershipRateLimit);
for (uint256 i = 0; i < idCommitmentsLength; i++) {
token.approve(address(w), price);