Skip to content

Commit

Permalink
Merge pull request #34 from liquity/feat-dev-stateless-checks
Browse files Browse the repository at this point in the history
feat: stateless checks use memory variables
  • Loading branch information
GalloDaSballo authored Oct 15, 2024
2 parents d77fa12 + e39a3fd commit f964608
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 16 deletions.
27 changes: 21 additions & 6 deletions src/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,19 @@ contract Governance is Multicall, UserProxyFactory, ReentrancyGuard, IGovernance
}

/// @inheritdoc IGovernance
function calculateVotingThreshold() public view returns (uint256) {
uint256 snapshotVotes = votesSnapshot.votes;
function getLatestVotingThreshold() public view returns (uint256) {
uint256 snapshotVotes = votesSnapshot.votes; /// @audit technically can be out of synch

return calculateVotingThreshold(snapshotVotes);
}

function calculateVotingThreshold() public returns (uint256) {
(VoteSnapshot memory snapshot, ) = _snapshotVotes();

return calculateVotingThreshold(snapshot.votes);
}

function calculateVotingThreshold(uint256 snapshotVotes) public view returns (uint256) {
if (snapshotVotes == 0) return 0;

uint256 minVotes; // to reach MIN_CLAIM: snapshotVotes * MIN_CLAIM / boldAccrued
Expand Down Expand Up @@ -359,6 +370,10 @@ contract Governance is Multicall, UserProxyFactory, ReentrancyGuard, IGovernance
(VoteSnapshot memory votesSnapshot_,) = _snapshotVotes();
(InitiativeVoteSnapshot memory votesForInitiativeSnapshot_, InitiativeState memory initiativeState) = _snapshotVotesForInitiative(_initiative);

return getInitiativeState(_initiative, votesSnapshot_, votesForInitiativeSnapshot_, initiativeState);
}

function getInitiativeState(address _initiative, VoteSnapshot memory votesSnapshot_, InitiativeVoteSnapshot memory votesForInitiativeSnapshot_, InitiativeState memory initiativeState) public view returns (InitiativeStatus status, uint16 lastEpochClaim, uint256 claimableAmount) {
lastEpochClaim = initiativeStates[_initiative].lastEpochClaim;

// == Already Claimed Condition == //
Expand All @@ -368,12 +383,13 @@ contract Governance is Multicall, UserProxyFactory, ReentrancyGuard, IGovernance
}

// == Disabled Condition == //
// TODO: If a initiative is disabled, we return false and the last epoch claim
// If a initiative is disabled, we return false and the last epoch claim
if(registeredInitiatives[_initiative] == UNREGISTERED_INITIATIVE) {
return (InitiativeStatus.DISABLED, lastEpochClaim, 0); /// @audit By definition it must have zero rewards
return (InitiativeStatus.DISABLED, lastEpochClaim, 0); /// By definition it has zero rewards
}

uint256 votingTheshold = calculateVotingThreshold();
// NOTE: Pass the snapshot value so we get accurate result
uint256 votingTheshold = calculateVotingThreshold(votesSnapshot_.votes);

// If it's voted and can get rewards
// Votes > calculateVotingThreshold
Expand Down Expand Up @@ -450,7 +466,6 @@ contract Governance is Multicall, UserProxyFactory, ReentrancyGuard, IGovernance

(, GlobalState memory state) = _snapshotVotes();

uint256 votingThreshold = calculateVotingThreshold();
uint16 currentEpoch = epoch();

UserState memory userState = userStates[msg.sender];
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ interface IGovernance {
/// - 4% of the total voting LQTY in the previous epoch
/// - or the minimum number of votes necessary to claim at least MIN_CLAIM BOLD
/// @return votingThreshold Voting threshold
function calculateVotingThreshold() external view returns (uint256 votingThreshold);
function getLatestVotingThreshold() external view returns (uint256 votingThreshold);

/// @notice Snapshots votes for the previous epoch and accrues funds for the current epoch
/// @param _initiative Address of the initiative
Expand Down
16 changes: 8 additions & 8 deletions test/Governance.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ contract GovernanceTest is Test {
governance.lqtyToVotes(_lqtyAmount, _currentTimestamp, _averageTimestamp);
}

function test_calculateVotingThreshold() public {
function test_getLatestVotingThreshold() public {
governance = new Governance(
address(lqty),
address(lusd),
Expand All @@ -411,7 +411,7 @@ contract GovernanceTest is Test {
);

// is 0 when the previous epochs votes are 0
assertEq(governance.calculateVotingThreshold(), 0);
assertEq(governance.getLatestVotingThreshold(), 0);

// check that votingThreshold is is high enough such that MIN_CLAIM is met
IGovernance.VoteSnapshot memory snapshot = IGovernance.VoteSnapshot(1e18, 1);
Expand All @@ -428,7 +428,7 @@ contract GovernanceTest is Test {
vm.store(address(governance), bytes32(uint256(1)), bytes32(abi.encode(boldAccrued)));
assertEq(governance.boldAccrued(), 1000e18);

assertEq(governance.calculateVotingThreshold(), MIN_CLAIM / 1000);
assertEq(governance.getLatestVotingThreshold(), MIN_CLAIM / 1000);

// check that votingThreshold is 4% of votes of previous epoch
governance = new Governance(
Expand Down Expand Up @@ -466,7 +466,7 @@ contract GovernanceTest is Test {
vm.store(address(governance), bytes32(uint256(1)), bytes32(abi.encode(boldAccrued)));
assertEq(governance.boldAccrued(), 1000e18);

assertEq(governance.calculateVotingThreshold(), 10000e18 * 0.04);
assertEq(governance.getLatestVotingThreshold(), 10000e18 * 0.04);
}

// should not revert under any state
Expand Down Expand Up @@ -512,7 +512,7 @@ contract GovernanceTest is Test {
vm.store(address(governance), bytes32(uint256(1)), bytes32(abi.encode(_boldAccrued)));
assertEq(governance.boldAccrued(), _boldAccrued);

governance.calculateVotingThreshold();
governance.getLatestVotingThreshold();
}

function test_registerInitiative() public {
Expand Down Expand Up @@ -715,7 +715,7 @@ contract GovernanceTest is Test {
(IGovernance.VoteSnapshot memory snapshot, IGovernance.InitiativeVoteSnapshot memory initiativeVoteSnapshot1) = governance.snapshotVotesForInitiative(baseInitiative1);
(, IGovernance.InitiativeVoteSnapshot memory initiativeVoteSnapshot2) = governance.snapshotVotesForInitiative(baseInitiative2);

uint256 threshold = governance.calculateVotingThreshold();
uint256 threshold = governance.getLatestVotingThreshold();
assertLt(initiativeVoteSnapshot1.votes, threshold, "it didn't get rewards");

uint256 votingPowerWithProjection = governance.lqtyToVotes(voteLQTY1, governance.epochStart() + governance.EPOCH_DURATION(), averageStakingTimestampVoteLQTY1);
Expand Down Expand Up @@ -758,7 +758,7 @@ contract GovernanceTest is Test {

(IGovernance.VoteSnapshot memory snapshot, IGovernance.InitiativeVoteSnapshot memory initiativeVoteSnapshot1) = governance.snapshotVotesForInitiative(baseInitiative1);

uint256 threshold = governance.calculateVotingThreshold();
uint256 threshold = governance.getLatestVotingThreshold();
assertLt(initiativeVoteSnapshot1.votes, threshold, "it didn't get rewards");
}

Expand Down Expand Up @@ -1157,7 +1157,7 @@ contract GovernanceTest is Test {
console.log("snapshot votes", votes);
console.log("snapshot vetos", vetos);

console.log("governance.calculateVotingThreshold()", governance.calculateVotingThreshold());
console.log("governance.getLatestVotingThreshold()", governance.getLatestVotingThreshold());
assertEq(governance.claimForInitiative(baseInitiative2), 0, "zero 2");
assertEq(governance.claimForInitiative(baseInitiative2), 0, "zero 3");

Expand Down
2 changes: 1 addition & 1 deletion test/TEST.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Governance:
- should return the correct number of seconds elapsed within an epoch for a given block.timestamp
- lqtyToVotes()
- should not revert under any input
- calculateVotingThreshold()
- getLatestVotingThreshold()
- should return a votingThreshold that's either
- high enough such that MIN_CLAIM is met
- 4% of the votes from the previous epoch
Expand Down

0 comments on commit f964608

Please sign in to comment.