Skip to content

Commit

Permalink
refactor: moved active proposal limitier params to space level (#155)
Browse files Browse the repository at this point in the history
* refactor: moved active proposal limitier params to space level

* fix: limit active proposals per space not globally

* fix: forked test error

---------

Co-authored-by: Orlando <[email protected]>
  • Loading branch information
Orland0x and Orlando authored May 15, 2023
1 parent f24861d commit 41f77f7
Show file tree
Hide file tree
Showing 12 changed files with 43 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .forge-snapshots/ProposeSigComp.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
170893
171411
2 changes: 1 addition & 1 deletion .forge-snapshots/VoteSigComp.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
52097
52079
2 changes: 1 addition & 1 deletion .forge-snapshots/VoteSigCompMetadata.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
53783
53758
2 changes: 1 addition & 1 deletion .forge-snapshots/VoteTxComp.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
45284
45266
2 changes: 1 addition & 1 deletion .forge-snapshots/VoteTxCompMetadata.snap
Original file line number Diff line number Diff line change
@@ -1 +1 @@
46875
46850
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@ import { ActiveProposalsLimiter } from "./utils/ActiveProposalsLimiter.sol";
/// @title Active Proposals Limiter Proposal Validation Strategy
/// @notice Strategy to limit proposal creation to a maximum number of active proposals per author.
contract ActiveProposalsLimiterProposalValidationStrategy is ActiveProposalsLimiter, IProposalValidationStrategy {
// solhint-disable-next-line no-empty-blocks
constructor(uint32 _cooldown, uint224 _maxActiveProposals) ActiveProposalsLimiter(_cooldown, _maxActiveProposals) {}

/// @notice Validates an author by checking if they have reached the maximum number of active proposals at the
/// current timestamp.
/// @param author Author of the proposal.
/// @param params ABI encoded array that should contain the following:
/// cooldown: Duration to wait before the proposal counter gets reset.
/// maxActiveProposals: Maximum number of active proposals per author. Must be != 0.
/// @return success Whether the proposal was validated.
function validate(
address author,
bytes calldata /* params */,
bytes calldata params,
bytes calldata /* userParams*/
) external override returns (bool success) {
return _validate(author);
(uint256 cooldown, uint256 maxActiveProposals) = abi.decode(params, (uint256, uint256));
return _validate(author, cooldown, maxActiveProposals);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,26 @@ contract PropositionPowerAndActiveProposalsLimiterValidationStrategy is
PropositionPower,
IProposalValidationStrategy
{
// solhint-disable-next-line no-empty-blocks
constructor(uint32 _cooldown, uint224 _maxActiveProposals) ActiveProposalsLimiter(_cooldown, _maxActiveProposals) {}

/// @notice Validates an author by checking if the proposition power of the author exceeds a threshold over a set of
/// strategies and if the author has reached the maximum number of active proposals at the current timestamp.
/// @param author Author of the proposal.
/// @param params ABI encoded array that should contain the following:
/// cooldown: Duration to wait before the proposal counter gets reset.
/// maxActiveProposals: Maximum number of active proposals per author. Must be != 0.
/// proposalThreshold: Minimum proposition power required to create a proposal.
/// allowedStrategies: Array of allowed voting strategies.
/// @param userParams ABI encoded array that should contain the user voting strategies.
function validate(address author, bytes calldata params, bytes calldata userParams) external returns (bool) {
(uint256 proposalThreshold, Strategy[] memory allowedStrategies) = abi.decode(params, (uint256, Strategy[]));
(
uint256 cooldown,
uint256 maxActiveProposals,
uint256 proposalThreshold,
Strategy[] memory allowedStrategies
) = abi.decode(params, (uint256, uint256, uint256, Strategy[]));
IndexedStrategy[] memory userStrategies = abi.decode(userParams, (IndexedStrategy[]));

return
ActiveProposalsLimiter._validate(author) &&
ActiveProposalsLimiter._validate(author, cooldown, maxActiveProposals) &&
PropositionPower._validate(author, proposalThreshold, allowedStrategies, userStrategies);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ contract PropositionPowerProposalValidationStrategy is PropositionPower, IPropos
/// @notice Validates an author by checking if the proposition power of the author exceeds a threshold
/// over a set of strategies.
/// @param author Author of the proposal.
/// @param params ABI encoded array that should contain the proposal threshold and allowed voting strategies.
/// @param params ABI encoded array that should contain the following:
/// proposalThreshold: Minimum proposition power required to create a proposal.
/// allowedStrategies: Array of allowed voting strategies.
/// @param userParams ABI encoded array that should contain the user voting strategies.
function validate(
address author,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,19 @@ abstract contract ActiveProposalsLimiter {
/// @notice Thrown when the maximum number of active proposals per user is set to 0.
error MaxActiveProposalsCannotBeZero();

/// @notice Cooldown duration to wait before the proposal counter gets reset.
uint32 public immutable cooldown;

/// @notice Maximum number of active proposals per user. Must be != 0.
uint224 public immutable maxActiveProposals;

/// @notice Mapping that stores and encoded Uint256 for each user, as follows:
/// @dev Mapping that stores an encoded Uint256 for each user for each space, as follows:
// [0..32] : 32 bits for the timestamp of the latest proposal made by the user
// [32..256] : 224 bits for the number of currently active proposals for this user
mapping(address => uint256) public usersPackedData;
mapping(address space => mapping(address author => uint256)) private usersPackedData;

constructor(uint32 _cooldown, uint224 _maxActiveProposals) {
if (_maxActiveProposals == 0) revert MaxActiveProposalsCannotBeZero();
/// @dev Validates an author by checking if they have reached the maximum number of active proposals at the current timestamp.
function _validate(address author, uint256 cooldown, uint256 maxActiveProposals) internal returns (bool success) {
if (maxActiveProposals == 0) revert MaxActiveProposalsCannotBeZero();

cooldown = _cooldown;
maxActiveProposals = _maxActiveProposals;
}
// The space calls the proposal validation strategy, therefore msg.sender corresponds to the space address.
address space = msg.sender;

/// @dev Validates an author by checking if they have reached the maximum number of active proposals at the current timestamp.
function _validate(address author) internal returns (bool success) {
uint256 packedData = usersPackedData[author];
uint256 packedData = usersPackedData[space][author];

// Least significant 32 bits is the lastTimestamp.
uint256 lastTimestamp = uint32(packedData);
Expand All @@ -50,7 +42,7 @@ abstract contract ActiveProposalsLimiter {
activeProposals += 1;
}

usersPackedData[author] = (activeProposals << 32) + uint32(block.timestamp);
usersPackedData[space][author] = (activeProposals << 32) + uint32(block.timestamp);
return true;
}
}
7 changes: 2 additions & 5 deletions test/ActiveProposalsLimiterProposalValidationStrategy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ contract ActiveProposalsLimterTest is SpaceTest {
maxActive = 5;
cooldown = 1 weeks;

activeProposalsLimiterProposalValidationStrategy = new ActiveProposalsLimiterProposalValidationStrategy(
1 weeks,
5
);
activeProposalsLimiterProposalValidationStrategy = new ActiveProposalsLimiterProposalValidationStrategy();

space.setProposalValidationStrategy(
Strategy(address(activeProposalsLimiterProposalValidationStrategy), new bytes(0)),
Strategy(address(activeProposalsLimiterProposalValidationStrategy), abi.encode(cooldown, maxActive)),
""
);
}
Expand Down
4 changes: 2 additions & 2 deletions test/ForkedTests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ contract ForkedTest is SpaceTest, SigUtils {
currentVotingStrategies[1] = Strategy(addr1, params1);

// Set the proposal validation strategy to Comp token proposition power.
validationStrategy = new PropositionPowerAndActiveProposalsLimiterValidationStrategy(864000, 5);
validationStrategy = new PropositionPowerAndActiveProposalsLimiterValidationStrategy();
// Using the current active strategies in the space as the allowed strategies for proposal.
space.setProposalValidationStrategy(
Strategy(address(validationStrategy), abi.encode(TOKEN_AMOUNT, currentVotingStrategies)),
Strategy(address(validationStrategy), abi.encode(864000, 5, TOKEN_AMOUNT, currentVotingStrategies)),
""
);
}
Expand Down
4 changes: 2 additions & 2 deletions test/GasSnapshots.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ contract GasSnapshotsTest is SpaceTest, SigUtils {
currentVotingStrategies[1] = Strategy(addr1, params1);

// Set the proposal validation strategy to Comp token proposition power.
validationStrategy = new PropositionPowerAndActiveProposalsLimiterValidationStrategy(864000, 5);
validationStrategy = new PropositionPowerAndActiveProposalsLimiterValidationStrategy();
// Using the current active strategies in the space as the allowed strategies for proposal.
space.setProposalValidationStrategy(
Strategy(address(validationStrategy), abi.encode(TOKEN_AMOUNT, currentVotingStrategies)),
Strategy(address(validationStrategy), abi.encode(864000, 5, TOKEN_AMOUNT, currentVotingStrategies)),
""
);
}
Expand Down

0 comments on commit 41f77f7

Please sign in to comment.