Skip to content

Commit

Permalink
Merge branch 'main' into todos
Browse files Browse the repository at this point in the history
  • Loading branch information
bingen committed Dec 5, 2024
2 parents 22bc82f + 078a766 commit b495c05
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 383 deletions.
2 changes: 0 additions & 2 deletions src/BribeInitiative.sol
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,6 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
IGovernance.Allocation calldata _allocation,
IGovernance.InitiativeState calldata _initiativeState
) external virtual onlyGovernance {
if (_currentEpoch == 0) return;

uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead();
uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead();

Expand Down
252 changes: 109 additions & 143 deletions src/Governance.sol

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/UserProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ contract UserProxy is IUserProxy {
PermitParams calldata _permitParams,
bool _doSendRewards,
address _recipient
) public onlyStakingV2 returns (uint256 lusdAmount, uint256 ethAmount) {
) external onlyStakingV2 returns (uint256 lusdAmount, uint256 ethAmount) {
require(_lqtyFrom == _permitParams.owner, "UserProxy: owner-not-sender");

uint256 initialLUSDAmount = lusd.balanceOf(address(this));
Expand All @@ -80,7 +80,7 @@ contract UserProxy is IUserProxy {

/// @inheritdoc IUserProxy
function unstake(uint256 _amount, bool _doSendRewards, address _recipient)
public
external
onlyStakingV2
returns (uint256 lusdAmount, uint256 ethAmount)
{
Expand Down
82 changes: 74 additions & 8 deletions src/interfaces/IGovernance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,24 @@ import {ILQTYStaking} from "./ILQTYStaking.sol";
import {PermitParams} from "../utils/Types.sol";

interface IGovernance {
event DepositLQTY(address user, uint256 depositedLQTY);
event WithdrawLQTY(address user, uint256 withdrawnLQTY, uint256 accruedLUSD, uint256 accruedETH);
event DepositLQTY(address indexed user, uint256 depositedLQTY);
event WithdrawLQTY(address indexed user, uint256 withdrawnLQTY, uint256 accruedLUSD, uint256 accruedETH);

event SnapshotVotes(uint240 votes, uint16 forEpoch);
event SnapshotVotesForInitiative(address initiative, uint240 votes, uint16 forEpoch);
event SnapshotVotes(uint256 votes, uint256 forEpoch, uint256 boldAccrued);
event SnapshotVotesForInitiative(address indexed initiative, uint256 votes, uint256 vetos, uint256 forEpoch);

event RegisterInitiative(address initiative, address registrant, uint16 atEpoch);
event UnregisterInitiative(address initiative, uint16 atEpoch);
event RegisterInitiative(address initiative, address registrant, uint256 atEpoch, bool hookSuccess);
event UnregisterInitiative(address initiative, uint256 atEpoch, bool hookSuccess);

event AllocateLQTY(address user, address initiative, int256 deltaVoteLQTY, int256 deltaVetoLQTY, uint16 atEpoch);
event ClaimForInitiative(address initiative, uint256 bold, uint256 forEpoch);
event AllocateLQTY(
address indexed user,
address indexed initiative,
int256 deltaVoteLQTY,
int256 deltaVetoLQTY,
uint256 atEpoch,
bool hookSuccess
);
event ClaimForInitiative(address indexed initiative, uint256 bold, uint256 forEpoch, bool hookSuccess);

struct Configuration {
uint128 registrationFee;
Expand Down Expand Up @@ -217,6 +224,33 @@ interface IGovernance {
pure
returns (uint208);

/// @dev Returns the most up to date voting threshold
/// In contrast to `getLatestVotingThreshold` this function updates the snapshot
/// This ensures that the value returned is always the latest
function calculateVotingThreshold() external returns (uint256);

/// @dev Utility function to compute the threshold votes without recomputing the snapshot
/// Note that `boldAccrued` is a cached value, this function works correctly only when called after an accrual
function calculateVotingThreshold(uint256 _votes) external view returns (uint256);

/// @notice Return the most up to date global snapshot and state as well as a flag to notify whether the state can be updated
/// This is a convenience function to always retrieve the most up to date state values
function getTotalVotesAndState()
external
view
returns (VoteSnapshot memory snapshot, GlobalState memory state, bool shouldUpdate);

/// @dev Given an initiative address, return it's most up to date snapshot and state as well as a flag to notify whether the state can be updated
/// This is a convenience function to always retrieve the most up to date state values
function getInitiativeSnapshotAndState(address _initiative)
external
view
returns (
InitiativeVoteSnapshot memory initiativeSnapshot,
InitiativeState memory initiativeState,
bool shouldUpdate
);

/// @notice Voting threshold is the max. of either:
/// - 4% of the total voting LQTY in the previous epoch
/// - or the minimum number of votes necessary to claim at least MIN_CLAIM BOLD
Expand All @@ -232,6 +266,38 @@ interface IGovernance {
external
returns (VoteSnapshot memory voteSnapshot, InitiativeVoteSnapshot memory initiativeVoteSnapshot);

/*//////////////////////////////////////////////////////////////
FSM
//////////////////////////////////////////////////////////////*/

enum InitiativeStatus {
NONEXISTENT,
/// This Initiative Doesn't exist | This is never returned
WARM_UP,
/// This epoch was just registered
SKIP,
/// This epoch will result in no rewards and no unregistering
CLAIMABLE,
/// This epoch will result in claiming rewards
CLAIMED,
/// The rewards for this epoch have been claimed
UNREGISTERABLE,
/// Can be unregistered
DISABLED // It was already Unregistered

}

function getInitiativeState(address _initiative)
external
returns (InitiativeStatus status, uint16 lastEpochClaim, uint256 claimableAmount);

function getInitiativeState(
address _initiative,
VoteSnapshot memory _votesSnapshot,
InitiativeVoteSnapshot memory _votesForInitiativeSnapshot,
InitiativeState memory _initiativeState
) external view returns (InitiativeStatus status, uint16 lastEpochClaim, uint256 claimableAmount);

/// @notice Registers a new initiative
/// @param _initiative Address of the initiative
function registerInitiative(address _initiative) external;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function add(uint88 a, int88 b) pure returns (uint88) {
if (b < 0) {
return a - abs(b);
}
return a + abs(b);
return a + uint88(b);
}

function max(uint256 a, uint256 b) pure returns (uint256) {
Expand Down
42 changes: 21 additions & 21 deletions test/E2E.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ contract ForkedE2ETests is Test {

address newInitiative = address(0x123123);
governance.registerInitiative(newInitiative);
assertEq(uint256(Governance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative), "Cooldown");
assertEq(uint256(IGovernance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative), "Cooldown");

uint256 skipCount;

Expand All @@ -165,25 +165,25 @@ contract ForkedE2ETests is Test {
// Whereas in next week it will work
vm.warp(block.timestamp + EPOCH_DURATION); // 1
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

// Cooldown on epoch Staert
vm.warp(block.timestamp + EPOCH_DURATION); // 2
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

vm.warp(block.timestamp + EPOCH_DURATION); // 3
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

vm.warp(block.timestamp + EPOCH_DURATION); // 3
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

vm.warp(block.timestamp + EPOCH_DURATION); // 4
++skipCount;
assertEq(
uint256(Governance.InitiativeStatus.UNREGISTERABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE"
uint256(IGovernance.InitiativeStatus.UNREGISTERABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE"
);

/// 4 + 1 ??
Expand All @@ -205,8 +205,8 @@ contract ForkedE2ETests is Test {
address newInitiative2 = address(0x1231234);
governance.registerInitiative(newInitiative);
governance.registerInitiative(newInitiative2);
assertEq(uint256(Governance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative), "Cooldown");
assertEq(uint256(Governance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative2), "Cooldown");
assertEq(uint256(IGovernance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative), "Cooldown");
assertEq(uint256(IGovernance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative2), "Cooldown");

uint256 skipCount;

Expand All @@ -217,7 +217,7 @@ contract ForkedE2ETests is Test {

vm.warp(block.timestamp + EPOCH_DURATION); // 1
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

_allocate(newInitiative2, 1e18, 0);

Expand All @@ -226,24 +226,24 @@ contract ForkedE2ETests is Test {
// Cooldown on epoch Staert
vm.warp(block.timestamp + EPOCH_DURATION); // 2
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

// 3rd Week of SKIP

vm.warp(block.timestamp + EPOCH_DURATION); // 3
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

// 4th Week of SKIP | If it doesn't get any rewards it will be UNREGISTERABLE

vm.warp(block.timestamp + EPOCH_DURATION); // 3
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

vm.warp(block.timestamp + EPOCH_DURATION); // 4
++skipCount;
assertEq(
uint256(Governance.InitiativeStatus.UNREGISTERABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE"
uint256(IGovernance.InitiativeStatus.UNREGISTERABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE"
);

/// It was SKIP for 4 EPOCHS, it is now UNREGISTERABLE
Expand All @@ -264,8 +264,8 @@ contract ForkedE2ETests is Test {
address newInitiative2 = address(0x1231234);
governance.registerInitiative(newInitiative);
governance.registerInitiative(newInitiative2);
assertEq(uint256(Governance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative), "Cooldown");
assertEq(uint256(Governance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative2), "Cooldown");
assertEq(uint256(IGovernance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative), "Cooldown");
assertEq(uint256(IGovernance.InitiativeStatus.WARM_UP), _getInitiativeStatus(newInitiative2), "Cooldown");

uint256 skipCount;

Expand All @@ -276,7 +276,7 @@ contract ForkedE2ETests is Test {

vm.warp(block.timestamp + EPOCH_DURATION); // 1
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

_allocate(newInitiative2, 1e18, 0);

Expand All @@ -285,27 +285,27 @@ contract ForkedE2ETests is Test {
// Cooldown on epoch Staert
vm.warp(block.timestamp + EPOCH_DURATION); // 2
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

// 3rd Week of SKIP

vm.warp(block.timestamp + EPOCH_DURATION); // 3
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

// 4th Week of SKIP | If it doesn't get any rewards it will be UNREGISTERABLE

vm.warp(block.timestamp + EPOCH_DURATION); // 3
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");
assertEq(uint256(IGovernance.InitiativeStatus.SKIP), _getInitiativeStatus(newInitiative), "SKIP");

// Allocating to it, saves it
_reset(newInitiative2);
_allocate(newInitiative, 1e18, 0);

vm.warp(block.timestamp + EPOCH_DURATION); // 4
++skipCount;
assertEq(uint256(Governance.InitiativeStatus.CLAIMABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE");
assertEq(uint256(IGovernance.InitiativeStatus.CLAIMABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE");
}

function _deposit(uint88 amt) internal {
Expand Down Expand Up @@ -339,7 +339,7 @@ contract ForkedE2ETests is Test {
}

function _getInitiativeStatus(address _initiative) internal returns (uint256) {
(Governance.InitiativeStatus status,,) = governance.getInitiativeState(_initiative);
(IGovernance.InitiativeStatus status,,) = governance.getInitiativeState(_initiative);
return uint256(status);
}
}
Loading

0 comments on commit b495c05

Please sign in to comment.