diff --git a/src/BribeInitiative.sol b/src/BribeInitiative.sol index 40dd6342..2720d2ae 100644 --- a/src/BribeInitiative.sol +++ b/src/BribeInitiative.sol @@ -10,8 +10,6 @@ import {IBribeInitiative} from "./interfaces/IBribeInitiative.sol"; import {DoubleLinkedList} from "./utils/DoubleLinkedList.sol"; -import {EncodingDecodingLib} from "src/utils/EncodingDecodingLib.sol"; - contract BribeInitiative is IInitiative, IBribeInitiative { using SafeERC20 for IERC20; using DoubleLinkedList for DoubleLinkedList.List; @@ -24,9 +22,9 @@ contract BribeInitiative is IInitiative, IBribeInitiative { IERC20 public immutable bribeToken; /// @inheritdoc IBribeInitiative - mapping(uint16 => Bribe) public bribeByEpoch; + mapping(uint256 => Bribe) public bribeByEpoch; /// @inheritdoc IBribeInitiative - mapping(address => mapping(uint16 => bool)) public claimedBribeAtEpoch; + mapping(address => mapping(uint256 => bool)) public claimedBribeAtEpoch; /// Double linked list of the total LQTY allocated at a given epoch DoubleLinkedList.List internal totalLQTYAllocationByEpoch; @@ -47,18 +45,18 @@ contract BribeInitiative is IInitiative, IBribeInitiative { } /// @inheritdoc IBribeInitiative - function totalLQTYAllocatedByEpoch(uint16 _epoch) external view returns (uint88, uint120) { + function totalLQTYAllocatedByEpoch(uint256 _epoch) external view returns (uint256, uint256) { return _loadTotalLQTYAllocation(_epoch); } /// @inheritdoc IBribeInitiative - function lqtyAllocatedByUserAtEpoch(address _user, uint16 _epoch) external view returns (uint88, uint120) { + function lqtyAllocatedByUserAtEpoch(address _user, uint256 _epoch) external view returns (uint256, uint256) { return _loadLQTYAllocation(_user, _epoch); } /// @inheritdoc IBribeInitiative - function depositBribe(uint128 _boldAmount, uint128 _bribeTokenAmount, uint16 _epoch) external { - uint16 epoch = governance.epoch(); + function depositBribe(uint256 _boldAmount, uint256 _bribeTokenAmount, uint256 _epoch) external { + uint256 epoch = governance.epoch(); require(_epoch >= epoch, "BribeInitiative: now-or-future-epochs"); Bribe memory bribe = bribeByEpoch[_epoch]; @@ -72,13 +70,11 @@ contract BribeInitiative is IInitiative, IBribeInitiative { bribeToken.safeTransferFrom(msg.sender, address(this), _bribeTokenAmount); } - uint256 constant TIMESTAMP_PRECISION = 1e26; - function _claimBribe( address _user, - uint16 _epoch, - uint16 _prevLQTYAllocationEpoch, - uint16 _prevTotalLQTYAllocationEpoch + uint256 _epoch, + uint256 _prevLQTYAllocationEpoch, + uint256 _prevTotalLQTYAllocationEpoch ) internal returns (uint256 boldAmount, uint256 bribeTokenAmount) { require(_epoch < governance.epoch(), "BribeInitiative: cannot-claim-for-current-epoch"); require(!claimedBribeAtEpoch[_user][_epoch], "BribeInitiative: already-claimed"); @@ -101,26 +97,17 @@ contract BribeInitiative is IInitiative, IBribeInitiative { "BribeInitiative: invalid-prev-total-lqty-allocation-epoch" ); - (uint88 totalLQTY, uint120 totalAverageTimestamp) = _decodeLQTYAllocation(totalLQTYAllocation.value); - require(totalLQTY > 0, "BribeInitiative: total-lqty-allocation-zero"); - - // NOTE: SCALING!!! | The timestamp will work until type(uint32).max | After which the math will eventually overflow - uint120 scaledEpochEnd = ( - uint120(governance.EPOCH_START()) + uint120(_epoch) * uint120(governance.EPOCH_DURATION()) - ) * uint120(TIMESTAMP_PRECISION); + require(totalLQTYAllocation.lqty > 0, "BribeInitiative: total-lqty-allocation-zero"); - assert(totalAverageTimestamp <= scaledEpochEnd); + uint256 epochEnd = governance.EPOCH_START() + _epoch * governance.EPOCH_DURATION(); - uint120 totalAverageAge = scaledEpochEnd - totalAverageTimestamp; - if (totalLQTY != 0 && totalAverageAge != 0) { - (uint88 lqty, uint120 averageTimestamp) = _decodeLQTYAllocation(lqtyAllocation.value); - require(lqty > 0, "BribeInitiative: lqty-allocation-zero"); + uint256 totalVotes = governance.lqtyToVotes(totalLQTYAllocation.lqty, epochEnd, totalLQTYAllocation.offset); + if (totalVotes != 0) { + require(lqtyAllocation.lqty > 0, "BribeInitiative: lqty-allocation-zero"); - assert(averageTimestamp <= scaledEpochEnd); - - uint120 averageAge = scaledEpochEnd - averageTimestamp; - boldAmount = uint256(bribe.boldAmount) * lqty / totalLQTY * averageAge / totalAverageAge; - bribeTokenAmount = uint256(bribe.bribeTokenAmount) * lqty / totalLQTY * averageAge / totalAverageAge; + uint256 votes = governance.lqtyToVotes(lqtyAllocation.lqty, epochEnd, lqtyAllocation.offset); + boldAmount = bribe.boldAmount * votes / totalVotes; + bribeTokenAmount = bribe.bribeTokenAmount * votes / totalVotes; } claimedBribeAtEpoch[_user][_epoch] = true; @@ -142,9 +129,8 @@ contract BribeInitiative is IInitiative, IBribeInitiative { bribeTokenAmount += bribeTokenAmount_; } - // NOTE: Due to rounding errors in the `averageTimestamp` bribes may slightly overpay compared to what they have allocated + // NOTE: Due to rounding errors, bribes may slightly overpay compared to what they have allocated // We cap to the available amount for this reason - // The error should be below 10 LQTY per annum, in the worst case if (boldAmount != 0) { uint256 max = bold.balanceOf(address(this)); if (boldAmount > max) { @@ -163,85 +149,79 @@ contract BribeInitiative is IInitiative, IBribeInitiative { } /// @inheritdoc IInitiative - function onRegisterInitiative(uint16) external virtual override onlyGovernance {} + function onRegisterInitiative(uint256) external virtual override onlyGovernance {} /// @inheritdoc IInitiative - function onUnregisterInitiative(uint16) external virtual override onlyGovernance {} + function onUnregisterInitiative(uint256) external virtual override onlyGovernance {} - function _setTotalLQTYAllocationByEpoch(uint16 _epoch, uint88 _lqty, uint120 _averageTimestamp, bool _insert) - private - { - uint224 value = _encodeLQTYAllocation(_lqty, _averageTimestamp); + function _setTotalLQTYAllocationByEpoch(uint256 _epoch, uint256 _lqty, uint256 _offset, bool _insert) private { if (_insert) { - totalLQTYAllocationByEpoch.insert(_epoch, value, 0); + totalLQTYAllocationByEpoch.insert(_epoch, _lqty, _offset, 0); } else { - totalLQTYAllocationByEpoch.items[_epoch].value = value; + totalLQTYAllocationByEpoch.items[_epoch].lqty = _lqty; + totalLQTYAllocationByEpoch.items[_epoch].offset = _offset; } - emit ModifyTotalLQTYAllocation(_epoch, _lqty, _averageTimestamp); + emit ModifyTotalLQTYAllocation(_epoch, _lqty, _offset); } function _setLQTYAllocationByUserAtEpoch( address _user, - uint16 _epoch, - uint88 _lqty, - uint120 _averageTimestamp, + uint256 _epoch, + uint256 _lqty, + uint256 _offset, bool _insert ) private { - uint224 value = _encodeLQTYAllocation(_lqty, _averageTimestamp); if (_insert) { - lqtyAllocationByUserAtEpoch[_user].insert(_epoch, value, 0); + lqtyAllocationByUserAtEpoch[_user].insert(_epoch, _lqty, _offset, 0); } else { - lqtyAllocationByUserAtEpoch[_user].items[_epoch].value = value; + lqtyAllocationByUserAtEpoch[_user].items[_epoch].lqty = _lqty; + lqtyAllocationByUserAtEpoch[_user].items[_epoch].offset = _offset; } - emit ModifyLQTYAllocation(_user, _epoch, _lqty, _averageTimestamp); + emit ModifyLQTYAllocation(_user, _epoch, _lqty, _offset); } - function _encodeLQTYAllocation(uint88 _lqty, uint120 _averageTimestamp) private pure returns (uint224) { - return EncodingDecodingLib.encodeLQTYAllocation(_lqty, _averageTimestamp); - } + function _loadTotalLQTYAllocation(uint256 _epoch) private view returns (uint256, uint256) { + require(_epoch <= governance.epoch(), "No future Lookup"); + DoubleLinkedList.Item memory totalLqtyAllocation = totalLQTYAllocationByEpoch.items[_epoch]; - function _decodeLQTYAllocation(uint224 _value) private pure returns (uint88, uint120) { - return EncodingDecodingLib.decodeLQTYAllocation(_value); + return (totalLqtyAllocation.lqty, totalLqtyAllocation.offset); } - function _loadTotalLQTYAllocation(uint16 _epoch) private view returns (uint88, uint120) { + function _loadLQTYAllocation(address _user, uint256 _epoch) private view returns (uint256, uint256) { require(_epoch <= governance.epoch(), "No future Lookup"); - return _decodeLQTYAllocation(totalLQTYAllocationByEpoch.items[_epoch].value); - } + DoubleLinkedList.Item memory lqtyAllocation = lqtyAllocationByUserAtEpoch[_user].items[_epoch]; - function _loadLQTYAllocation(address _user, uint16 _epoch) private view returns (uint88, uint120) { - require(_epoch <= governance.epoch(), "No future Lookup"); - return _decodeLQTYAllocation(lqtyAllocationByUserAtEpoch[_user].items[_epoch].value); + return (lqtyAllocation.lqty, lqtyAllocation.offset); } /// @inheritdoc IBribeInitiative - function getMostRecentUserEpoch(address _user) external view returns (uint16) { - uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); + function getMostRecentUserEpoch(address _user) external view returns (uint256) { + uint256 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); return mostRecentUserEpoch; } /// @inheritdoc IBribeInitiative - function getMostRecentTotalEpoch() external view returns (uint16) { - uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead(); + function getMostRecentTotalEpoch() external view returns (uint256) { + uint256 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead(); return mostRecentTotalEpoch; } function onAfterAllocateLQTY( - uint16 _currentEpoch, + uint256 _currentEpoch, address _user, IGovernance.UserState calldata _userState, IGovernance.Allocation calldata _allocation, IGovernance.InitiativeState calldata _initiativeState ) external virtual onlyGovernance { - uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); - uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead(); + uint256 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); + uint256 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead(); _setTotalLQTYAllocationByEpoch( _currentEpoch, _initiativeState.voteLQTY, - _initiativeState.averageStakingTimestampVoteLQTY, + _initiativeState.voteOffset, mostRecentTotalEpoch != _currentEpoch // Insert if current > recent ); @@ -249,11 +229,11 @@ contract BribeInitiative is IInitiative, IBribeInitiative { _user, _currentEpoch, _allocation.voteLQTY, - _userState.averageStakingTimestamp, + _userState.allocatedOffset, mostRecentUserEpoch != _currentEpoch // Insert if user current > recent ); } /// @inheritdoc IInitiative - function onClaimForInitiative(uint16, uint256) external virtual override onlyGovernance {} + function onClaimForInitiative(uint256, uint256) external virtual override onlyGovernance {} } diff --git a/src/CurveV2GaugeRewards.sol b/src/CurveV2GaugeRewards.sol index f6cd1869..dea21ee6 100644 --- a/src/CurveV2GaugeRewards.sol +++ b/src/CurveV2GaugeRewards.sol @@ -22,7 +22,7 @@ contract CurveV2GaugeRewards is BribeInitiative { /// @notice Governance transfers Bold, and we deposit it into the gauge /// @dev Doing this allows anyone to trigger the claim - function onClaimForInitiative(uint16, uint256 _bold) external override onlyGovernance { + function onClaimForInitiative(uint256, uint256 _bold) external override onlyGovernance { _depositIntoGauge(_bold); } diff --git a/src/Governance.sol b/src/Governance.sol index c15c35a6..b32946fa 100644 --- a/src/Governance.sol +++ b/src/Governance.sol @@ -12,7 +12,7 @@ import {ILQTYStaking} from "./interfaces/ILQTYStaking.sol"; import {UserProxy} from "./UserProxy.sol"; import {UserProxyFactory} from "./UserProxyFactory.sol"; -import {add, max} from "./utils/Math.sol"; +import {add, sub, max} from "./utils/Math.sol"; import {_requireNoDuplicates, _requireNoNegatives} from "./utils/UniqueArray.sol"; import {MultiDelegateCall} from "./utils/MultiDelegateCall.sol"; import {WAD, PermitParams} from "./utils/Types.sol"; @@ -71,12 +71,9 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// @inheritdoc IGovernance mapping(address => mapping(address => Allocation)) public lqtyAllocatedByUserToInitiative; /// @inheritdoc IGovernance - mapping(address => uint16) public override registeredInitiatives; + mapping(address => uint256) public override registeredInitiatives; - uint16 constant UNREGISTERED_INITIATIVE = type(uint16).max; - - // 100 Million LQTY will be necessary to make the rounding error cause 1 second of loss per operation - uint120 public constant TIMESTAMP_PRECISION = 1e26; + uint256 constant UNREGISTERED_INITIATIVE = type(uint256).max; constructor( address _lqty, @@ -136,34 +133,15 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own _renounceOwnership(); } - function _averageAge(uint120 _currentTimestamp, uint120 _averageTimestamp) internal pure returns (uint120) { - // Due to rounding error, _averageTimestamp can sometimes be higher than _currentTimestamp - if (_currentTimestamp < _averageTimestamp) return 0; - return _currentTimestamp - _averageTimestamp; - } - - function _calculateAverageTimestamp( - uint256 _prevOuterAverageTimestamp, - uint256 _newInnerAverageTimestamp, - uint256 _prevLQTYBalance, - uint256 _newLQTYBalance - ) internal pure returns (uint120) { - if (_newLQTYBalance == 0) return 0; - - return uint120( - _newInnerAverageTimestamp + _prevOuterAverageTimestamp * _prevLQTYBalance / _newLQTYBalance - - _newInnerAverageTimestamp * _prevLQTYBalance / _newLQTYBalance - ); - } - /*////////////////////////////////////////////////////////////// STAKING //////////////////////////////////////////////////////////////*/ - function _updateUserTimestamp(uint88 _lqtyAmount) private returns (UserProxy) { + function _increaseUserVoteTrackers(uint256 _lqtyAmount) private returns (UserProxy) { require(_lqtyAmount > 0, "Governance: zero-lqty-amount"); // Assert that we have resetted here + // TODO: Remove, as now unecessary UserState memory userState = userStates[msg.sender]; require(userState.allocatedLQTY == 0, "Governance: must-be-zero-allocation"); @@ -175,29 +153,22 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own UserProxy userProxy = UserProxy(payable(userProxyAddress)); - uint88 lqtyStaked = uint88(stakingV1.stakes(userProxyAddress)); - - // update the average staked timestamp for LQTY staked by the user + // update the vote power trackers + userState.unallocatedLQTY += _lqtyAmount; + userState.unallocatedOffset += block.timestamp * _lqtyAmount; - // NOTE: Upscale user TS by `TIMESTAMP_PRECISION` - userState.averageStakingTimestamp = _calculateAverageTimestamp( - userState.averageStakingTimestamp, - uint120(block.timestamp) * uint120(TIMESTAMP_PRECISION), - lqtyStaked, - lqtyStaked + _lqtyAmount - ); userStates[msg.sender] = userState; return userProxy; } /// @inheritdoc IGovernance - function depositLQTY(uint88 _lqtyAmount) external { + function depositLQTY(uint256 _lqtyAmount) external { depositLQTY(_lqtyAmount, false, msg.sender); } - function depositLQTY(uint88 _lqtyAmount, bool _doSendRewards, address _recipient) public nonReentrant { - UserProxy userProxy = _updateUserTimestamp(_lqtyAmount); + function depositLQTY(uint256 _lqtyAmount, bool _doSendRewards, address _recipient) public nonReentrant { + UserProxy userProxy = _increaseUserVoteTrackers(_lqtyAmount); (uint256 lusdReceived, uint256 lusdSent, uint256 ethReceived, uint256 ethSent) = userProxy.stake(_lqtyAmount, msg.sender, _doSendRewards, _recipient); @@ -206,17 +177,17 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own } /// @inheritdoc IGovernance - function depositLQTYViaPermit(uint88 _lqtyAmount, PermitParams calldata _permitParams) external { + function depositLQTYViaPermit(uint256 _lqtyAmount, PermitParams calldata _permitParams) external { depositLQTYViaPermit(_lqtyAmount, _permitParams, false, msg.sender); } function depositLQTYViaPermit( - uint88 _lqtyAmount, + uint256 _lqtyAmount, PermitParams calldata _permitParams, bool _doSendRewards, address _recipient ) public nonReentrant { - UserProxy userProxy = _updateUserTimestamp(_lqtyAmount); + UserProxy userProxy = _increaseUserVoteTrackers(_lqtyAmount); (uint256 lusdReceived, uint256 lusdSent, uint256 ethReceived, uint256 ethSent) = userProxy.stakeViaPermit(_lqtyAmount, msg.sender, _permitParams, _doSendRewards, _recipient); @@ -225,11 +196,11 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own } /// @inheritdoc IGovernance - function withdrawLQTY(uint88 _lqtyAmount) external { + function withdrawLQTY(uint256 _lqtyAmount) external { withdrawLQTY(_lqtyAmount, true, msg.sender); } - function withdrawLQTY(uint88 _lqtyAmount, bool _doSendRewards, address _recipient) public nonReentrant { + function withdrawLQTY(uint256 _lqtyAmount, bool _doSendRewards, address _recipient) public nonReentrant { // check that user has reset before changing lqty balance UserState storage userState = userStates[msg.sender]; require(userState.allocatedLQTY == 0, "Governance: must-allocate-zero"); @@ -237,6 +208,21 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own UserProxy userProxy = UserProxy(payable(deriveUserProxyAddress(msg.sender))); require(address(userProxy).code.length != 0, "Governance: user-proxy-not-deployed"); + // Update the offset tracker + if (_lqtyAmount < userState.unallocatedLQTY) { + // The offset decrease is proportional to the partial lqty decrease + uint256 offsetDecrease = _lqtyAmount * userState.unallocatedOffset / userState.unallocatedLQTY; + userState.unallocatedOffset -= offsetDecrease; + } else { + // if _lqtyAmount == userState.unallocatedLqty, zero the offset tracker + userState.unallocatedOffset = 0; + } + + // Update the user's LQTY tracker + userState.unallocatedLQTY -= _lqtyAmount; + + userStates[msg.sender] = userState; + ( uint256 lqtyReceived, uint256 lqtySent, @@ -272,27 +258,24 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own //////////////////////////////////////////////////////////////*/ /// @inheritdoc IGovernance - function epoch() public view returns (uint16) { - return uint16(((block.timestamp - EPOCH_START) / EPOCH_DURATION) + 1); + function epoch() public view returns (uint256) { + return ((block.timestamp - EPOCH_START) / EPOCH_DURATION) + 1; } /// @inheritdoc IGovernance - function epochStart() public view returns (uint32) { - return uint32(EPOCH_START + (epoch() - 1) * EPOCH_DURATION); + function epochStart() public view returns (uint256) { + return EPOCH_START + (epoch() - 1) * EPOCH_DURATION; } /// @inheritdoc IGovernance - function secondsWithinEpoch() public view returns (uint32) { - return uint32((block.timestamp - EPOCH_START) % EPOCH_DURATION); + function secondsWithinEpoch() public view returns (uint256) { + return (block.timestamp - EPOCH_START) % EPOCH_DURATION; } /// @inheritdoc IGovernance - function lqtyToVotes(uint88 _lqtyAmount, uint120 _currentTimestamp, uint120 _averageTimestamp) - public - pure - returns (uint208) - { - return uint208(_lqtyAmount) * uint208(_averageAge(_currentTimestamp, _averageTimestamp)); + function lqtyToVotes(uint256 _lqtyAmount, uint256 _timestamp, uint256 _offset) public pure returns (uint256) { + uint256 prod = _lqtyAmount * _timestamp; + return prod > _offset ? prod - _offset : 0; } /*////////////////////////////////////////////////////////////// @@ -345,18 +328,14 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own view returns (VoteSnapshot memory snapshot, GlobalState memory state, bool shouldUpdate) { - uint16 currentEpoch = epoch(); + uint256 currentEpoch = epoch(); snapshot = votesSnapshot; state = globalState; if (snapshot.forEpoch < currentEpoch - 1) { shouldUpdate = true; - snapshot.votes = lqtyToVotes( - state.countedVoteLQTY, - uint120(epochStart()) * uint120(TIMESTAMP_PRECISION), - state.countedVoteLQTYAverageTimestamp - ); + snapshot.votes = lqtyToVotes(state.countedVoteLQTY, epochStart(), state.countedVoteOffset); snapshot.forEpoch = currentEpoch - 1; } } @@ -388,19 +367,16 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own ) { // Get the storage data - uint16 currentEpoch = epoch(); + uint256 currentEpoch = epoch(); initiativeSnapshot = votesForInitiativeSnapshot[_initiative]; initiativeState = initiativeStates[_initiative]; if (initiativeSnapshot.forEpoch < currentEpoch - 1) { shouldUpdate = true; - uint120 start = uint120(epochStart()) * uint120(TIMESTAMP_PRECISION); - uint208 votes = - lqtyToVotes(initiativeState.voteLQTY, start, initiativeState.averageStakingTimestampVoteLQTY); - uint208 vetos = - lqtyToVotes(initiativeState.vetoLQTY, start, initiativeState.averageStakingTimestampVetoLQTY); - // NOTE: Upscaling to u224 is safe + uint256 start = epochStart(); + uint256 votes = lqtyToVotes(initiativeState.voteLQTY, start, initiativeState.voteOffset); + uint256 vetos = lqtyToVotes(initiativeState.vetoLQTY, start, initiativeState.vetoOffset); initiativeSnapshot.votes = votes; initiativeSnapshot.vetos = vetos; @@ -426,7 +402,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// See the view version of `getInitiativeState` for the underlying logic on Initatives FSM function getInitiativeState(address _initiative) public - returns (InitiativeStatus status, uint16 lastEpochClaim, uint256 claimableAmount) + returns (InitiativeStatus status, uint256 lastEpochClaim, uint256 claimableAmount) { (VoteSnapshot memory votesSnapshot_,) = _snapshotVotes(); (InitiativeVoteSnapshot memory votesForInitiativeSnapshot_, InitiativeState memory initiativeState) = @@ -441,8 +417,8 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own VoteSnapshot memory _votesSnapshot, InitiativeVoteSnapshot memory _votesForInitiativeSnapshot, InitiativeState memory _initiativeState - ) public view returns (InitiativeStatus status, uint16 lastEpochClaim, uint256 claimableAmount) { - uint16 initiativeRegistrationEpoch = registeredInitiatives[_initiative]; + ) public view returns (InitiativeStatus status, uint256 lastEpochClaim, uint256 claimableAmount) { + uint256 initiativeRegistrationEpoch = registeredInitiatives[_initiative]; // == Non existent Condition == // if (initiativeRegistrationEpoch == 0) { @@ -450,7 +426,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// By definition it has zero rewards } - uint16 currentEpoch = epoch(); + uint256 currentEpoch = epoch(); // == Just Registered Condition == // if (initiativeRegistrationEpoch == currentEpoch) { @@ -481,25 +457,12 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own // == Rewards Conditions (votes can be zero, logic is the same) == // // By definition if _votesForInitiativeSnapshot.votes > 0 then _votesSnapshot.votes > 0 + if ( + _votesForInitiativeSnapshot.votes > votingTheshold + && _votesForInitiativeSnapshot.votes > _votesForInitiativeSnapshot.vetos + ) { + uint256 claim = _votesForInitiativeSnapshot.votes * boldAccrued / _votesSnapshot.votes; - uint256 upscaledInitiativeVotes = uint256(_votesForInitiativeSnapshot.votes); - uint256 upscaledInitiativeVetos = uint256(_votesForInitiativeSnapshot.vetos); - uint256 upscaledTotalVotes = uint256(_votesSnapshot.votes); - - if (upscaledInitiativeVotes > votingTheshold && !(upscaledInitiativeVetos >= upscaledInitiativeVotes)) { - /// 2^208 means we only have 2^48 left - /// Therefore we need to scale the value down by 4 orders of magnitude to make it fit - assert(upscaledInitiativeVotes * 1e14 / (VOTING_THRESHOLD_FACTOR / 1e4) > upscaledTotalVotes); - - // 34 times when using 0.03e18 -> 33.3 + 1-> 33 + 1 = 34 - uint256 CUSTOM_PRECISION = WAD / VOTING_THRESHOLD_FACTOR + 1; - - /// Because of the updated timestamp, we can run into overflows if we multiply by `boldAccrued` - /// We use `CUSTOM_PRECISION` for this reason, a smaller multiplicative value - /// The change SHOULD be safe because we already check for `threshold` before getting into these lines - /// As an alternative, this line could be replaced by https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol - uint256 claim = - upscaledInitiativeVotes * CUSTOM_PRECISION / upscaledTotalVotes * boldAccrued / CUSTOM_PRECISION; return (InitiativeStatus.CLAIMABLE, lastEpochClaim, claim); } @@ -507,8 +470,8 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own // e.g. if `UNREGISTRATION_AFTER_EPOCHS` is 4, the 4th epoch flip that would result in SKIP, will result in the initiative being `UNREGISTERABLE` if ( (_initiativeState.lastEpochClaim + UNREGISTRATION_AFTER_EPOCHS < currentEpoch - 1) - || upscaledInitiativeVetos > upscaledInitiativeVotes - && upscaledInitiativeVetos > votingTheshold * UNREGISTRATION_THRESHOLD_FACTOR / WAD + || _votesForInitiativeSnapshot.vetos > _votesForInitiativeSnapshot.votes + && _votesForInitiativeSnapshot.vetos > votingTheshold * UNREGISTRATION_THRESHOLD_FACTOR / WAD ) { return (InitiativeStatus.UNREGISTERABLE, lastEpochClaim, 0); } @@ -519,7 +482,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// @inheritdoc IGovernance function registerInitiative(address _initiative) external nonReentrant { - uint16 currentEpoch = epoch(); + uint256 currentEpoch = epoch(); require(currentEpoch > 2, "Governance: registration-not-yet-enabled"); bold.safeTransferFrom(msg.sender, address(this), REGISTRATION_FEE); @@ -535,13 +498,13 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own // an initiative can be registered if the registrant has more voting power (LQTY * age) // than the registration threshold derived from the previous epoch's total global votes - uint256 upscaledSnapshotVotes = uint256(snapshot.votes); + uint256 upscaledSnapshotVotes = snapshot.votes; + + uint256 totalUserOffset = userState.allocatedOffset + userState.unallocatedOffset; require( - lqtyToVotes( - uint88(stakingV1.stakes(userProxyAddress)), - uint120(epochStart()) * uint120(TIMESTAMP_PRECISION), - userState.averageStakingTimestamp - ) >= upscaledSnapshotVotes * REGISTRATION_THRESHOLD_FACTOR / WAD, + // Check against the user's total voting power, so include both allocated and unallocated LQTY + lqtyToVotes(stakingV1.stakes(userProxyAddress), epochStart(), totalUserOffset) + >= upscaledSnapshotVotes * REGISTRATION_THRESHOLD_FACTOR / WAD, "Governance: insufficient-lqty" ); @@ -560,8 +523,10 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own struct ResetInitiativeData { address initiative; - int88 LQTYVotes; - int88 LQTYVetos; + int256 LQTYVotes; + int256 LQTYVetos; + int256 OffsetVotes; + int256 OffsetVetos; } /// @dev Resets an initiative and return the previous votes @@ -573,33 +538,34 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own { ResetInitiativeData[] memory cachedData = new ResetInitiativeData[](_initiativesToReset.length); - int88[] memory deltaLQTYVotes = new int88[](_initiativesToReset.length); - int88[] memory deltaLQTYVetos = new int88[](_initiativesToReset.length); + int256[] memory deltaLQTYVotes = new int256[](_initiativesToReset.length); + int256[] memory deltaLQTYVetos = new int256[](_initiativesToReset.length); + int256[] memory deltaOffsetVotes = new int256[](_initiativesToReset.length); + int256[] memory deltaOffsetVetos = new int256[](_initiativesToReset.length); // Prepare reset data for (uint256 i; i < _initiativesToReset.length; i++) { Allocation memory alloc = lqtyAllocatedByUserToInitiative[msg.sender][_initiativesToReset[i]]; require(alloc.voteLQTY > 0 || alloc.vetoLQTY > 0, "Governance: nothing to reset"); - // Must be below, else we cannot reset" - // Makes cast safe - assert(alloc.voteLQTY <= uint88(type(int88).max)); - assert(alloc.vetoLQTY <= uint88(type(int88).max)); - // Cache, used to enforce limits later cachedData[i] = ResetInitiativeData({ initiative: _initiativesToReset[i], - LQTYVotes: int88(alloc.voteLQTY), - LQTYVetos: int88(alloc.vetoLQTY) + LQTYVotes: int256(alloc.voteLQTY), + LQTYVetos: int256(alloc.vetoLQTY), + OffsetVotes: int256(alloc.voteOffset), + OffsetVetos: int256(alloc.vetoOffset) }); // -0 is still 0, so its fine to flip both - deltaLQTYVotes[i] = -int88(cachedData[i].LQTYVotes); - deltaLQTYVetos[i] = -int88(cachedData[i].LQTYVetos); + deltaLQTYVotes[i] = -(cachedData[i].LQTYVotes); + deltaLQTYVetos[i] = -(cachedData[i].LQTYVetos); + deltaOffsetVotes[i] = -(cachedData[i].OffsetVotes); + deltaOffsetVetos[i] = -(cachedData[i].OffsetVetos); } // RESET HERE || All initiatives will receive most updated data and 0 votes / vetos - _allocateLQTY(_initiativesToReset, deltaLQTYVotes, deltaLQTYVetos); + _allocateLQTY(_initiativesToReset, deltaLQTYVotes, deltaLQTYVetos, deltaOffsetVotes, deltaOffsetVetos); return cachedData; } @@ -625,8 +591,8 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own function allocateLQTY( address[] calldata _initiativesToReset, address[] calldata _initiatives, - int88[] calldata _absoluteLQTYVotes, - int88[] calldata _absoluteLQTYVetos + int256[] calldata _absoluteLQTYVotes, + int256[] calldata _absoluteLQTYVetos ) external nonReentrant { require(_initiatives.length == _absoluteLQTYVotes.length, "Length"); require(_absoluteLQTYVetos.length == _absoluteLQTYVotes.length, "Length"); @@ -647,6 +613,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// Invariant, 0 allocated = 0 votes UserState memory userState = userStates[msg.sender]; require(userState.allocatedLQTY == 0, "must be a reset"); + require(userState.unallocatedLQTY != 0, "Governance: insufficient-or-allocated-lqty"); // avoid div-by-zero // After cutoff you can only re-apply the same vote // Or vote less @@ -677,8 +644,19 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own } } + int256[] memory absoluteOffsetVotes = new int256[](_initiatives.length); + int256[] memory absoluteOffsetVetos = new int256[](_initiatives.length); + + // Calculate the offset portions that correspond to each LQTY vote and veto portion + for (uint256 x; x < _initiatives.length; x++) { + absoluteOffsetVotes[x] = + _absoluteLQTYVotes[x] * int256(userState.unallocatedOffset) / int256(userState.unallocatedLQTY); + absoluteOffsetVetos[x] = + _absoluteLQTYVetos[x] * int256(userState.unallocatedOffset) / int256(userState.unallocatedLQTY); + } + // Vote here, all values are now absolute changes - _allocateLQTY(_initiatives, _absoluteLQTYVotes, _absoluteLQTYVetos); + _allocateLQTY(_initiatives, _absoluteLQTYVotes, _absoluteLQTYVetos, absoluteOffsetVotes, absoluteOffsetVetos); } // Avoid "stack too deep" by placing these variables in memory @@ -690,6 +668,11 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own InitiativeState initiativeState; InitiativeState prevInitiativeState; Allocation allocation; + uint256 currentEpoch; + int256 deltaLQTYVotes; + int256 deltaLQTYVetos; + int256 deltaOffsetVotes; + int256 deltaOffsetVetos; } /// @dev For each given initiative applies relative changes to the allocation @@ -697,8 +680,10 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// Review the flows as the function could be used in many ways, but it ends up being used in just those 2 ways function _allocateLQTY( address[] memory _initiatives, - int88[] memory _deltaLQTYVotes, - int88[] memory _deltaLQTYVetos + int256[] memory _deltaLQTYVotes, + int256[] memory _deltaLQTYVetos, + int256[] memory _deltaOffsetVotes, + int256[] memory _deltaOffsetVetos ) internal { require( _initiatives.length == _deltaLQTYVotes.length && _initiatives.length == _deltaLQTYVetos.length, @@ -707,14 +692,17 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own AllocateLQTYMemory memory vars; (vars.votesSnapshot_, vars.state) = _snapshotVotes(); - uint16 currentEpoch = epoch(); + vars.currentEpoch = epoch(); vars.userState = userStates[msg.sender]; for (uint256 i = 0; i < _initiatives.length; i++) { address initiative = _initiatives[i]; - int88 deltaLQTYVotes = _deltaLQTYVotes[i]; - int88 deltaLQTYVetos = _deltaLQTYVetos[i]; - assert(deltaLQTYVotes != 0 || deltaLQTYVetos != 0); + vars.deltaLQTYVotes = _deltaLQTYVotes[i]; + vars.deltaLQTYVetos = _deltaLQTYVetos[i]; + assert(vars.deltaLQTYVotes != 0 || vars.deltaLQTYVetos != 0); + + vars.deltaOffsetVotes = _deltaOffsetVotes[i]; + vars.deltaOffsetVetos = _deltaOffsetVetos[i]; /// === Check FSM === /// // Can vote positively in SKIP, CLAIMABLE and CLAIMED states @@ -726,7 +714,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own initiative, vars.votesSnapshot_, vars.votesForInitiativeSnapshot_, vars.initiativeState ); - if (deltaLQTYVotes > 0 || deltaLQTYVetos > 0) { + if (vars.deltaLQTYVotes > 0 || vars.deltaLQTYVetos > 0) { /// You cannot vote on `unregisterable` but a vote may have been there require( status == InitiativeStatus.SKIP || status == InitiativeStatus.CLAIMABLE @@ -736,7 +724,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own } if (status == InitiativeStatus.DISABLED) { - require(deltaLQTYVotes <= 0 && deltaLQTYVetos <= 0, "Must be a withdrawal"); + require(vars.deltaLQTYVotes <= 0 && vars.deltaLQTYVetos <= 0, "Must be a withdrawal"); } /// === UPDATE ACCOUNTING === /// @@ -745,76 +733,69 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own // deep copy of the initiative's state before the allocation vars.prevInitiativeState = InitiativeState( vars.initiativeState.voteLQTY, + vars.initiativeState.voteOffset, vars.initiativeState.vetoLQTY, - vars.initiativeState.averageStakingTimestampVoteLQTY, - vars.initiativeState.averageStakingTimestampVetoLQTY, + vars.initiativeState.vetoOffset, vars.initiativeState.lastEpochClaim ); - // update the average staking timestamp for the initiative based on the user's average staking timestamp - vars.initiativeState.averageStakingTimestampVoteLQTY = _calculateAverageTimestamp( - vars.initiativeState.averageStakingTimestampVoteLQTY, - vars.userState.averageStakingTimestamp, - vars.initiativeState.voteLQTY, - add(vars.initiativeState.voteLQTY, deltaLQTYVotes) - ); - vars.initiativeState.averageStakingTimestampVetoLQTY = _calculateAverageTimestamp( - vars.initiativeState.averageStakingTimestampVetoLQTY, - vars.userState.averageStakingTimestamp, - vars.initiativeState.vetoLQTY, - add(vars.initiativeState.vetoLQTY, deltaLQTYVetos) - ); - // allocate the voting and vetoing LQTY to the initiative - vars.initiativeState.voteLQTY = add(vars.initiativeState.voteLQTY, deltaLQTYVotes); - vars.initiativeState.vetoLQTY = add(vars.initiativeState.vetoLQTY, deltaLQTYVetos); + vars.initiativeState.voteLQTY = add(vars.initiativeState.voteLQTY, vars.deltaLQTYVotes); + vars.initiativeState.vetoLQTY = add(vars.initiativeState.vetoLQTY, vars.deltaLQTYVetos); + + // Update the initiative's vote and veto offsets + vars.initiativeState.voteOffset = add(vars.initiativeState.voteOffset, vars.deltaOffsetVotes); + vars.initiativeState.vetoOffset = add(vars.initiativeState.vetoOffset, vars.deltaOffsetVetos); // update the initiative's state initiativeStates[initiative] = vars.initiativeState; // == GLOBAL STATE == // - // update the average staking timestamp for all counted voting LQTY - /// Discount previous only if the initiative was not unregistered - - /// We update the state only for non-disabled initiaitives - /// Disabled initiaitves have had their totals subtracted already - /// Math is also non associative so we cannot easily compare values + /// We update the state only for non-disabled initiatives + /// Disabled initiatves have had their totals subtracted already if (status != InitiativeStatus.DISABLED) { - /// Removing votes from state desynchs the state until all users remove their votes from the initiative - /// The invariant that holds is: the one that removes the initiatives that have been unregistered - vars.state.countedVoteLQTYAverageTimestamp = _calculateAverageTimestamp( - vars.state.countedVoteLQTYAverageTimestamp, - vars.prevInitiativeState.averageStakingTimestampVoteLQTY, - vars.state.countedVoteLQTY, - vars.state.countedVoteLQTY - vars.prevInitiativeState.voteLQTY - ); assert(vars.state.countedVoteLQTY >= vars.prevInitiativeState.voteLQTY); - vars.state.countedVoteLQTY -= vars.prevInitiativeState.voteLQTY; - vars.state.countedVoteLQTYAverageTimestamp = _calculateAverageTimestamp( - vars.state.countedVoteLQTYAverageTimestamp, - vars.initiativeState.averageStakingTimestampVoteLQTY, - vars.state.countedVoteLQTY, - vars.state.countedVoteLQTY + vars.initiativeState.voteLQTY - ); + // Remove old initative LQTY and offset from global count + vars.state.countedVoteLQTY -= vars.prevInitiativeState.voteLQTY; + vars.state.countedVoteOffset -= vars.prevInitiativeState.voteOffset; + // Add new initative LQTY and offset to global count vars.state.countedVoteLQTY += vars.initiativeState.voteLQTY; + vars.state.countedVoteOffset += vars.initiativeState.voteOffset; } - // == USER ALLOCATION == // + // == USER ALLOCATION TO INITIATIVE == // - // allocate the voting and vetoing LQTY to the initiative + // Record the vote and veto LQTY and offsets by user to initative vars.allocation = lqtyAllocatedByUserToInitiative[msg.sender][initiative]; - vars.allocation.voteLQTY = add(vars.allocation.voteLQTY, deltaLQTYVotes); - vars.allocation.vetoLQTY = add(vars.allocation.vetoLQTY, deltaLQTYVetos); - vars.allocation.atEpoch = currentEpoch; + // Update offsets + vars.allocation.voteOffset = add(vars.allocation.voteOffset, vars.deltaOffsetVotes); + vars.allocation.vetoOffset = add(vars.allocation.vetoOffset, vars.deltaOffsetVetos); + + // Update votes and vetos + vars.allocation.voteLQTY = add(vars.allocation.voteLQTY, vars.deltaLQTYVotes); + vars.allocation.vetoLQTY = add(vars.allocation.vetoLQTY, vars.deltaLQTYVetos); + + vars.allocation.atEpoch = vars.currentEpoch; + require(!(vars.allocation.voteLQTY != 0 && vars.allocation.vetoLQTY != 0), "Governance: vote-and-veto"); lqtyAllocatedByUserToInitiative[msg.sender][initiative] = vars.allocation; // == USER STATE == // - vars.userState.allocatedLQTY = add(vars.userState.allocatedLQTY, deltaLQTYVotes + deltaLQTYVetos); + // Remove from the user's unallocated LQTY and offset + vars.userState.unallocatedLQTY = + sub(vars.userState.unallocatedLQTY, (vars.deltaLQTYVotes + vars.deltaLQTYVetos)); + vars.userState.unallocatedOffset = + sub(vars.userState.unallocatedOffset, (vars.deltaOffsetVotes + vars.deltaOffsetVetos)); + + // Add to the user's allocated LQTY and offset + vars.userState.allocatedLQTY = + add(vars.userState.allocatedLQTY, (vars.deltaLQTYVotes + vars.deltaLQTYVetos)); + vars.userState.allocatedOffset = + add(vars.userState.allocatedOffset, (vars.deltaOffsetVotes + vars.deltaOffsetVetos)); // Replaces try / catch | Enforces sufficient gas is passed bool success = safeCallWithMinGas( @@ -823,16 +804,17 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own 0, abi.encodeCall( IInitiative.onAfterAllocateLQTY, - (currentEpoch, msg.sender, vars.userState, vars.allocation, vars.initiativeState) + (vars.currentEpoch, msg.sender, vars.userState, vars.allocation, vars.initiativeState) ) ); - emit AllocateLQTY(msg.sender, initiative, deltaLQTYVotes, deltaLQTYVetos, currentEpoch, success); + emit AllocateLQTY( + msg.sender, initiative, vars.deltaLQTYVotes, vars.deltaLQTYVetos, vars.currentEpoch, success + ); } require( - vars.userState.allocatedLQTY == 0 - || vars.userState.allocatedLQTY <= uint88(stakingV1.stakes(deriveUserProxyAddress(msg.sender))), + vars.userState.allocatedLQTY <= stakingV1.stakes(deriveUserProxyAddress(msg.sender)), "Governance: insufficient-or-allocated-lqty" ); @@ -852,23 +834,16 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own require(status == InitiativeStatus.UNREGISTERABLE, "Governance: cannot-unregister-initiative"); // Remove weight from current state - uint16 currentEpoch = epoch(); + uint256 currentEpoch = epoch(); // NOTE: Safe to remove | See `check_claim_soundness` assert(initiativeState.lastEpochClaim < currentEpoch - 1); - // recalculate the average staking timestamp for all counted voting LQTY if the initiative was counted in - // Removing votes from state desynchs the state until all users remove their votes from the initiative - - state.countedVoteLQTYAverageTimestamp = _calculateAverageTimestamp( - state.countedVoteLQTYAverageTimestamp, - initiativeState.averageStakingTimestampVoteLQTY, - state.countedVoteLQTY, - state.countedVoteLQTY - initiativeState.voteLQTY - ); assert(state.countedVoteLQTY >= initiativeState.voteLQTY); - /// RECON: Overflow + assert(state.countedVoteOffset >= initiativeState.voteOffset); + state.countedVoteLQTY -= initiativeState.voteLQTY; + state.countedVoteOffset -= initiativeState.voteOffset; globalState = state; @@ -929,7 +904,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own return claimableAmount; } - function _requireNoNOP(int88[] memory _absoluteLQTYVotes, int88[] memory _absoluteLQTYVetos) internal pure { + function _requireNoNOP(int256[] memory _absoluteLQTYVotes, int256[] memory _absoluteLQTYVetos) internal pure { for (uint256 i; i < _absoluteLQTYVotes.length; i++) { require(_absoluteLQTYVotes[i] > 0 || _absoluteLQTYVetos[i] > 0, "Governance: voting nothing"); } diff --git a/src/UniV4Donations.sol b/src/UniV4Donations.sol index 3d38eb7e..8c80a094 100644 --- a/src/UniV4Donations.sol +++ b/src/UniV4Donations.sol @@ -20,7 +20,7 @@ contract UniV4Donations is BribeInitiative, BaseHook { using PoolIdLibrary for PoolKey; event DonateToPool(uint256 amount); - event RestartVesting(uint16 epoch, uint240 amount); + event RestartVesting(uint256 epoch, uint256 amount); uint256 public immutable VESTING_EPOCH_START; uint256 public immutable VESTING_EPOCH_DURATION; @@ -31,8 +31,8 @@ contract UniV4Donations is BribeInitiative, BaseHook { int24 private immutable tickSpacing; struct Vesting { - uint240 amount; - uint16 epoch; + uint256 amount; + uint256 epoch; uint256 released; } @@ -63,19 +63,19 @@ contract UniV4Donations is BribeInitiative, BaseHook { tickSpacing = _tickSpacing; } - function vestingEpoch() public view returns (uint16) { - return uint16(((block.timestamp - VESTING_EPOCH_START) / VESTING_EPOCH_DURATION)) + 1; + function vestingEpoch() public view returns (uint256) { + return ((block.timestamp - VESTING_EPOCH_START) / VESTING_EPOCH_DURATION) + 1; } function vestingEpochStart() public view returns (uint256) { return VESTING_EPOCH_START + ((vestingEpoch() - 1) * VESTING_EPOCH_DURATION); } - function _restartVesting(uint240 claimed) internal returns (Vesting memory) { - uint16 epoch = vestingEpoch(); + function _restartVesting(uint256 claimed) internal returns (Vesting memory) { + uint256 epoch = vestingEpoch(); Vesting memory _vesting = vesting; if (_vesting.epoch < epoch) { - _vesting.amount = claimed + _vesting.amount - uint240(_vesting.released); // roll over unclaimed amount + _vesting.amount = claimed + _vesting.amount - uint256(_vesting.released); // roll over unclaimed amount _vesting.epoch = epoch; _vesting.released = 0; vesting = _vesting; @@ -88,7 +88,7 @@ contract UniV4Donations is BribeInitiative, BaseHook { uint256 public received; /// @notice On claim we deposit the rewards - This is to prevent a griefing - function onClaimForInitiative(uint16, uint256 _bold) external override onlyGovernance { + function onClaimForInitiative(uint256, uint256 _bold) external override onlyGovernance { received += _bold; } @@ -106,7 +106,7 @@ contract UniV4Donations is BribeInitiative, BaseHook { received = 0; // Rest of logic - Vesting memory _vesting = _restartVesting(uint240(toUse)); + Vesting memory _vesting = _restartVesting(toUse); uint256 amount = (_vesting.amount * (block.timestamp - vestingEpochStart()) / VESTING_EPOCH_DURATION) - _vesting.released; diff --git a/src/UserProxy.sol b/src/UserProxy.sol index b34c8022..2f1ffd7d 100644 --- a/src/UserProxy.sol +++ b/src/UserProxy.sol @@ -120,8 +120,8 @@ contract UserProxy is IUserProxy { } /// @inheritdoc IUserProxy - function staked() external view returns (uint88) { - return uint88(stakingV1.stakes(address(this))); + function staked() external view returns (uint256) { + return stakingV1.stakes(address(this)); } receive() external payable {} diff --git a/src/interfaces/IBribeInitiative.sol b/src/interfaces/IBribeInitiative.sol index 4f349c9f..0ec54aab 100644 --- a/src/interfaces/IBribeInitiative.sol +++ b/src/interfaces/IBribeInitiative.sol @@ -6,10 +6,10 @@ import {IERC20} from "openzeppelin/contracts/interfaces/IERC20.sol"; import {IGovernance} from "./IGovernance.sol"; interface IBribeInitiative { - event DepositBribe(address depositor, uint128 boldAmount, uint128 bribeTokenAmount, uint16 epoch); - event ModifyLQTYAllocation(address user, uint16 epoch, uint88 lqtyAllocated, uint120 averageTimestamp); - event ModifyTotalLQTYAllocation(uint16 epoch, uint88 totalLQTYAllocated, uint120 averageTimestamp); - event ClaimBribe(address user, uint16 epoch, uint256 boldAmount, uint256 bribeTokenAmount); + event DepositBribe(address depositor, uint256 boldAmount, uint256 bribeTokenAmount, uint256 epoch); + event ModifyLQTYAllocation(address user, uint256 epoch, uint256 lqtyAllocated, uint256 offset); + event ModifyTotalLQTYAllocation(uint256 epoch, uint256 totalLQTYAllocated, uint256 offset); + event ClaimBribe(address user, uint256 epoch, uint256 boldAmount, uint256 bribeTokenAmount); /// @notice Address of the governance contract /// @return governance Adress of the governance contract @@ -22,36 +22,36 @@ interface IBribeInitiative { function bribeToken() external view returns (IERC20 bribeToken); struct Bribe { - uint128 boldAmount; - uint128 bribeTokenAmount; // [scaled as 10 ** bribeToken.decimals()] + uint256 boldAmount; + uint256 bribeTokenAmount; // [scaled as 10 ** bribeToken.decimals()] } /// @notice Amount of bribe tokens deposited for a given epoch /// @param _epoch Epoch at which the bribe was deposited /// @return boldAmount Amount of BOLD tokens deposited /// @return bribeTokenAmount Amount of bribe tokens deposited - function bribeByEpoch(uint16 _epoch) external view returns (uint128 boldAmount, uint128 bribeTokenAmount); + function bribeByEpoch(uint256 _epoch) external view returns (uint256 boldAmount, uint256 bribeTokenAmount); /// @notice Check if a user has claimed bribes for a given epoch /// @param _user Address of the user /// @param _epoch Epoch at which the bribe may have been claimed by the user /// @return claimed If the user has claimed the bribe - function claimedBribeAtEpoch(address _user, uint16 _epoch) external view returns (bool claimed); + function claimedBribeAtEpoch(address _user, uint256 _epoch) external view returns (bool claimed); /// @notice Total LQTY allocated to the initiative at a given epoch /// @param _epoch Epoch at which the LQTY was allocated /// @return totalLQTYAllocated Total LQTY allocated - function totalLQTYAllocatedByEpoch(uint16 _epoch) + function totalLQTYAllocatedByEpoch(uint256 _epoch) external view - returns (uint88 totalLQTYAllocated, uint120 averageTimestamp); + returns (uint256 totalLQTYAllocated, uint256 averageTimestamp); /// @notice LQTY allocated by a user to the initiative at a given epoch /// @param _user Address of the user /// @param _epoch Epoch at which the LQTY was allocated by the user /// @return lqtyAllocated LQTY allocated by the user - function lqtyAllocatedByUserAtEpoch(address _user, uint16 _epoch) + function lqtyAllocatedByUserAtEpoch(address _user, uint256 _epoch) external view - returns (uint88 lqtyAllocated, uint120 averageTimestamp); + returns (uint256 lqtyAllocated, uint256 averageTimestamp); /// @notice Deposit bribe tokens for a given epoch /// @dev The caller has to approve this contract to spend the BOLD and bribe tokens. @@ -59,15 +59,15 @@ interface IBribeInitiative { /// @param _boldAmount Amount of BOLD tokens to deposit /// @param _bribeTokenAmount Amount of bribe tokens to deposit /// @param _epoch Epoch at which the bribe is deposited - function depositBribe(uint128 _boldAmount, uint128 _bribeTokenAmount, uint16 _epoch) external; + function depositBribe(uint256 _boldAmount, uint256 _bribeTokenAmount, uint256 _epoch) external; struct ClaimData { // Epoch at which the user wants to claim the bribes - uint16 epoch; + uint256 epoch; // Epoch at which the user updated the LQTY allocation for this initiative - uint16 prevLQTYAllocationEpoch; + uint256 prevLQTYAllocationEpoch; // Epoch at which the total LQTY allocation is updated for this initiative - uint16 prevTotalLQTYAllocationEpoch; + uint256 prevTotalLQTYAllocationEpoch; } /// @notice Claim bribes for a user @@ -80,8 +80,8 @@ interface IBribeInitiative { returns (uint256 boldAmount, uint256 bribeTokenAmount); /// @notice Given a user address return the last recorded epoch for their allocation - function getMostRecentUserEpoch(address _user) external view returns (uint16); + function getMostRecentUserEpoch(address _user) external view returns (uint256); /// @notice Return the last recorded epoch for the system - function getMostRecentTotalEpoch() external view returns (uint16); + function getMostRecentTotalEpoch() external view returns (uint256); } diff --git a/src/interfaces/IGovernance.sol b/src/interfaces/IGovernance.sol index 8df01471..167a282c 100644 --- a/src/interfaces/IGovernance.sol +++ b/src/interfaces/IGovernance.sol @@ -63,16 +63,16 @@ interface IGovernance { event ClaimForInitiative(address indexed initiative, uint256 bold, uint256 forEpoch, bool hookSuccess); struct Configuration { - uint128 registrationFee; - uint128 registrationThresholdFactor; - uint128 unregistrationThresholdFactor; - uint16 unregistrationAfterEpochs; - uint128 votingThresholdFactor; - uint88 minClaim; - uint88 minAccrual; - uint32 epochStart; - uint32 epochDuration; - uint32 epochVotingCutoff; + uint256 registrationFee; + uint256 registrationThresholdFactor; + uint256 unregistrationThresholdFactor; + uint256 unregistrationAfterEpochs; + uint256 votingThresholdFactor; + uint256 minClaim; + uint256 minAccrual; + uint256 epochStart; + uint256 epochDuration; + uint256 epochVotingCutoff; } function registerInitialInitiatives(address[] memory _initiatives) external; @@ -124,21 +124,21 @@ interface IGovernance { function boldAccrued() external view returns (uint256 boldAccrued); struct VoteSnapshot { - uint240 votes; // Votes at epoch transition - uint16 forEpoch; // Epoch for which the votes are counted + uint256 votes; // Votes at epoch transition + uint256 forEpoch; // Epoch for which the votes are counted } struct InitiativeVoteSnapshot { - uint224 votes; // Votes at epoch transition - uint16 forEpoch; // Epoch for which the votes are counted - uint16 lastCountedEpoch; // Epoch at which which the votes where counted last in the global snapshot - uint224 vetos; // Vetos at epoch transition + uint256 votes; // Votes at epoch transition + uint256 forEpoch; // Epoch for which the votes are counted + uint256 lastCountedEpoch; // Epoch at which which the votes where counted last in the global snapshot + uint256 vetos; // Vetos at epoch transition } /// @notice Returns the vote count snapshot of the previous epoch /// @return votes Number of votes /// @return forEpoch Epoch for which the votes are counted - function votesSnapshot() external view returns (uint240 votes, uint16 forEpoch); + function votesSnapshot() external view returns (uint256 votes, uint256 forEpoch); /// @notice Returns the vote count snapshot for an initiative of the previous epoch /// @param _initiative Address of the initiative /// @return votes Number of votes @@ -147,73 +147,77 @@ interface IGovernance { function votesForInitiativeSnapshot(address _initiative) external view - returns (uint224 votes, uint16 forEpoch, uint16 lastCountedEpoch, uint224 vetos); + returns (uint256 votes, uint256 forEpoch, uint256 lastCountedEpoch, uint256 vetos); struct Allocation { - uint88 voteLQTY; // LQTY allocated vouching for the initiative - uint88 vetoLQTY; // LQTY vetoing the initiative - uint16 atEpoch; // Epoch at which the allocation was last updated + uint256 voteLQTY; // LQTY allocated vouching for the initiative + uint256 voteOffset; // Offset associated with LQTY vouching for the initiative + uint256 vetoLQTY; // LQTY vetoing the initiative + uint256 vetoOffset; // Offset associated with LQTY vetoing the initiative + uint256 atEpoch; // Epoch at which the allocation was last updated } struct UserState { - uint88 allocatedLQTY; // LQTY allocated by the user - uint120 averageStakingTimestamp; // Average timestamp at which LQTY was staked by the user + uint256 unallocatedLQTY; // LQTY deposited and unallocated + uint256 unallocatedOffset; // The offset sum corresponding to the unallocated LQTY + uint256 allocatedLQTY; // LQTY allocated by the user to initatives + uint256 allocatedOffset; // The offset sum corresponding to the allocated LQTY } struct InitiativeState { - uint88 voteLQTY; // LQTY allocated vouching for the initiative - uint88 vetoLQTY; // LQTY allocated vetoing the initiative - uint120 averageStakingTimestampVoteLQTY; // Average staking timestamp of the voting LQTY for the initiative - uint120 averageStakingTimestampVetoLQTY; // Average staking timestamp of the vetoing LQTY for the initiative - uint16 lastEpochClaim; + uint256 voteLQTY; // LQTY allocated vouching for the initiative + uint256 voteOffset; // Offset associated with LQTY vouching for to the initative + uint256 vetoLQTY; // LQTY allocated vetoing the initiative + uint256 vetoOffset; // Offset associated with LQTY veoting the initative + uint256 lastEpochClaim; } struct GlobalState { - uint88 countedVoteLQTY; // Total LQTY that is included in vote counting - uint120 countedVoteLQTYAverageTimestamp; // Average timestamp: derived initiativeAllocation.averageTimestamp + uint256 countedVoteLQTY; // Total LQTY that is included in vote counting + uint256 countedVoteOffset; // Offset associated with the counted vote LQTY } /// @notice Returns the user's state - /// @param _user Address of the user - /// @return allocatedLQTY LQTY allocated by the user - /// @return averageStakingTimestamp Average timestamp at which LQTY was staked (deposited) by the user - function userStates(address _user) external view returns (uint88 allocatedLQTY, uint120 averageStakingTimestamp); + /// @return unallocatedLQTY LQTY deposited and unallocated + /// @return unallocatedOffset Offset associated with unallocated LQTY + /// @return allocatedLQTY allocated by the user to initatives + /// @return allocatedOffset Offset associated with allocated LQTY + function userStates(address _user) + external + view + returns (uint256 unallocatedLQTY, uint256 unallocatedOffset, uint256 allocatedLQTY, uint256 allocatedOffset); /// @notice Returns the initiative's state /// @param _initiative Address of the initiative /// @return voteLQTY LQTY allocated vouching for the initiative + /// @return voteOffset Offset associated with voteLQTY /// @return vetoLQTY LQTY allocated vetoing the initiative - /// @return averageStakingTimestampVoteLQTY // Average staking timestamp of the voting LQTY for the initiative - /// @return averageStakingTimestampVetoLQTY // Average staking timestamp of the vetoing LQTY for the initiative + /// @return vetoOffset Offset associated with vetoLQTY /// @return lastEpochClaim // Last epoch at which rewards were claimed function initiativeStates(address _initiative) external view - returns ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - uint16 lastEpochClaim - ); + returns (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset, uint256 lastEpochClaim); /// @notice Returns the global state /// @return countedVoteLQTY Total LQTY that is included in vote counting - /// @return countedVoteLQTYAverageTimestamp Average timestamp: derived initiativeAllocation.averageTimestamp - function globalState() external view returns (uint88 countedVoteLQTY, uint120 countedVoteLQTYAverageTimestamp); + /// @return countedVoteOffset Offset associated with countedVoteLQTY + function globalState() external view returns (uint256 countedVoteLQTY, uint256 countedVoteOffset); /// @notice Returns the amount of voting and vetoing LQTY a user allocated to an initiative /// @param _user Address of the user /// @param _initiative Address of the initiative /// @return voteLQTY LQTY allocated vouching for the initiative - /// @return vetoLQTY LQTY allocated vetoing the initiative + /// @return voteOffset The offset associated with voteLQTY + /// @return vetoLQTY allocated vetoing the initiative + /// @return vetoOffset the offset associated with vetoLQTY /// @return atEpoch Epoch at which the allocation was last updated function lqtyAllocatedByUserToInitiative(address _user, address _initiative) external view - returns (uint88 voteLQTY, uint88 vetoLQTY, uint16 atEpoch); + returns (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset, uint256 atEpoch); /// @notice Returns when an initiative was registered /// @param _initiative Address of the initiative /// @return atEpoch Epoch at which the initiative was registered - function registeredInitiatives(address _initiative) external view returns (uint16 atEpoch); + function registeredInitiatives(address _initiative) external view returns (uint256 atEpoch); /*////////////////////////////////////////////////////////////// STAKING @@ -222,19 +226,19 @@ interface IGovernance { /// @notice Deposits LQTY /// @dev The caller has to approve their `UserProxy` address to spend the LQTY tokens /// @param _lqtyAmount Amount of LQTY to deposit - function depositLQTY(uint88 _lqtyAmount) external; + function depositLQTY(uint256 _lqtyAmount) external; /// @notice Deposits LQTY /// @dev The caller has to approve their `UserProxy` address to spend the LQTY tokens /// @param _lqtyAmount Amount of LQTY to deposit /// @param _doSendRewards If true, send rewards claimed from LQTY staking /// @param _recipient Address to which the tokens should be sent - function depositLQTY(uint88 _lqtyAmount, bool _doSendRewards, address _recipient) external; + function depositLQTY(uint256 _lqtyAmount, bool _doSendRewards, address _recipient) external; /// @notice Deposits LQTY via Permit /// @param _lqtyAmount Amount of LQTY to deposit /// @param _permitParams Permit parameters - function depositLQTYViaPermit(uint88 _lqtyAmount, PermitParams calldata _permitParams) external; + function depositLQTYViaPermit(uint256 _lqtyAmount, PermitParams calldata _permitParams) external; /// @notice Deposits LQTY via Permit /// @param _lqtyAmount Amount of LQTY to deposit @@ -242,7 +246,7 @@ interface IGovernance { /// @param _doSendRewards If true, send rewards claimed from LQTY staking /// @param _recipient Address to which the tokens should be sent function depositLQTYViaPermit( - uint88 _lqtyAmount, + uint256 _lqtyAmount, PermitParams calldata _permitParams, bool _doSendRewards, address _recipient @@ -250,13 +254,13 @@ interface IGovernance { /// @notice Withdraws LQTY and claims any accrued LUSD and ETH rewards from StakingV1 /// @param _lqtyAmount Amount of LQTY to withdraw - function withdrawLQTY(uint88 _lqtyAmount) external; + function withdrawLQTY(uint256 _lqtyAmount) external; /// @notice Withdraws LQTY and claims any accrued LUSD and ETH rewards from StakingV1 /// @param _lqtyAmount Amount of LQTY to withdraw /// @param _doSendRewards If true, send rewards claimed from LQTY staking /// @param _recipient Address to which the tokens should be sent - function withdrawLQTY(uint88 _lqtyAmount, bool _doSendRewards, address _recipient) external; + function withdrawLQTY(uint256 _lqtyAmount, bool _doSendRewards, address _recipient) external; /// @notice Claims staking rewards from StakingV1 without unstaking /// @dev Note: in the unlikely event that the caller's `UserProxy` holds any LQTY tokens, they will also be sent to `_rewardRecipient` @@ -271,22 +275,20 @@ interface IGovernance { /// @notice Returns the current epoch number /// @return epoch Current epoch - function epoch() external view returns (uint16 epoch); + function epoch() external view returns (uint256 epoch); /// @notice Returns the timestamp at which the current epoch started /// @return epochStart Epoch start of the current epoch - function epochStart() external view returns (uint32 epochStart); + function epochStart() external view returns (uint256 epochStart); /// @notice Returns the number of seconds that have gone by since the current epoch started /// @return secondsWithinEpoch Seconds within the current epoch - function secondsWithinEpoch() external view returns (uint32 secondsWithinEpoch); - /// @notice Returns the number of votes per LQTY for a user - /// @param _lqtyAmount Amount of LQTY to convert to votes - /// @param _currentTimestamp Current timestamp - /// @param _averageTimestamp Average timestamp at which the LQTY was staked + function secondsWithinEpoch() external view returns (uint256 secondsWithinEpoch); + + /// @notice Returns the voting power for an entity (i.e. user or initiative) at a given timestamp + /// @param _lqtyAmount Amount of LQTY associated with the entity + /// @param _timestamp Timestamp at which to calculate voting power + /// @param _offset The entity's offset sum /// @return votes Number of votes - function lqtyToVotes(uint88 _lqtyAmount, uint120 _currentTimestamp, uint120 _averageTimestamp) - external - pure - returns (uint208); + function lqtyToVotes(uint256 _lqtyAmount, uint256 _timestamp, uint256 _offset) external pure returns (uint256); /// @dev Returns the most up to date voting threshold /// In contrast to `getLatestVotingThreshold` this function updates the snapshot @@ -353,14 +355,14 @@ interface IGovernance { function getInitiativeState(address _initiative) external - returns (InitiativeStatus status, uint16 lastEpochClaim, uint256 claimableAmount); + returns (InitiativeStatus status, uint256 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); + ) external view returns (InitiativeStatus status, uint256 lastEpochClaim, uint256 claimableAmount); /// @notice Registers a new initiative /// @param _initiative Address of the initiative @@ -380,8 +382,8 @@ interface IGovernance { function allocateLQTY( address[] calldata _resetInitiatives, address[] memory _initiatives, - int88[] memory _absoluteLQTYVotes, - int88[] memory absoluteLQTYVetos + int256[] memory _absoluteLQTYVotes, + int256[] memory absoluteLQTYVetos ) external; /// @notice Splits accrued funds according to votes received between all initiatives diff --git a/src/interfaces/IInitiative.sol b/src/interfaces/IInitiative.sol index ddb3179b..4a415c54 100644 --- a/src/interfaces/IInitiative.sol +++ b/src/interfaces/IInitiative.sol @@ -6,11 +6,11 @@ import {IGovernance} from "./IGovernance.sol"; interface IInitiative { /// @notice Callback hook that is called by Governance after the initiative was successfully registered /// @param _atEpoch Epoch at which the initiative is registered - function onRegisterInitiative(uint16 _atEpoch) external; + function onRegisterInitiative(uint256 _atEpoch) external; /// @notice Callback hook that is called by Governance after the initiative was unregistered /// @param _atEpoch Epoch at which the initiative is unregistered - function onUnregisterInitiative(uint16 _atEpoch) external; + function onUnregisterInitiative(uint256 _atEpoch) external; /// @notice Callback hook that is called by Governance after the LQTY allocation is updated by a user /// @param _currentEpoch Epoch at which the LQTY allocation is updated @@ -19,7 +19,7 @@ interface IInitiative { /// @param _allocation Allocation state from user to initiative /// @param _initiativeState Initiative state function onAfterAllocateLQTY( - uint16 _currentEpoch, + uint256 _currentEpoch, address _user, IGovernance.UserState calldata _userState, IGovernance.Allocation calldata _allocation, @@ -30,5 +30,5 @@ interface IInitiative { /// to the initiative /// @param _claimEpoch Epoch at which the claim was distributed /// @param _bold Amount of BOLD that was distributed - function onClaimForInitiative(uint16 _claimEpoch, uint256 _bold) external; + function onClaimForInitiative(uint256 _claimEpoch, uint256 _bold) external; } diff --git a/src/interfaces/IUserProxy.sol b/src/interfaces/IUserProxy.sol index 166c8259..7da78371 100644 --- a/src/interfaces/IUserProxy.sol +++ b/src/interfaces/IUserProxy.sol @@ -76,5 +76,5 @@ interface IUserProxy { /// @notice Returns the current amount LQTY staked by a user in the V1 staking contract /// @return staked Amount of LQTY tokens staked - function staked() external view returns (uint88); + function staked() external view returns (uint256); } diff --git a/src/utils/DoubleLinkedList.sol b/src/utils/DoubleLinkedList.sol index 7c10fec1..f6fc97ab 100644 --- a/src/utils/DoubleLinkedList.sol +++ b/src/utils/DoubleLinkedList.sol @@ -6,13 +6,14 @@ pragma solidity ^0.8.24; /// and the tail is defined as the null item's next pointer ([tail][prev][item][next][head]) library DoubleLinkedList { struct Item { - uint224 value; - uint16 prev; - uint16 next; + uint256 lqty; + uint256 offset; + uint256 prev; + uint256 next; } struct List { - mapping(uint16 => Item) items; + mapping(uint256 => Item) items; } error IdIsZero(); @@ -22,14 +23,14 @@ library DoubleLinkedList { /// @notice Returns the head item id of the list /// @param list Linked list which contains the item /// @return _ Id of the head item - function getHead(List storage list) internal view returns (uint16) { + function getHead(List storage list) internal view returns (uint256) { return list.items[0].prev; } /// @notice Returns the tail item id of the list /// @param list Linked list which contains the item /// @return _ Id of the tail item - function getTail(List storage list) internal view returns (uint16) { + function getTail(List storage list) internal view returns (uint256) { return list.items[0].next; } @@ -37,7 +38,7 @@ library DoubleLinkedList { /// @param list Linked list which contains the items /// @param id Id of the current item /// @return _ Id of the current item's next item - function getNext(List storage list, uint16 id) internal view returns (uint16) { + function getNext(List storage list, uint256 id) internal view returns (uint256) { return list.items[id].next; } @@ -45,23 +46,24 @@ library DoubleLinkedList { /// @param list Linked list which contains the items /// @param id Id of the current item /// @return _ Id of the current item's previous item - function getPrev(List storage list, uint16 id) internal view returns (uint16) { + function getPrev(List storage list, uint256 id) internal view returns (uint256) { return list.items[id].prev; } /// @notice Returns the value of item `id` /// @param list Linked list which contains the item /// @param id Id of the item - /// @return _ Value of the item - function getValue(List storage list, uint16 id) internal view returns (uint224) { - return list.items[id].value; + /// @return LQTY associated with the item + /// @return Offset associated with the item's LQTY + function getLQTYAndOffset(List storage list, uint256 id) internal view returns (uint256, uint256) { + return (list.items[id].lqty, list.items[id].offset); } /// @notice Returns the item `id` /// @param list Linked list which contains the item /// @param id Id of the item /// @return _ Item - function getItem(List storage list, uint16 id) internal view returns (Item memory) { + function getItem(List storage list, uint256 id) internal view returns (Item memory) { return list.items[id]; } @@ -69,7 +71,7 @@ library DoubleLinkedList { /// @param list Linked list which should contain the item /// @param id Id of the item to check /// @return _ True if the list contains the item, false otherwise - function contains(List storage list, uint16 id) internal view returns (bool) { + function contains(List storage list, uint256 id) internal view returns (bool) { if (id == 0) revert IdIsZero(); return (list.items[id].prev != 0 || list.items[id].next != 0 || list.items[0].next == id); } @@ -79,16 +81,18 @@ library DoubleLinkedList { /// @dev This function should not be called with an `id` that is already in the list. /// @param list Linked list which contains the next item and into which the new item will be inserted /// @param id Id of the item to insert - /// @param value Value of the item to insert + /// @param lqty amount of LQTY + /// @param offset associated with the LQTY amount /// @param next Id of the item which should follow item `id` - function insert(List storage list, uint16 id, uint224 value, uint16 next) internal { + function insert(List storage list, uint256 id, uint256 lqty, uint256 offset, uint256 next) internal { if (contains(list, id)) revert ItemInList(); if (next != 0 && !contains(list, next)) revert ItemNotInList(); - uint16 prev = list.items[next].prev; + uint256 prev = list.items[next].prev; list.items[prev].next = id; list.items[next].prev = id; list.items[id].prev = prev; list.items[id].next = next; - list.items[id].value = value; + list.items[id].lqty = lqty; + list.items[id].offset = offset; } } diff --git a/src/utils/EncodingDecodingLib.sol b/src/utils/EncodingDecodingLib.sol deleted file mode 100644 index 79026859..00000000 --- a/src/utils/EncodingDecodingLib.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.24; - -library EncodingDecodingLib { - function encodeLQTYAllocation(uint88 _lqty, uint120 _averageTimestamp) internal pure returns (uint224) { - uint224 _value = (uint224(_lqty) << 120) | _averageTimestamp; - return _value; - } - - function decodeLQTYAllocation(uint224 _value) internal pure returns (uint88, uint120) { - return (uint88(_value >> 120), uint120(_value)); - } -} diff --git a/src/utils/Math.sol b/src/utils/Math.sol index ba18e214..67a6c0ad 100644 --- a/src/utils/Math.sol +++ b/src/utils/Math.sol @@ -1,17 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -function add(uint88 a, int88 b) pure returns (uint88) { +function add(uint256 a, int256 b) pure returns (uint256) { if (b < 0) { return a - abs(b); } - return a + uint88(b); + return a + uint256(b); +} + +function sub(uint256 a, int256 b) pure returns (uint256) { + if (b < 0) { + return a + abs(b); + } + return a - uint256(b); } function max(uint256 a, uint256 b) pure returns (uint256) { return a > b ? a : b; } -function abs(int88 a) pure returns (uint88) { - return a < 0 ? uint88(uint256(-int256(a))) : uint88(a); +function abs(int256 a) pure returns (uint256) { + return a < 0 ? uint256(-int256(a)) : uint256(a); } diff --git a/src/utils/UniqueArray.sol b/src/utils/UniqueArray.sol index 8a8c2400..c7b47e71 100644 --- a/src/utils/UniqueArray.sol +++ b/src/utils/UniqueArray.sol @@ -23,7 +23,7 @@ function _requireNoDuplicates(address[] calldata arr) pure { } } -function _requireNoNegatives(int88[] memory vals) pure { +function _requireNoNegatives(int256[] memory vals) pure { uint256 arrLength = vals.length; for (uint i; i < arrLength; i++) { diff --git a/test/BribeInitiative.t.sol b/test/BribeInitiative.t.sol index b08c0f16..f3fc94a9 100644 --- a/test/BribeInitiative.t.sol +++ b/test/BribeInitiative.t.sol @@ -25,15 +25,15 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { address private constant initiative2 = address(0x2); address private constant initiative3 = address(0x3); - uint128 private constant REGISTRATION_FEE = 1e18; - uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; - uint32 private constant EPOCH_DURATION = 7 days; // 7 days - uint32 private constant EPOCH_VOTING_CUTOFF = 518400; + uint256 private constant REGISTRATION_FEE = 1e18; + uint256 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; + uint256 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; + uint256 private constant UNREGISTRATION_AFTER_EPOCHS = 4; + uint256 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; + uint256 private constant MIN_CLAIM = 500e18; + uint256 private constant MIN_ACCRUAL = 1000e18; + uint256 private constant EPOCH_DURATION = 7 days; // 7 days + uint256 private constant EPOCH_VOTING_CUTOFF = 518400; Governance private governance; address[] private initialInitiatives; @@ -54,7 +54,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }); @@ -93,7 +93,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // allocate LQTY to the bribeInitiative _allocateLQTY(user1, 10e18, 0); // total LQTY allocated for this epoch should increase - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); assertEq(totalLQTYAllocated, 10e18); } @@ -107,7 +107,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // allocate LQTY to veto bribeInitiative _allocateLQTY(user1, 0, 10e18); // total LQTY allocated for this epoch should not increase - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); assertEq(totalLQTYAllocated, 0); } @@ -122,8 +122,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _allocateLQTY(user1, 5e18, 0); // total LQTY allocated for this epoch should increase - (uint88 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated1, 5e18); assertEq(userLQTYAllocated1, 5e18); @@ -133,8 +133,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _allocateLQTY(user1, 5e18, 0); // total LQTY allocated for this epoch should not change - (uint88 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated2, 5e18); assertEq(userLQTYAllocated1, 5e18); } @@ -147,14 +147,14 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user1 allocates in first epoch _allocateLQTY(user1, 5e18, 0); - (uint88 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated1, 5e18); assertEq(userLQTYAllocated1, 5e18); _allocateLQTY(user1, 5e18, 0); - (uint88 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated2, 5e18); assertEq(userLQTYAllocated2, 5e18); } @@ -166,14 +166,14 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user1 allocates in first epoch _allocateLQTY(user1, 5e18, 0); - (uint88 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated1, 5e18); assertEq(userLQTYAllocated1, 5e18); console2.log("current governance epoch: ", governance.epoch()); // user's linked-list should be updated to have a value for the current epoch - (uint88 allocatedAtEpoch,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 allocatedAtEpoch,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); console2.log("allocatedAtEpoch: ", allocatedAtEpoch); } @@ -186,8 +186,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user1 allocates in first epoch _allocateLQTY(user1, 10e18, 0); - (uint88 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated1, 10e18); assertEq(userLQTYAllocated1, 10e18); @@ -196,8 +196,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user allocations should be disjoint because they're in separate epochs _allocateLQTY(user2, 10e18, 0); - (uint88 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); + (uint256 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); assertEq(totalLQTYAllocated2, 20e18); assertEq(userLQTYAllocated2, 10e18); } @@ -211,14 +211,14 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user1 allocates in first epoch _allocateLQTY(user1, 10e18, 0); - (uint88 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated1,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated1, 10e18); assertEq(userLQTYAllocated1, 10e18); _allocateLQTY(user2, 10e18, 0); - (uint88 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); + (uint256 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated2,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); assertEq(totalLQTYAllocated2, 20e18); assertEq(userLQTYAllocated2, 10e18); } @@ -232,13 +232,13 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user1 allocates in first epoch _allocateLQTY(user1, 10e18, 0); - (uint88 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 totalLQTYAllocated1,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); assertEq(totalLQTYAllocated1, 10e18); // warp to the end of the epoch vm.warp(block.timestamp + (EPOCH_VOTING_CUTOFF - 1)); - (uint88 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 totalLQTYAllocated2,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); assertEq(totalLQTYAllocated2, 10e18); } @@ -255,22 +255,22 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { function test_claimBribes() public { // =========== epoch 1 ================== // user stakes in epoch 1 - _stakeLQTY(user1, 1e6 ether); + _stakeLQTY(user1, 1e18); // =========== epoch 2 ================== vm.warp(block.timestamp + EPOCH_DURATION); assertEq(2, governance.epoch(), "not in epoch 2"); // lusdHolder deposits lqty and lusd bribes claimable in epoch 3 - _depositBribe(1e6 ether, 1e6 ether, governance.epoch() + 1); - uint16 depositedBribe = governance.epoch() + 1; + _depositBribe(1e18, 1e18, governance.epoch() + 1); + uint256 depositedBribe = governance.epoch() + 1; // =========== epoch 3 ================== vm.warp(block.timestamp + EPOCH_DURATION); assertEq(3, governance.epoch(), "not in epoch 3"); // user votes on bribeInitiative - _allocateLQTY(user1, 1e6 ether, 0); + _allocateLQTY(user1, 1e18, 0); // =========== epoch 5 ================== vm.warp(block.timestamp + (EPOCH_DURATION * 2)); @@ -279,8 +279,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user should receive bribe from their allocated stake (uint256 boldAmount, uint256 bribeTokenAmount) = _claimBribe(user1, depositedBribe, depositedBribe, depositedBribe); - assertEq(boldAmount, 1e6 ether); - assertEq(bribeTokenAmount, 1e6 ether); + assertEq(boldAmount, 1e18); + assertEq(bribeTokenAmount, 1e18); } // user that votes in an epoch that has bribes allocated to it will receive bribes on claiming @@ -345,7 +345,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { assertEq(5, governance.epoch(), "not in epoch 5"); // check amount of bribes in epoch 3 - (uint128 boldAmountFromStorage, uint128 bribeTokenAmountFromStorage) = + (uint256 boldAmountFromStorage, uint256 bribeTokenAmountFromStorage) = IBribeInitiative(bribeInitiative).bribeByEpoch(governance.epoch() - 2); assertEq(boldAmountFromStorage, 1e18, "boldAmountFromStorage != 1e18"); assertEq(bribeTokenAmountFromStorage, 1e18, "bribeTokenAmountFromStorage != 1e18"); @@ -359,8 +359,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user should receive bribe from their allocated stake for each epoch // user claims for epoch 3 - uint16 claimEpoch = governance.epoch() - 2; // claim for epoch 3 - uint16 prevAllocationEpoch = governance.epoch() - 2; // epoch 3 + uint256 claimEpoch = governance.epoch() - 2; // claim for epoch 3 + uint256 prevAllocationEpoch = governance.epoch() - 2; // epoch 3 (uint256 boldAmount, uint256 bribeTokenAmount) = _claimBribe(user1, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); assertEq(boldAmount, 1e18); @@ -401,20 +401,20 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { assertEq(4, governance.epoch(), "not in epoch 4"); // user claims for epoch 3 - uint16 claimEpoch = governance.epoch() - 1; // claim for epoch 3 - uint16 prevAllocationEpoch = governance.epoch() - 1; // epoch 3 + uint256 claimEpoch = governance.epoch() - 1; // claim for epoch 3 + uint256 prevAllocationEpoch = governance.epoch() - 1; // epoch 3 (uint256 boldAmount, uint256 bribeTokenAmount) = _claimBribe(user1, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); // calculate user share of total allocation for initiative for the given epoch as percentage - (uint88 userLqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, 3); - (uint88 totalLqtyAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(3); + (uint256 userLqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, 3); + (uint256 totalLqtyAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(3); uint256 userShareOfTotalAllocated = uint256((userLqtyAllocated * 10_000) / totalLqtyAllocated); console2.log("userLqtyAllocated: ", userLqtyAllocated); console2.log("totalLqtyAllocated: ", totalLqtyAllocated); // calculate user received bribes as share of total bribes as percentage - (uint128 boldAmountForEpoch, uint128 bribeTokenAmountForEpoch) = bribeInitiative.bribeByEpoch(3); + (uint256 boldAmountForEpoch, uint256 bribeTokenAmountForEpoch) = bribeInitiative.bribeByEpoch(3); uint256 userShareOfTotalBoldForEpoch = (boldAmount * 10_000) / uint256(boldAmountForEpoch); uint256 userShareOfTotalBribeForEpoch = (bribeTokenAmount * 10_000) / uint256(bribeTokenAmountForEpoch); @@ -431,13 +431,15 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { ); } - function test_claimedBribes_fraction_fuzz(uint88 user1StakeAmount, uint88 user2StakeAmount, uint88 user3StakeAmount) - public - { + function test_claimedBribes_fraction_fuzz( + uint256 user1StakeAmount, + uint256 user2StakeAmount, + uint256 user3StakeAmount + ) public { // =========== epoch 1 ================== - user1StakeAmount = uint88(bound(uint256(user1StakeAmount), 1, lqty.balanceOf(user1))); - user2StakeAmount = uint88(bound(uint256(user2StakeAmount), 1, lqty.balanceOf(user2))); - user3StakeAmount = uint88(bound(uint256(user3StakeAmount), 1, lqty.balanceOf(user3))); + user1StakeAmount = uint256(bound(uint256(user1StakeAmount), 1, lqty.balanceOf(user1))); + user2StakeAmount = uint256(bound(uint256(user2StakeAmount), 1, lqty.balanceOf(user2))); + user3StakeAmount = uint256(bound(uint256(user3StakeAmount), 1, lqty.balanceOf(user3))); // all users stake in epoch 1 _stakeLQTY(user1, user1StakeAmount); @@ -456,17 +458,17 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { assertEq(3, governance.epoch(), "not in epoch 3"); // users all vote on bribeInitiative - _allocateLQTY(user1, int88(user1StakeAmount), 0); - _allocateLQTY(user2, int88(user2StakeAmount), 0); - _allocateLQTY(user3, int88(user3StakeAmount), 0); + _allocateLQTY(user1, int256(user1StakeAmount), 0); + _allocateLQTY(user2, int256(user2StakeAmount), 0); + _allocateLQTY(user3, int256(user3StakeAmount), 0); // =========== epoch 4 ================== vm.warp(block.timestamp + EPOCH_DURATION); assertEq(4, governance.epoch(), "not in epoch 4"); // all users claim bribes for epoch 3 - uint16 claimEpoch = governance.epoch() - 1; // claim for epoch 3 - uint16 prevAllocationEpoch = governance.epoch() - 1; // epoch 3 + uint256 claimEpoch = governance.epoch() - 1; // claim for epoch 3 + uint256 prevAllocationEpoch = governance.epoch() - 1; // epoch 3 (uint256 boldAmount1, uint256 bribeTokenAmount1) = _claimBribe(user1, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); (uint256 boldAmount2, uint256 bribeTokenAmount2) = @@ -551,8 +553,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { assertEq(4, governance.epoch(), "not in epoch 4"); // user claims for epoch 3 - uint16 claimEpoch = governance.epoch() - 1; // claim for epoch 3 - uint16 prevAllocationEpoch = governance.epoch() - 1; // epoch 3 + uint256 claimEpoch = governance.epoch() - 1; // claim for epoch 3 + uint256 prevAllocationEpoch = governance.epoch() - 1; // epoch 3 (uint256 boldAmount, uint256 bribeTokenAmount) = _claimBribe(user1, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); assertEq(boldAmount, 1e18, "voter doesn't receive full bold bribe amount"); @@ -595,8 +597,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { console2.log("current epoch: ", governance.epoch()); // user should receive bribe from their allocated stake in epoch 2 - uint16 claimEpoch = governance.epoch() - 2; // claim for epoch 3 - uint16 prevAllocationEpoch = governance.epoch() - 2; // epoch 3 + uint256 claimEpoch = governance.epoch() - 2; // claim for epoch 3 + uint256 prevAllocationEpoch = governance.epoch() - 2; // epoch 3 (uint256 boldAmount, uint256 bribeTokenAmount) = _claimBribe(user1, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); assertEq(boldAmount, 1e18); @@ -631,7 +633,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // user votes on bribeInitiative _allocateLQTY(user1, 1e18, 0); - (uint88 lqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 lqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(lqtyAllocated, 1e18, "lqty doesn't immediately get allocated"); } @@ -659,8 +661,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // deposit bribe for Epoch + 2 _depositBribe(1e18, 1e18, governance.epoch() + 1); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 5e17, "total allocation"); assertEq(userLQTYAllocated, 5e17, "user allocation"); @@ -695,7 +697,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { lusd.approve(address(bribeInitiative), 1e18); vm.expectRevert("BribeInitiative: now-or-future-epochs"); - bribeInitiative.depositBribe(1e18, 1e18, uint16(0)); + bribeInitiative.depositBribe(1e18, 1e18, uint256(0)); vm.stopPrank(); } @@ -711,8 +713,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _allocateLQTY(user1, 1e18, 0); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 1e18); assertEq(userLQTYAllocated, 1e18); @@ -742,8 +744,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _allocateLQTY(user1, 1e18, 0); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 1e18); assertEq(userLQTYAllocated, 1e18); @@ -773,8 +775,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _allocateLQTY(user1, 1e18, 0); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 1e18); assertEq(userLQTYAllocated, 1e18); @@ -805,8 +807,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _allocateLQTY(user1, 1e18, 0); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 1e18); assertEq(userLQTYAllocated, 1e18); @@ -834,8 +836,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _tryAllocateNothing(user1); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 0); assertEq(userLQTYAllocated, 0); @@ -868,8 +870,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { _tryAllocateNothing(user1); - (uint88 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - (uint88 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); + (uint256 totalLQTYAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); + (uint256 userLQTYAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user1, governance.epoch()); assertEq(totalLQTYAllocated, 0); assertEq(userLQTYAllocated, 0); @@ -893,7 +895,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { /** * Helpers */ - function _stakeLQTY(address staker, uint88 amount) internal { + function _stakeLQTY(address staker, uint256 amount) internal { vm.startPrank(staker); address userProxy = governance.deriveUserProxyAddress(staker); lqty.approve(address(userProxy), amount); @@ -901,10 +903,10 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { vm.stopPrank(); } - function _allocateLQTY(address staker, int88 absoluteVoteLQTYAmt, int88 absoluteVetoLQTYAmt) internal { + function _allocateLQTY(address staker, int256 absoluteVoteLQTYAmt, int256 absoluteVetoLQTYAmt) internal { vm.startPrank(staker); address[] memory initiativesToReset; - (uint88 currentVote, uint88 currentVeto,) = + (uint256 currentVote,, uint256 currentVeto,,) = governance.lqtyAllocatedByUserToInitiative(staker, address(bribeInitiative)); if (currentVote != 0 || currentVeto != 0) { initiativesToReset = new address[](1); @@ -914,24 +916,24 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { address[] memory initiatives = new address[](1); initiatives[0] = address(bribeInitiative); - int88[] memory absoluteVoteLQTY = new int88[](1); + int256[] memory absoluteVoteLQTY = new int256[](1); absoluteVoteLQTY[0] = absoluteVoteLQTYAmt; - int88[] memory absoluteVetoLQTY = new int88[](1); + int256[] memory absoluteVetoLQTY = new int256[](1); absoluteVetoLQTY[0] = absoluteVetoLQTYAmt; governance.allocateLQTY(initiativesToReset, initiatives, absoluteVoteLQTY, absoluteVetoLQTY); vm.stopPrank(); } - function _allocate(address staker, address initiative, int88 votes, int88 vetos) internal { + function _allocate(address staker, address initiative, int256 votes, int256 vetos) internal { vm.startPrank(staker); address[] memory initiatives = new address[](1); initiatives[0] = initiative; - int88[] memory absoluteLQTYVotes = new int88[](1); + int256[] memory absoluteLQTYVotes = new int256[](1); absoluteLQTYVotes[0] = votes; - int88[] memory absoluteLQTYVetos = new int88[](1); + int256[] memory absoluteLQTYVetos = new int256[](1); absoluteLQTYVetos[0] = vetos; governance.allocateLQTY(initiatives, initiatives, absoluteLQTYVotes, absoluteLQTYVetos); @@ -946,8 +948,8 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { address[] memory initiatives = new address[](1); initiatives[0] = address(bribeInitiative); - int88[] memory absoluteVoteLQTY = new int88[](1); - int88[] memory absoluteVetoLQTY = new int88[](1); + int256[] memory absoluteVoteLQTY = new int256[](1); + int256[] memory absoluteVetoLQTY = new int256[](1); vm.expectRevert("Governance: voting nothing"); governance.allocateLQTY(initiativesToReset, initiatives, absoluteVoteLQTY, absoluteVetoLQTY); @@ -963,7 +965,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { vm.stopPrank(); } - function _depositBribe(uint128 boldAmount, uint128 bribeAmount, uint16 epoch) public { + function _depositBribe(uint128 boldAmount, uint256 bribeAmount, uint256 epoch) public { vm.startPrank(lusdHolder); lqty.approve(address(bribeInitiative), boldAmount); lusd.approve(address(bribeInitiative), bribeAmount); @@ -971,7 +973,7 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { vm.stopPrank(); } - function _depositBribe(address _initiative, uint128 boldAmount, uint128 bribeAmount, uint16 epoch) public { + function _depositBribe(address _initiative, uint256 boldAmount, uint256 bribeAmount, uint256 epoch) public { vm.startPrank(lusdHolder); lqty.approve(_initiative, boldAmount); lusd.approve(_initiative, bribeAmount); @@ -981,18 +983,18 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { function _claimBribe( address claimer, - uint16 epoch, - uint16 prevLQTYAllocationEpoch, - uint16 prevTotalLQTYAllocationEpoch + uint256 epoch, + uint256 prevLQTYAllocationEpoch, + uint256 prevTotalLQTYAllocationEpoch ) public returns (uint256 boldAmount, uint256 bribeTokenAmount) { return _claimBribe(claimer, epoch, prevLQTYAllocationEpoch, prevTotalLQTYAllocationEpoch, false); } function _claimBribe( address claimer, - uint16 epoch, - uint16 prevLQTYAllocationEpoch, - uint16 prevTotalLQTYAllocationEpoch, + uint256 epoch, + uint256 prevLQTYAllocationEpoch, + uint256 prevTotalLQTYAllocationEpoch, bool expectRevert ) public returns (uint256 boldAmount, uint256 bribeTokenAmount) { vm.startPrank(claimer); @@ -1007,20 +1009,20 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { vm.stopPrank(); } - function _getUserShareOfAllocationAsPercentage(address user, uint16 epoch) + function _getUserShareOfAllocationAsPercentage(address user, uint256 epoch) internal returns (uint256 userShareOfTotalAllocated) { - (uint88 userLqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user, epoch); - (uint88 totalLqtyAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(epoch); + (uint256 userLqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user, epoch); + (uint256 totalLqtyAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(epoch); userShareOfTotalAllocated = (uint256(userLqtyAllocated) * 10_000) / uint256(totalLqtyAllocated); } - function _getBribesAsPercentageOfTotal(uint16 epoch, uint256 userBoldAmount, uint256 userBribeTokenAmount) + function _getBribesAsPercentageOfTotal(uint256 epoch, uint256 userBoldAmount, uint256 userBribeTokenAmount) internal returns (uint256 userShareOfTotalBoldForEpoch, uint256 userShareOfTotalBribeForEpoch) { - (uint128 boldAmountForEpoch, uint128 bribeTokenAmountForEpoch) = bribeInitiative.bribeByEpoch(epoch); + (uint256 boldAmountForEpoch, uint256 bribeTokenAmountForEpoch) = bribeInitiative.bribeByEpoch(epoch); uint256 userShareOfTotalBoldForEpoch = (userBoldAmount * 10_000) / uint256(boldAmountForEpoch); uint256 userShareOfTotalBribeForEpoch = (userBribeTokenAmount * 10_000) / uint256(bribeTokenAmountForEpoch); return (userShareOfTotalBoldForEpoch, userShareOfTotalBribeForEpoch); diff --git a/test/BribeInitiativeAllocate.t.sol b/test/BribeInitiativeAllocate.t.sol index 566a4171..0e9deaee 100644 --- a/test/BribeInitiativeAllocate.t.sol +++ b/test/BribeInitiativeAllocate.t.sol @@ -1,956 +1,956 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; - -import {Test} from "forge-std/Test.sol"; -import {console} from "forge-std/console.sol"; - -import {BribeInitiative} from "../src/BribeInitiative.sol"; - -import {IGovernance} from "../src/interfaces/IGovernance.sol"; - -import {MockERC20Tester} from "./mocks/MockERC20Tester.sol"; -import {MockGovernance} from "./mocks/MockGovernance.sol"; - -// new epoch: -// no veto to no veto: insert new user allocation, add and sub from total allocation -// (prevVoteLQTY == 0 || prevVoteLQTY != 0) && _vetoLQTY == 0 - -// no veto to veto: insert new 0 user allocation, sub from total allocation -// (prevVoteLQTY == 0 || prevVoteLQTY != 0) && _vetoLQTY != 0 - -// veto to no veto: insert new user allocation, add to total allocation -// prevVoteLQTY == 0 && _vetoLQTY == 0 - -// veto to veto: insert new 0 user allocation, do nothing to total allocation -// prevVoteLQTY == 0 && _vetoLQTY != 0 - -// same epoch: -// no veto to no veto: update user allocation, add and sub from total allocation -// no veto to veto: set 0 user allocation, sub from total allocation -// veto to no veto: update user allocation, add to total allocation -// veto to veto: set 0 user allocation, do nothing to total allocation - -contract BribeInitiativeAllocateTest is Test { - MockERC20Tester private lqty; - MockERC20Tester private lusd; - address private constant user = address(0xF977814e90dA44bFA03b6295A0616a897441aceC); - address private constant user2 = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - address private constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - - MockGovernance private governance; - BribeInitiative private bribeInitiative; - - function setUp() public { - lqty = new MockERC20Tester("Liquity", "LQTY"); - lusd = new MockERC20Tester("Liquity USD", "LUSD"); - - lqty.mint(lusdHolder, 10000e18); - lusd.mint(lusdHolder, 10000e18); - - governance = new MockGovernance(); - - bribeInitiative = new BribeInitiative(address(governance), address(lusd), address(lqty)); - } - - function test_onAfterAllocateLQTY_newEpoch_NoVetoToNoVeto() public { - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - governance.setEpoch(1); - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: 1}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - } - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - - { - IGovernance.UserState memory userState2 = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation2 = - IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: 1}); - IGovernance.InitiativeState memory initiativeState2 = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState2, allocation2, initiativeState2); - } - - (uint88 totalLQTYAllocated2, uint120 totalAverageTimestamp2) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated2, 1001e18); - assertEq(totalAverageTimestamp2, block.timestamp); - (uint88 userLQTYAllocated2, uint120 userAverageTimestamp2) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated2, 1000e18); - assertEq(userAverageTimestamp2, block.timestamp); - - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - governance.setEpoch(2); - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint32(1)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: 2}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 2001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(1), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - } - - (totalLQTYAllocated, totalAverageTimestamp) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 2001e18); - assertEq(totalAverageTimestamp, 1); - (userLQTYAllocated, userAverageTimestamp) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 2000e18); - assertEq(userAverageTimestamp, 1); - - governance.setEpoch(3); - - vm.startPrank(address(user)); - - BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); - claimData[0].epoch = 2; - claimData[0].prevLQTYAllocationEpoch = 2; - claimData[0].prevTotalLQTYAllocationEpoch = 2; - (uint256 boldAmount, uint256 bribeTokenAmount) = bribeInitiative.claimBribes(claimData); - assertGt(boldAmount, 999e18); - assertGt(bribeTokenAmount, 999e18); - } - - function test_onAfterAllocateLQTY_newEpoch_NoVetoToVeto() public { - governance.setEpoch(1); - vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch - - vm.startPrank(address(governance)); - - // set user2 allocations like governance would using onAfterAllocateLQTY at epoch 1 - // sets avgTimestamp to current block.timestamp - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: 1}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - // set user2 allocations like governance would using onAfterAllocateLQTY at epoch 1 - // sets avgTimestamp to current block.timestamp - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: 1}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - // lusdHolder deposits bribes into the initiative - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - - governance.setEpoch(2); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts - - vm.startPrank(address(governance)); - - // set allocation in initiative for user in epoch 1 - // sets avgTimestamp to current block.timestamp - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: 1}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 0, - vetoLQTY: 1, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 0); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - // set allocation in initiative for user2 in epoch 1 - // sets avgTimestamp to current block.timestamp - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: 1}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 0, - vetoLQTY: 1, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 0); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - governance.setEpoch(3); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to third epoch ts - - vm.startPrank(address(user)); - - BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); - claimData[0].epoch = 2; - claimData[0].prevLQTYAllocationEpoch = 2; - claimData[0].prevTotalLQTYAllocationEpoch = 2; - vm.expectRevert("BribeInitiative: total-lqty-allocation-zero"); - (uint256 boldAmount, uint256 bribeTokenAmount) = bribeInitiative.claimBribes(claimData); - assertEq(boldAmount, 0, "boldAmount nonzero"); - assertEq(bribeTokenAmount, 0, "bribeTokenAmount nonzero"); - } - - function test_onAfterAllocateLQTY_newEpoch_VetoToNoVeto() public { - governance.setEpoch(1); - vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch - - vm.startPrank(address(governance)); - - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - - IGovernance.UserState memory userStateVeto = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocationVeto = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1000e18, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeStateVeto = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 1000e18, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: uint32(block.timestamp), - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY( - governance.epoch(), user, userStateVeto, allocationVeto, initiativeStateVeto - ); - - (uint88 totalLQTYAllocatedAfterVeto, uint120 totalAverageTimestampAfterVeto) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocatedAfterVeto, 1e18); - assertEq(totalAverageTimestampAfterVeto, uint120(block.timestamp)); - (uint88 userLQTYAllocatedAfterVeto, uint120 userAverageTimestampAfterVeto) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocatedAfterVeto, 0); - assertEq(userAverageTimestampAfterVeto, uint120(block.timestamp)); - - governance.setEpoch(2); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts - - IGovernance.UserState memory userStateNewEpoch = - IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocationNewEpoch = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeStateNewEpoch = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 1, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: uint32(block.timestamp), - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY( - governance.epoch(), user, userStateNewEpoch, allocationNewEpoch, initiativeStateNewEpoch - ); - - (uint88 totalLQTYAllocatedNewEpoch, uint120 totalAverageTimestampNewEpoch) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocatedNewEpoch, 1e18); - assertEq(totalAverageTimestampNewEpoch, uint120(block.timestamp)); - (uint88 userLQTYAllocatedNewEpoch, uint120 userAverageTimestampNewEpoch) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocatedNewEpoch, 0); - assertEq(userAverageTimestampNewEpoch, uint120(block.timestamp)); - - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - - vm.startPrank(address(governance)); - - governance.setEpoch(3); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to third epoch ts - - IGovernance.UserState memory userStateNewEpoch3 = - IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocationNewEpoch3 = - IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeStateNewEpoch3 = IGovernance.InitiativeState({ - voteLQTY: 2001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY( - governance.epoch(), user, userStateNewEpoch3, allocationNewEpoch3, initiativeStateNewEpoch3 - ); - - (uint88 totalLQTYAllocatedNewEpoch3, uint120 totalAverageTimestampNewEpoch3) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocatedNewEpoch3, 2001e18); - assertEq(totalAverageTimestampNewEpoch3, uint120(block.timestamp)); - (uint88 userLQTYAllocatedNewEpoch3, uint120 userAverageTimestampNewEpoch3) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocatedNewEpoch3, 2000e18); - assertEq(userAverageTimestampNewEpoch3, uint120(block.timestamp)); - - governance.setEpoch(4); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to fourth epoch ts - - vm.startPrank(address(user)); - - BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); - claimData[0].epoch = 3; - claimData[0].prevLQTYAllocationEpoch = 3; - claimData[0].prevTotalLQTYAllocationEpoch = 3; - bribeInitiative.claimBribes(claimData); - } - - function test_onAfterAllocateLQTY_newEpoch_VetoToVeto() public { - governance.setEpoch(1); - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 1000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - governance.setEpoch(2); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - governance.setEpoch(3); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - } - - function test_onAfterAllocateLQTY_sameEpoch_NoVetoToNoVeto() public { - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - - governance.setEpoch(1); - vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 1000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 2001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 2001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 2000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - governance.setEpoch(2); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts - - vm.startPrank(address(user)); - - BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); - claimData[0].epoch = 1; - claimData[0].prevLQTYAllocationEpoch = 1; - claimData[0].prevTotalLQTYAllocationEpoch = 1; - bribeInitiative.claimBribes(claimData); - } - - function test_onAfterAllocateLQTY_sameEpoch_NoVetoToVeto() public { - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - - governance.setEpoch(1); - vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 1000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - governance.setEpoch(2); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts - - vm.startPrank(address(user)); - - BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); - claimData[0].epoch = 1; - claimData[0].prevLQTYAllocationEpoch = 1; - claimData[0].prevTotalLQTYAllocationEpoch = 1; - vm.expectRevert("BribeInitiative: lqty-allocation-zero"); - (uint256 boldAmount, uint256 bribeTokenAmount) = bribeInitiative.claimBribes(claimData); - assertEq(boldAmount, 0); - assertEq(bribeTokenAmount, 0); - } - - function test_onAfterAllocateLQTY_sameEpoch_VetoToNoVeto() public { - vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), 1000e18); - lusd.approve(address(bribeInitiative), 1000e18); - bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); - vm.stopPrank(); - - governance.setEpoch(1); - vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 1000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 2001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 2001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 2000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - governance.setEpoch(2); - vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts - - vm.startPrank(address(user)); - - BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); - claimData[0].epoch = 1; - claimData[0].prevLQTYAllocationEpoch = 1; - claimData[0].prevTotalLQTYAllocationEpoch = 1; - bribeInitiative.claimBribes(claimData); - } - - function test_onAfterAllocateLQTY_sameEpoch_VetoToVeto() public { - governance.setEpoch(1); - - vm.startPrank(address(governance)); - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); - assertEq(userLQTYAllocated, 1e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint32(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1001e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint32(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1001e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 1000e18); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint120(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint120(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint120(block.timestamp)); - } - - { - IGovernance.UserState memory userState = - IGovernance.UserState({allocatedLQTY: 2, averageStakingTimestamp: uint120(block.timestamp)}); - IGovernance.Allocation memory allocation = - IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 2, atEpoch: uint16(governance.epoch())}); - IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ - voteLQTY: 1e18, - vetoLQTY: 0, - averageStakingTimestampVoteLQTY: uint120(block.timestamp), - averageStakingTimestampVetoLQTY: 0, - lastEpochClaim: 0 - }); - bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); - - (uint88 totalLQTYAllocated, uint120 totalAverageTimestamp) = - bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); - assertEq(totalLQTYAllocated, 1e18); - assertEq(totalAverageTimestamp, uint120(block.timestamp)); - (uint88 userLQTYAllocated, uint120 userAverageTimestamp) = - bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); - assertEq(userLQTYAllocated, 0); - assertEq(userAverageTimestamp, uint32(block.timestamp)); - } - } - - // function test_onAfterAllocateLQTY() public { - // governance.setEpoch(1); - - // vm.startPrank(address(governance)); - - // // first total deposit, first user deposit - // bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, 1000e18, 0); - // assertEq(bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()), 1000e18); - // assertEq(bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()), 1000e18); - - // // second total deposit, second user deposit - // bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, 1000e18, 0); - // assertEq(bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()), 1000e18); // should stay the same - // assertEq(bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()), 1000e18); // should stay the same - - // // third total deposit, first user deposit - // bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, 1000e18, 0); - // assertEq(bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()), 2000e18); - // assertEq(bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()), 1000e18); - - // vm.stopPrank(); - // } -} +// // SPDX-License-Identifier: UNLICENSED +// pragma solidity ^0.8.24; + +// import {Test} from "forge-std/Test.sol"; +// import {console} from "forge-std/console.sol"; + +// import {BribeInitiative} from "../src/BribeInitiative.sol"; + +// import {IGovernance} from "../src/interfaces/IGovernance.sol"; + +// import {MockERC20Tester} from "./mocks/MockERC20Tester.sol"; +// import {MockGovernance} from "./mocks/MockGovernance.sol"; + +// // new epoch: +// // no veto to no veto: insert new user allocation, add and sub from total allocation +// // (prevVoteLQTY == 0 || prevVoteLQTY != 0) && _vetoLQTY == 0 + +// // no veto to veto: insert new 0 user allocation, sub from total allocation +// // (prevVoteLQTY == 0 || prevVoteLQTY != 0) && _vetoLQTY != 0 + +// // veto to no veto: insert new user allocation, add to total allocation +// // prevVoteLQTY == 0 && _vetoLQTY == 0 + +// // veto to veto: insert new 0 user allocation, do nothing to total allocation +// // prevVoteLQTY == 0 && _vetoLQTY != 0 + +// // same epoch: +// // no veto to no veto: update user allocation, add and sub from total allocation +// // no veto to veto: set 0 user allocation, sub from total allocation +// // veto to no veto: update user allocation, add to total allocation +// // veto to veto: set 0 user allocation, do nothing to total allocation + +// contract BribeInitiativeAllocateTest is Test { +// MockERC20Tester private lqty; +// MockERC20Tester private lusd; +// address private constant user = address(0xF977814e90dA44bFA03b6295A0616a897441aceC); +// address private constant user2 = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); +// address private constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); + +// MockGovernance private governance; +// BribeInitiative private bribeInitiative; + +// function setUp() public { +// lqty = new MockERC20Tester("Liquity", "LQTY"); +// lusd = new MockERC20Tester("Liquity USD", "LUSD"); + +// lqty.mint(lusdHolder, 10000e18); +// lusd.mint(lusdHolder, 10000e18); + +// governance = new MockGovernance(); + +// bribeInitiative = new BribeInitiative(address(governance), address(lusd), address(lqty)); +// } + +// function test_onAfterAllocateLQTY_newEpoch_NoVetoToNoVeto() public { +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); +// governance.setEpoch(1); + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: 1}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); +// } +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); + +// { +// IGovernance.UserState memory userState2 = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation2 = +// IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: 1}); +// IGovernance.InitiativeState memory initiativeState2 = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState2, allocation2, initiativeState2); +// } + +// (uint256 totalLQTYAllocated2, uint256 totalAverageTimestamp2) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated2, 1001e18); +// assertEq(totalAverageTimestamp2, block.timestamp); +// (uint256 userLQTYAllocated2, uint256 userAverageTimestamp2) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated2, 1000e18); +// assertEq(userAverageTimestamp2, block.timestamp); + +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); +// governance.setEpoch(2); + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint256(1)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: 2}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 2001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(1), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); +// } + +// (totalLQTYAllocated, totalAverageTimestamp) = bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 2001e18); +// assertEq(totalAverageTimestamp, 1); +// (userLQTYAllocated, userAverageTimestamp) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 2000e18); +// assertEq(userAverageTimestamp, 1); + +// governance.setEpoch(3); + +// vm.startPrank(address(user)); + +// BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); +// claimData[0].epoch = 2; +// claimData[0].prevLQTYAllocationEpoch = 2; +// claimData[0].prevTotalLQTYAllocationEpoch = 2; +// (uint256 boldAmount, uint256 bribeTokenAmount) = bribeInitiative.claimBribes(claimData); +// assertGt(boldAmount, 999e18); +// assertGt(bribeTokenAmount, 999e18); +// } + +// function test_onAfterAllocateLQTY_newEpoch_NoVetoToVeto() public { +// governance.setEpoch(1); +// vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch + +// vm.startPrank(address(governance)); + +// // set user2 allocations like governance would using onAfterAllocateLQTY at epoch 1 +// // sets avgTimestamp to current block.timestamp +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: 1}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// // set user2 allocations like governance would using onAfterAllocateLQTY at epoch 1 +// // sets avgTimestamp to current block.timestamp +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: 1}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// // lusdHolder deposits bribes into the initiative +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); + +// governance.setEpoch(2); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts + +// vm.startPrank(address(governance)); + +// // set allocation in initiative for user in epoch 1 +// // sets avgTimestamp to current block.timestamp +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: 1}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 0, +// vetoLQTY: 1, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 0); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// // set allocation in initiative for user2 in epoch 1 +// // sets avgTimestamp to current block.timestamp +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: 1}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 0, +// vetoLQTY: 1, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 0); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// governance.setEpoch(3); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to third epoch ts + +// vm.startPrank(address(user)); + +// BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); +// claimData[0].epoch = 2; +// claimData[0].prevLQTYAllocationEpoch = 2; +// claimData[0].prevTotalLQTYAllocationEpoch = 2; +// vm.expectRevert("BribeInitiative: total-lqty-allocation-zero"); +// (uint256 boldAmount, uint256 bribeTokenAmount) = bribeInitiative.claimBribes(claimData); +// assertEq(boldAmount, 0, "boldAmount nonzero"); +// assertEq(bribeTokenAmount, 0, "bribeTokenAmount nonzero"); +// } + +// function test_onAfterAllocateLQTY_newEpoch_VetoToNoVeto() public { +// governance.setEpoch(1); +// vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch + +// vm.startPrank(address(governance)); + +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); + +// IGovernance.UserState memory userStateVeto = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocationVeto = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1000e18, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeStateVeto = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 1000e18, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: uint256(block.timestamp), +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY( +// governance.epoch(), user, userStateVeto, allocationVeto, initiativeStateVeto +// ); + +// (uint256 totalLQTYAllocatedAfterVeto, uint256 totalAverageTimestampAfterVeto) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocatedAfterVeto, 1e18); +// assertEq(totalAverageTimestampAfterVeto, uint256(block.timestamp)); +// (uint256 userLQTYAllocatedAfterVeto, uint256 userAverageTimestampAfterVeto) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocatedAfterVeto, 0); +// assertEq(userAverageTimestampAfterVeto, uint256(block.timestamp)); + +// governance.setEpoch(2); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts + +// IGovernance.UserState memory userStateNewEpoch = +// IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocationNewEpoch = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeStateNewEpoch = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 1, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: uint256(block.timestamp), +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY( +// governance.epoch(), user, userStateNewEpoch, allocationNewEpoch, initiativeStateNewEpoch +// ); + +// (uint256 totalLQTYAllocatedNewEpoch, uint256 totalAverageTimestampNewEpoch) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocatedNewEpoch, 1e18); +// assertEq(totalAverageTimestampNewEpoch, uint256(block.timestamp)); +// (uint256 userLQTYAllocatedNewEpoch, uint256 userAverageTimestampNewEpoch) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocatedNewEpoch, 0); +// assertEq(userAverageTimestampNewEpoch, uint256(block.timestamp)); + +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); + +// vm.startPrank(address(governance)); + +// governance.setEpoch(3); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to third epoch ts + +// IGovernance.UserState memory userStateNewEpoch3 = +// IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocationNewEpoch3 = +// IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeStateNewEpoch3 = IGovernance.InitiativeState({ +// voteLQTY: 2001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY( +// governance.epoch(), user, userStateNewEpoch3, allocationNewEpoch3, initiativeStateNewEpoch3 +// ); + +// (uint256 totalLQTYAllocatedNewEpoch3, uint256 totalAverageTimestampNewEpoch3) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocatedNewEpoch3, 2001e18); +// assertEq(totalAverageTimestampNewEpoch3, uint256(block.timestamp)); +// (uint256 userLQTYAllocatedNewEpoch3, uint256 userAverageTimestampNewEpoch3) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocatedNewEpoch3, 2000e18); +// assertEq(userAverageTimestampNewEpoch3, uint256(block.timestamp)); + +// governance.setEpoch(4); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to fourth epoch ts + +// vm.startPrank(address(user)); + +// BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); +// claimData[0].epoch = 3; +// claimData[0].prevLQTYAllocationEpoch = 3; +// claimData[0].prevTotalLQTYAllocationEpoch = 3; +// bribeInitiative.claimBribes(claimData); +// } + +// function test_onAfterAllocateLQTY_newEpoch_VetoToVeto() public { +// governance.setEpoch(1); + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 1000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// governance.setEpoch(2); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// governance.setEpoch(3); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } +// } + +// function test_onAfterAllocateLQTY_sameEpoch_NoVetoToNoVeto() public { +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); + +// governance.setEpoch(1); +// vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 1000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 2001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 2001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 2000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// governance.setEpoch(2); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts + +// vm.startPrank(address(user)); + +// BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); +// claimData[0].epoch = 1; +// claimData[0].prevLQTYAllocationEpoch = 1; +// claimData[0].prevTotalLQTYAllocationEpoch = 1; +// bribeInitiative.claimBribes(claimData); +// } + +// function test_onAfterAllocateLQTY_sameEpoch_NoVetoToVeto() public { +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); + +// governance.setEpoch(1); +// vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 1000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// governance.setEpoch(2); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts + +// vm.startPrank(address(user)); + +// BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); +// claimData[0].epoch = 1; +// claimData[0].prevLQTYAllocationEpoch = 1; +// claimData[0].prevTotalLQTYAllocationEpoch = 1; +// vm.expectRevert("BribeInitiative: lqty-allocation-zero"); +// (uint256 boldAmount, uint256 bribeTokenAmount) = bribeInitiative.claimBribes(claimData); +// assertEq(boldAmount, 0); +// assertEq(bribeTokenAmount, 0); +// } + +// function test_onAfterAllocateLQTY_sameEpoch_VetoToNoVeto() public { +// vm.startPrank(lusdHolder); +// lqty.approve(address(bribeInitiative), 1000e18); +// lusd.approve(address(bribeInitiative), 1000e18); +// bribeInitiative.depositBribe(1000e18, 1000e18, governance.epoch() + 1); +// vm.stopPrank(); + +// governance.setEpoch(1); +// vm.warp(governance.EPOCH_DURATION()); // warp to end of first epoch + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 1000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 2000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 2000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 2001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 2001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 2000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// governance.setEpoch(2); +// vm.warp(block.timestamp + governance.EPOCH_DURATION()); // warp to second epoch ts + +// vm.startPrank(address(user)); + +// BribeInitiative.ClaimData[] memory claimData = new BribeInitiative.ClaimData[](1); +// claimData[0].epoch = 1; +// claimData[0].prevLQTYAllocationEpoch = 1; +// claimData[0].prevTotalLQTYAllocationEpoch = 1; +// bribeInitiative.claimBribes(claimData); +// } + +// function test_onAfterAllocateLQTY_sameEpoch_VetoToVeto() public { +// governance.setEpoch(1); + +// vm.startPrank(address(governance)); + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()); +// assertEq(userLQTYAllocated, 1e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1000e18, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 1000e18, vetoLQTY: 0, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1001e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1001e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 1000e18); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 1, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 1, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } + +// { +// IGovernance.UserState memory userState = +// IGovernance.UserState({allocatedLQTY: 2, averageStakingTimestamp: uint256(block.timestamp)}); +// IGovernance.Allocation memory allocation = +// IGovernance.Allocation({voteLQTY: 0, vetoLQTY: 2, atEpoch: uint256(governance.epoch())}); +// IGovernance.InitiativeState memory initiativeState = IGovernance.InitiativeState({ +// voteLQTY: 1e18, +// vetoLQTY: 0, +// averageStakingTimestampVoteLQTY: uint256(block.timestamp), +// averageStakingTimestampVetoLQTY: 0, +// lastEpochClaim: 0 +// }); +// bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, userState, allocation, initiativeState); + +// (uint256 totalLQTYAllocated, uint256 totalAverageTimestamp) = +// bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()); +// assertEq(totalLQTYAllocated, 1e18); +// assertEq(totalAverageTimestamp, uint256(block.timestamp)); +// (uint256 userLQTYAllocated, uint256 userAverageTimestamp) = +// bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()); +// assertEq(userLQTYAllocated, 0); +// assertEq(userAverageTimestamp, uint256(block.timestamp)); +// } +// } + +// // function test_onAfterAllocateLQTY() public { +// // governance.setEpoch(1); + +// // vm.startPrank(address(governance)); + +// // // first total deposit, first user deposit +// // bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, 1000e18, 0); +// // assertEq(bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()), 1000e18); +// // assertEq(bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()), 1000e18); + +// // // second total deposit, second user deposit +// // bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user, 1000e18, 0); +// // assertEq(bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()), 1000e18); // should stay the same +// // assertEq(bribeInitiative.lqtyAllocatedByUserAtEpoch(user, governance.epoch()), 1000e18); // should stay the same + +// // // third total deposit, first user deposit +// // bribeInitiative.onAfterAllocateLQTY(governance.epoch(), user2, 1000e18, 0); +// // assertEq(bribeInitiative.totalLQTYAllocatedByEpoch(governance.epoch()), 2000e18); +// // assertEq(bribeInitiative.lqtyAllocatedByUserAtEpoch(user2, governance.epoch()), 1000e18); + +// // vm.stopPrank(); +// // } +// } diff --git a/test/BribeInitiativeFireAndForget.t.sol b/test/BribeInitiativeFireAndForget.t.sol index 7ed7d091..105bc509 100644 --- a/test/BribeInitiativeFireAndForget.t.sol +++ b/test/BribeInitiativeFireAndForget.t.sol @@ -25,8 +25,8 @@ contract BribeInitiativeFireAndForgetTest is MockStakingV1Deployer { uint32 constant EPOCH_DURATION = 7 days; uint32 constant EPOCH_VOTING_CUTOFF = 6 days; - uint16 constant MAX_NUM_EPOCHS = 100; - uint88 constant MAX_VOTE = 1e6 ether; + uint256 constant MAX_NUM_EPOCHS = 100; + uint256 constant MAX_VOTE = 1e6 ether; uint128 constant MAX_BRIBE = 1e6 ether; uint256 constant MAX_CLAIMS_PER_CALL = 10; uint256 constant MEAN_TIME_BETWEEN_VOTES = 2 * EPOCH_DURATION; @@ -50,7 +50,7 @@ contract BribeInitiativeFireAndForgetTest is MockStakingV1Deployer { }); struct Vote { - uint16 epoch; + uint256 epoch; uint256 amount; } @@ -132,10 +132,10 @@ contract BribeInitiativeFireAndForgetTest is MockStakingV1Deployer { /// forge-config: ci.fuzz.runs = 50 function test_AbleToClaimBribesInAnyOrder_EvenFromEpochsWhereVoterStayedInactive(bytes32 seed) external { Random.Context memory random = Random.init(seed); - uint16 startingEpoch = governance.epoch(); - uint16 lastEpoch = startingEpoch; + uint256 startingEpoch = governance.epoch(); + uint256 lastEpoch = startingEpoch; - for (uint16 i = startingEpoch; i < startingEpoch + MAX_NUM_EPOCHS; ++i) { + for (uint256 i = startingEpoch; i < startingEpoch + MAX_NUM_EPOCHS; ++i) { boldAtEpoch[i] = random.generate(MAX_BRIBE); brybAtEpoch[i] = random.generate(MAX_BRIBE); @@ -148,15 +148,15 @@ contract BribeInitiativeFireAndForgetTest is MockStakingV1Deployer { for (;;) { vm.warp(block.timestamp + random.generate(2 * MEAN_TIME_BETWEEN_VOTES)); - uint16 epoch = governance.epoch(); + uint256 epoch = governance.epoch(); - for (uint16 i = lastEpoch; i < epoch; ++i) { + for (uint256 i = lastEpoch; i < epoch; ++i) { voteAtEpoch[i] = latestVote[voter].amount; toteAtEpoch[i] = latestVote[voter].amount + latestVote[other].amount; claimDataAtEpoch[i].epoch = i; claimDataAtEpoch[i].prevLQTYAllocationEpoch = latestVote[voter].epoch; claimDataAtEpoch[i].prevTotalLQTYAllocationEpoch = - uint16(Math.max(latestVote[voter].epoch, latestVote[other].epoch)); + uint256(Math.max(latestVote[voter].epoch, latestVote[other].epoch)); console.log( string.concat( @@ -232,16 +232,16 @@ contract BribeInitiativeFireAndForgetTest is MockStakingV1Deployer { ///////////// function _vote(address who, address initiative, uint256 vote) internal { - assertLeDecimal(vote, uint256(int256(type(int88).max)), 18, "vote > type(uint88).max"); + assertLeDecimal(vote, uint256(int256(type(int256).max)), 18, "vote > type(uint256).max"); vm.startPrank(who); if (vote > 0) { address[] memory initiatives = new address[](1); - int88[] memory votes = new int88[](1); - int88[] memory vetos = new int88[](1); + int256[] memory votes = new int256[](1); + int256[] memory vetos = new int256[](1); initiatives[0] = initiative; - votes[0] = int88(uint88(vote)); + votes[0] = int256(uint256(vote)); governance.allocateLQTY(initiativesToReset[who], initiatives, votes, vetos); if (initiativesToReset[who].length != 0) initiativesToReset[who].pop(); diff --git a/test/CurveV2GaugeRewards.t.sol b/test/CurveV2GaugeRewards.t.sol index 6071afe4..7a1c491b 100644 --- a/test/CurveV2GaugeRewards.t.sol +++ b/test/CurveV2GaugeRewards.t.sol @@ -28,8 +28,8 @@ contract ForkedCurveV2GaugeRewardsTest is Test { uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; + uint256 private constant MIN_CLAIM = 500e18; + uint256 private constant MIN_ACCRUAL = 1000e18; uint32 private constant EPOCH_DURATION = 604800; uint32 private constant EPOCH_VOTING_CUTOFF = 518400; diff --git a/test/Deployment.t.sol b/test/Deployment.t.sol index 692ed2ff..de6a3da7 100644 --- a/test/Deployment.t.sol +++ b/test/Deployment.t.sol @@ -45,8 +45,8 @@ contract DeploymentTest is MockStakingV1Deployer { address[] initiativesToReset; address[] initiatives; - int88[] votes; - int88[] vetos; + int256[] votes; + int256[] vetos; function setUp() external { vm.warp(START_TIME); @@ -125,10 +125,10 @@ contract DeploymentTest is MockStakingV1Deployer { ///////////// function _voteOnInitiative() internal { - uint88 lqtyAmount = 1 ether; + uint256 lqtyAmount = 1 ether; lqty.mint(voter, lqtyAmount); - votes.push(int88(lqtyAmount)); + votes.push(int256(lqtyAmount)); vetos.push(0); vm.startPrank(voter); @@ -155,7 +155,7 @@ contract DeploymentTest is MockStakingV1Deployer { } function _depositLQTY() internal { - uint88 lqtyAmount = 1 ether; + uint256 lqtyAmount = 1 ether; lqty.mint(registrant, lqtyAmount); vm.startPrank(registrant); lqty.approve(governance.deriveUserProxyAddress(registrant), lqtyAmount); diff --git a/test/DoubleLinkedList.t.sol b/test/DoubleLinkedList.t.sol index 4164ff0c..2d84a86c 100644 --- a/test/DoubleLinkedList.t.sol +++ b/test/DoubleLinkedList.t.sol @@ -10,24 +10,24 @@ contract DoubleLinkedListWrapper { DoubleLinkedList.List list; - function getHead() public view returns (uint16) { + function getHead() public view returns (uint256) { return list.getHead(); } - function getTail() public view returns (uint16) { + function getTail() public view returns (uint256) { return list.getTail(); } - function getNext(uint16 id) public view returns (uint16) { + function getNext(uint256 id) public view returns (uint256) { return list.getNext(id); } - function getPrev(uint16 id) public view returns (uint16) { + function getPrev(uint256 id) public view returns (uint256) { return list.getPrev(id); } - function insert(uint16 id, uint16 next) public { - list.insert(id, 1, next); + function insert(uint256 id, uint256 next) public { + list.insert(id, 1, 1, next); } } diff --git a/test/E2E.t.sol b/test/E2E.t.sol index e680092b..eeabd7d7 100644 --- a/test/E2E.t.sol +++ b/test/E2E.t.sol @@ -19,15 +19,15 @@ contract ForkedE2ETests is Test { address private constant user2 = address(0x10C9cff3c4Faa8A60cB8506a7A99411E6A199038); address private constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - uint128 private constant REGISTRATION_FEE = 1e18; - uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; - uint32 private constant EPOCH_DURATION = 604800; - uint32 private constant EPOCH_VOTING_CUTOFF = 518400; + uint256 private constant REGISTRATION_FEE = 1e18; + uint256 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; + uint256 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; + uint256 private constant UNREGISTRATION_AFTER_EPOCHS = 4; + uint256 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; + uint256 private constant MIN_CLAIM = 500e18; + uint256 private constant MIN_ACCRUAL = 1000e18; + uint256 private constant EPOCH_DURATION = 604800; + uint256 private constant EPOCH_VOTING_CUTOFF = 518400; Governance private governance; address[] private initialInitiatives; @@ -47,7 +47,7 @@ contract ForkedE2ETests is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp - EPOCH_DURATION), + epochStart: uint256(block.timestamp - EPOCH_DURATION), /// @audit KEY epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF @@ -318,26 +318,26 @@ contract ForkedE2ETests is Test { assertEq(uint256(IGovernance.InitiativeStatus.CLAIMABLE), _getInitiativeStatus(newInitiative), "UNREGISTERABLE"); } - function _deposit(uint88 amt) internal { + function _deposit(uint256 amt) internal { address userProxy = governance.deployUserProxy(); lqty.approve(address(userProxy), amt); governance.depositLQTY(amt); } - function _allocate(address initiative, int88 votes, int88 vetos) internal { + function _allocate(address initiative, int256 votes, int256 vetos) internal { address[] memory initiativesToReset; address[] memory initiatives = new address[](1); initiatives[0] = initiative; - int88[] memory absoluteLQTYVotes = new int88[](1); + int256[] memory absoluteLQTYVotes = new int256[](1); absoluteLQTYVotes[0] = votes; - int88[] memory absoluteLQTYVetos = new int88[](1); + int256[] memory absoluteLQTYVetos = new int256[](1); absoluteLQTYVetos[0] = vetos; governance.allocateLQTY(initiativesToReset, initiatives, absoluteLQTYVotes, absoluteLQTYVetos); } - function _allocate(address[] memory initiatives, int88[] memory votes, int88[] memory vetos) internal { + function _allocate(address[] memory initiatives, int256[] memory votes, int256[] memory vetos) internal { address[] memory initiativesToReset; governance.allocateLQTY(initiativesToReset, initiatives, votes, vetos); } diff --git a/test/EncodingDecoding.t.sol b/test/EncodingDecoding.t.sol deleted file mode 100644 index 8d741d8e..00000000 --- a/test/EncodingDecoding.t.sol +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; - -import {Test} from "forge-std/Test.sol"; - -import {EncodingDecodingLib} from "src/utils/EncodingDecodingLib.sol"; - -contract EncodingDecodingTest is Test { - // value -> encoding -> decoding -> value - function test_encoding_and_decoding_symmetrical(uint88 lqty, uint120 averageTimestamp) public { - uint224 encodedValue = EncodingDecodingLib.encodeLQTYAllocation(lqty, averageTimestamp); - (uint88 decodedLqty, uint120 decodedAverageTimestamp) = EncodingDecodingLib.decodeLQTYAllocation(encodedValue); - - assertEq(lqty, decodedLqty); - assertEq(averageTimestamp, decodedAverageTimestamp); - - // Redo - uint224 reEncoded = EncodingDecodingLib.encodeLQTYAllocation(decodedLqty, decodedAverageTimestamp); - (uint88 reDecodedLqty, uint120 reDecodedAverageTimestamp) = - EncodingDecodingLib.decodeLQTYAllocation(encodedValue); - - assertEq(reEncoded, encodedValue); - assertEq(reDecodedLqty, decodedLqty); - assertEq(reDecodedAverageTimestamp, decodedAverageTimestamp); - } - - // receive -> undo -> check -> redo -> compare - function test_receive_undo_compare(uint120 encodedValue) public { - _receive_undo_compare(encodedValue); - } - - // receive -> undo -> check -> redo -> compare - function _receive_undo_compare(uint224 encodedValue) public { - /// These values fail because we could pass a value that is bigger than intended - (uint88 decodedLqty, uint120 decodedAverageTimestamp) = EncodingDecodingLib.decodeLQTYAllocation(encodedValue); - - uint224 encodedValue2 = EncodingDecodingLib.encodeLQTYAllocation(decodedLqty, decodedAverageTimestamp); - (uint88 decodedLqty2, uint120 decodedAverageTimestamp2) = - EncodingDecodingLib.decodeLQTYAllocation(encodedValue2); - - assertEq(encodedValue, encodedValue2, "encoded values not equal"); - assertEq(decodedLqty, decodedLqty2, "decoded lqty not equal"); - assertEq(decodedAverageTimestamp, decodedAverageTimestamp2, "decoded timestamps not equal"); - } -} diff --git a/test/Governance.t.sol b/test/Governance.t.sol index d8a60d63..55749aab 100644 --- a/test/Governance.t.sol +++ b/test/Governance.t.sol @@ -60,14 +60,14 @@ abstract contract GovernanceTest is Test { address internal constant user2 = address(0x10C9cff3c4Faa8A60cB8506a7A99411E6A199038); address internal constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - uint128 private constant REGISTRATION_FEE = 1e18; - uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; - uint32 private constant EPOCH_DURATION = 604800; + uint256 private constant REGISTRATION_FEE = 1e18; + uint256 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; + uint256 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; + uint256 private constant UNREGISTRATION_AFTER_EPOCHS = 4; + uint256 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; + uint256 private constant MIN_CLAIM = 500e18; + uint256 private constant MIN_ACCRUAL = 1000e18; + uint256 private constant EPOCH_DURATION = 604800; uint32 private constant EPOCH_VOTING_CUTOFF = 518400; GovernanceTester private governance; @@ -92,7 +92,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }); @@ -127,52 +127,60 @@ abstract contract GovernanceTest is Test { // should revert if the `_lqtyAmount` > `lqty.balanceOf(msg.sender)` _expectInsufficientAllowanceAndBalance(); - governance.depositLQTY(type(uint88).max); + governance.depositLQTY(1e26); + + uint256 lqtyDeposit = 2e18; // should not revert if the user doesn't have a UserProxy deployed yet address userProxy = governance.deriveUserProxyAddress(user); - lqty.approve(address(userProxy), 1e18); + lqty.approve(address(userProxy), lqtyDeposit); // vm.expectEmit("DepositLQTY", abi.encode(user, 1e18)); - // deploy and deposit 1 LQTY - governance.depositLQTY(1e18); - assertEq(UserProxy(payable(userProxy)).staked(), 1e18); - (uint88 allocatedLQTY, uint120 averageStakingTimestamp) = governance.userStates(user); - assertEq(allocatedLQTY, 0); - // first deposit should have an averageStakingTimestamp if block.timestamp - assertEq(averageStakingTimestamp, block.timestamp * 1e26); + // deploy and deposit 2 LQTY + governance.depositLQTY(lqtyDeposit); + assertEq(UserProxy(payable(userProxy)).staked(), lqtyDeposit); + (uint256 unallocatedLQTY, uint256 unallocatedOffset,,) = governance.userStates(user); + assertEq(unallocatedLQTY, lqtyDeposit); + + uint256 expectedOffset1 = block.timestamp * lqtyDeposit; + // first deposit should have an unallocated offset of deposit * block.timestamp + assertEq(unallocatedOffset, expectedOffset1); vm.warp(block.timestamp + timeIncrease); - lqty.approve(address(userProxy), 1e18); - governance.depositLQTY(1e18); - assertEq(UserProxy(payable(userProxy)).staked(), 2e18); - (allocatedLQTY, averageStakingTimestamp) = governance.userStates(user); - assertEq(allocatedLQTY, 0); - // subsequent deposits should have a stake weighted average - assertEq(averageStakingTimestamp, (block.timestamp - timeIncrease / 2) * 1e26, "Avg ts"); + // Deposit again + lqty.approve(address(userProxy), lqtyDeposit); + governance.depositLQTY(lqtyDeposit); + assertEq(UserProxy(payable(userProxy)).staked(), lqtyDeposit * 2); + (unallocatedLQTY, unallocatedOffset,,) = governance.userStates(user); + assertEq(unallocatedLQTY, lqtyDeposit * 2); + + uint256 expectedOffset2 = expectedOffset1 + block.timestamp * lqtyDeposit; + // subsequent deposits should result in an increased unallocated offset + assertEq(unallocatedOffset, expectedOffset2, "unallocated offset"); - // withdraw 0.5 half of LQTY + // withdraw half of LQTY vm.warp(block.timestamp + timeIncrease); vm.startPrank(address(this)); vm.expectRevert("Governance: user-proxy-not-deployed"); - governance.withdrawLQTY(1e18); + governance.withdrawLQTY(lqtyDeposit); vm.stopPrank(); vm.startPrank(user); - governance.withdrawLQTY(1e18); - assertEq(UserProxy(payable(userProxy)).staked(), 1e18); - (allocatedLQTY, averageStakingTimestamp) = governance.userStates(user); - assertEq(allocatedLQTY, 0); - assertEq(averageStakingTimestamp, ((block.timestamp - timeIncrease) - timeIncrease / 2) * 1e26, "avg ts2"); + governance.withdrawLQTY(lqtyDeposit); + assertEq(UserProxy(payable(userProxy)).staked(), lqtyDeposit); + (unallocatedLQTY, unallocatedOffset,,) = governance.userStates(user); + assertEq(unallocatedLQTY, lqtyDeposit); + // Withdrawing half of the LQTY should also halve the offset, i.e. withdraw "proportionally" from all past deposits + assertEq(unallocatedOffset, expectedOffset2 / 2, "unallocated offset2"); // withdraw remaining LQTY - governance.withdrawLQTY(1e18); + governance.withdrawLQTY(lqtyDeposit); assertEq(UserProxy(payable(userProxy)).staked(), 0); - (allocatedLQTY, averageStakingTimestamp) = governance.userStates(user); - assertEq(allocatedLQTY, 0); - assertEq(averageStakingTimestamp, ((block.timestamp - timeIncrease) - timeIncrease / 2) * 1e26, "avg ts3"); + (unallocatedLQTY, unallocatedOffset,,) = governance.userStates(user); + assertEq(unallocatedLQTY, 0); + assertEq(unallocatedOffset, 0, "unallocated offset2"); vm.stopPrank(); } @@ -236,14 +244,14 @@ abstract contract GovernanceTest is Test { vm.startPrank(wallet.addr); _expectInsufficientAllowanceAndBalance(); - governance.depositLQTYViaPermit(type(uint88).max, permitParams); + governance.depositLQTYViaPermit(1e26, permitParams); // deploy and deposit 1 LQTY governance.depositLQTYViaPermit(1e18, permitParams); assertEq(UserProxy(payable(userProxy)).staked(), 1e18); - (uint88 allocatedLQTY, uint120 averageStakingTimestamp) = governance.userStates(wallet.addr); - assertEq(allocatedLQTY, 0); - assertEq(averageStakingTimestamp, block.timestamp * 1e26); + (uint256 unallocatedLQTY, uint256 unallocatedOffset,,) = governance.userStates(wallet.addr); + assertEq(unallocatedLQTY, 1e18); + assertEq(unallocatedOffset, 1e18 * block.timestamp); } function test_claimFromStakingV1() public { @@ -322,8 +330,8 @@ abstract contract GovernanceTest is Test { } // should not revert under any input - function test_lqtyToVotes(uint88 _lqtyAmount, uint120 _currentTimestamp, uint120 _averageTimestamp) public { - governance.lqtyToVotes(_lqtyAmount, _currentTimestamp, _averageTimestamp); + function test_lqtyToVotes(uint88 _lqtyAmount, uint32 _currentTimestamp, uint256 _offset) public { + governance.lqtyToVotes(_lqtyAmount, _currentTimestamp, _offset); } function test_getLatestVotingThreshold() public { @@ -340,7 +348,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -374,7 +382,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: 10e18, minAccrual: 10e18, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -393,14 +401,18 @@ abstract contract GovernanceTest is Test { // should not revert under any state function test_calculateVotingThreshold_fuzz( - uint128 _votes, - uint16 _forEpoch, - uint88 _boldAccrued, - uint128 _votingThresholdFactor, - uint88 _minClaim + uint256 _votes, + uint256 _forEpoch, + uint256 _boldAccrued, + uint256 _votingThresholdFactor, + uint256 _minClaim ) public { - _votingThresholdFactor = _votingThresholdFactor % 1e18; - /// Clamp to prevent misconfig + _votes = bound(_votes, 0, type(uint128).max); + _forEpoch = bound(_forEpoch, 0, type(uint16).max); + _boldAccrued = bound(_boldAccrued, 0, 1e9 ether); + _votingThresholdFactor = bound(_votingThresholdFactor, 0, 1 ether - 1); + _minClaim = bound(_minClaim, 0, 1e9 ether); + governance = new GovernanceTester( address(lqty), address(lusd), @@ -413,8 +425,8 @@ abstract contract GovernanceTest is Test { unregistrationAfterEpochs: UNREGISTRATION_AFTER_EPOCHS, votingThresholdFactor: _votingThresholdFactor, minClaim: _minClaim, - minAccrual: type(uint88).max, - epochStart: uint32(block.timestamp), + minAccrual: type(uint256).max, + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -473,7 +485,7 @@ abstract contract GovernanceTest is Test { governance.registerInitiative(address(0)); governance.registerInitiative(baseInitiative3); - uint16 atEpoch = governance.registeredInitiatives(baseInitiative3); + uint256 atEpoch = governance.registeredInitiatives(baseInitiative3); assertEq(atEpoch, governance.epoch()); // should revert if the initiative was already registered @@ -546,24 +558,22 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1e18; deltaLQTYVotes[1] = 999e18; - int88[] memory deltaLQTYVetos = new int88[](2); + int256[] memory deltaLQTYVetos = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); - (uint256 allocatedLQTY,) = governance.userStates(user); + (,, uint256 allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 1_000e18); - (uint88 voteLQTY1,, uint120 averageStakingTimestampVoteLQTY1,,) = governance.initiativeStates(baseInitiative1); + (uint256 voteLQTY1, uint256 voteOffset1,,,) = governance.initiativeStates(baseInitiative1); - (uint88 voteLQTY2,,,,) = governance.initiativeStates(baseInitiative2); + (uint256 voteLQTY2,,,,) = governance.initiativeStates(baseInitiative2); // Get power at time of vote - uint256 votingPower = governance.lqtyToVotes( - voteLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY1 - ); + uint256 votingPower = governance.lqtyToVotes(voteLQTY1, block.timestamp, voteOffset1); assertGt(votingPower, 0, "Non zero power"); /// @audit TODO Fully digest and explain the bug @@ -583,9 +593,7 @@ abstract contract GovernanceTest is Test { assertLt(initiativeVoteSnapshot1.votes, threshold, "it didn't get rewards"); uint256 votingPowerWithProjection = governance.lqtyToVotes( - voteLQTY1, - uint120(governance.epochStart() + governance.EPOCH_DURATION()), - averageStakingTimestampVoteLQTY1 + voteLQTY1, uint256(governance.epochStart() + governance.EPOCH_DURATION()), voteOffset1 ); assertLt(votingPower, threshold, "Current Power is not enough - Desynch A"); assertLt(votingPowerWithProjection, threshold, "Future Power is also not enough - Desynch B"); @@ -609,10 +617,10 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1e18; deltaLQTYVotes[1] = 999e18; - int88[] memory deltaLQTYVetos = new int88[](2); + int256[] memory deltaLQTYVetos = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); @@ -644,8 +652,8 @@ abstract contract GovernanceTest is Test { removeInitiatives[1] = baseInitiative2; governance.resetAllocations(removeInitiatives, true); - int88[] memory removeDeltaLQTYVotes = new int88[](2); - int88[] memory removeDeltaLQTYVetos = new int88[](2); + int256[] memory removeDeltaLQTYVotes = new int256[](2); + int256[] memory removeDeltaLQTYVetos = new int256[](2); removeDeltaLQTYVotes[0] = -1e18; vm.expectRevert("Cannot be negative"); @@ -653,9 +661,9 @@ abstract contract GovernanceTest is Test { address[] memory reAddInitiatives = new address[](1); reAddInitiatives[0] = baseInitiative1; - int88[] memory reAddDeltaLQTYVotes = new int88[](1); + int256[] memory reAddDeltaLQTYVotes = new int256[](1); reAddDeltaLQTYVotes[0] = 1e18; - int88[] memory reAddDeltaLQTYVetos = new int88[](1); + int256[] memory reAddDeltaLQTYVetos = new int256[](1); /// @audit This MUST revert, an initiative should not be re-votable once disabled vm.expectRevert("Governance: active-vote-fsm"); @@ -685,10 +693,10 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1e18; deltaLQTYVotes[1] = 999e18; - int88[] memory deltaLQTYVetos = new int88[](2); + int256[] memory deltaLQTYVetos = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); @@ -703,7 +711,7 @@ abstract contract GovernanceTest is Test { // Get state here // Get initiative state - (uint88 b4_countedVoteLQTY, uint120 b4_countedVoteLQTYAverageTimestamp) = governance.globalState(); + (uint256 b4_countedVoteLQTY, uint256 b4_countedVoteOffset) = governance.globalState(); // I want to remove my allocation initiativesToReset = new address[](2); @@ -712,22 +720,20 @@ abstract contract GovernanceTest is Test { // don't need to explicitly remove allocation because it already gets reset address[] memory removeInitiatives = new address[](1); removeInitiatives[0] = baseInitiative2; - int88[] memory removeDeltaLQTYVotes = new int88[](1); + int256[] memory removeDeltaLQTYVotes = new int256[](1); removeDeltaLQTYVotes[0] = 999e18; - int88[] memory removeDeltaLQTYVetos = new int88[](1); + int256[] memory removeDeltaLQTYVetos = new int256[](1); governance.allocateLQTY(initiativesToReset, removeInitiatives, removeDeltaLQTYVotes, removeDeltaLQTYVetos); { // Get state here // TODO Get initiative state - (uint88 after_countedVoteLQTY, uint120 after_countedVoteLQTYAverageTimestamp) = governance.globalState(); + (uint256 after_countedVoteLQTY, uint256 after_countedVoteOffset) = governance.globalState(); assertEq(after_countedVoteLQTY, b4_countedVoteLQTY, "LQTY should not change"); - assertEq( - b4_countedVoteLQTYAverageTimestamp, after_countedVoteLQTYAverageTimestamp, "Avg TS should not change" - ); + assertEq(b4_countedVoteOffset, after_countedVoteOffset, "Offset should not change"); } } @@ -748,10 +754,10 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1e18; deltaLQTYVotes[1] = 999e18; - int88[] memory deltaLQTYVetos = new int88[](2); + int256[] memory deltaLQTYVetos = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); @@ -775,9 +781,9 @@ abstract contract GovernanceTest is Test { // Grab values b4 unregistering and b4 removing user allocation - (uint88 b4_countedVoteLQTY, uint120 b4_countedVoteLQTYAverageTimestamp) = governance.globalState(); - (uint88 b4_allocatedLQTY, uint120 b4_averageStakingTimestamp) = governance.userStates(user); - (uint88 b4_voteLQTY,,,,) = governance.initiativeStates(baseInitiative1); + (uint256 b4_countedVoteLQTY, uint256 b4_countedVoteOffset) = governance.globalState(); + (,, uint256 b4_allocatedLQTY, uint256 b4_allocatedOffset) = governance.userStates(user); + (uint256 b4_voteLQTY,,,,) = governance.initiativeStates(baseInitiative1); // Unregistering governance.unregisterInitiative(baseInitiative1); @@ -787,20 +793,20 @@ abstract contract GovernanceTest is Test { // We expect the state to already have those removed // We expect the user to not have any changes - (uint88 after_countedVoteLQTY,) = governance.globalState(); + (uint256 after_countedVoteLQTY,) = governance.globalState(); assertEq(after_countedVoteLQTY, b4_countedVoteLQTY - b4_voteLQTY, "Global Lqty change after unregister"); assertEq(1e18, b4_voteLQTY, "sanity check"); - (uint88 after_allocatedLQTY, uint120 after_averageStakingTimestamp) = governance.userStates(user); + (,, uint256 after_allocatedLQTY, uint256 after_unallocatedOffset) = governance.userStates(user); // We expect no changes here ( - uint88 after_voteLQTY, - uint88 after_vetoLQTY, - uint120 after_averageStakingTimestampVoteLQTY, - uint120 after_averageStakingTimestampVetoLQTY, - uint16 after_lastEpochClaim + uint256 after_voteLQTY, + uint256 after_voteOffset, + uint256 after_vetoLQTY, + uint256 after_vetoOffset, + uint256 after_lastEpochClaim ) = governance.initiativeStates(baseInitiative1); assertEq(b4_voteLQTY, after_voteLQTY, "Initiative votes are the same"); @@ -818,23 +824,21 @@ abstract contract GovernanceTest is Test { // After user counts LQTY the { - (uint88 after_user_countedVoteLQTY, uint120 after_user_countedVoteLQTYAverageTimestamp) = - governance.globalState(); + (uint256 after_user_countedVoteLQTY, uint256 after_user_countedVoteOffset) = governance.globalState(); // The LQTY was already removed assertEq(after_user_countedVoteLQTY, 0, "Removal 1"); } // User State allocated LQTY changes by entire previous allocation amount - // Timestamp should not change { - (uint88 after_user_allocatedLQTY,) = governance.userStates(user); + (,, uint256 after_user_allocatedLQTY,) = governance.userStates(user); assertEq(after_user_allocatedLQTY, 0, "Removal 2"); } // Check user math only change is the LQTY amt // user was the only one allocated so since all alocations were reset, the initative lqty should be 0 { - (uint88 after_user_voteLQTY,,,,) = governance.initiativeStates(baseInitiative1); + (uint256 after_user_voteLQTY,,,,) = governance.initiativeStates(baseInitiative1); assertEq(after_user_voteLQTY, 0, "Removal 3"); } @@ -857,13 +861,13 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1e18; deltaLQTYVotes[1] = 999e18; - int88[] memory deltaLQTYVetos = new int88[](2); + int256[] memory deltaLQTYVetos = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); - (uint88 allocatedB4Test,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + (uint256 allocatedB4Test,,,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); console.log("allocatedB4Test", allocatedB4Test); vm.warp(block.timestamp + governance.EPOCH_DURATION()); @@ -875,20 +879,20 @@ abstract contract GovernanceTest is Test { removeInitiatives[0] = baseInitiative1; removeInitiatives[1] = baseInitiative2; - (uint88 allocatedB4Removal,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + (uint256 allocatedB4Removal,,,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); console.log("allocatedB4Removal", allocatedB4Removal); governance.resetAllocations(removeInitiatives, true); - (uint88 allocatedAfterRemoval,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + (uint256 allocatedAfterRemoval,,,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); console.log("allocatedAfterRemoval", allocatedAfterRemoval); vm.expectRevert("Governance: nothing to reset"); governance.resetAllocations(removeInitiatives, true); - int88[] memory removeDeltaLQTYVotes = new int88[](2); - int88[] memory removeDeltaLQTYVetos = new int88[](2); + int256[] memory removeDeltaLQTYVotes = new int256[](2); + int256[] memory removeDeltaLQTYVetos = new int256[](2); vm.expectRevert("Governance: voting nothing"); governance.allocateLQTY(initiativesToReset, removeInitiatives, removeDeltaLQTYVotes, removeDeltaLQTYVetos); - (uint88 allocatedAfter,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + (uint256 allocatedAfter,,,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); console.log("allocatedAfter", allocatedAfter); } @@ -907,17 +911,17 @@ abstract contract GovernanceTest is Test { lqty.approve(address(userProxy), 1e18); governance.depositLQTY(1e18); - (uint88 allocatedLQTY, uint120 averageStakingTimestampUser) = governance.userStates(user); + (,, uint256 allocatedLQTY, uint256 allocatedOffset) = governance.userStates(user); assertEq(allocatedLQTY, 0); - (uint88 countedVoteLQTY,) = governance.globalState(); + (uint256 countedVoteLQTY,) = governance.globalState(); assertEq(countedVoteLQTY, 0); address[] memory initiativesToReset; address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaLQTYVotes = new int88[](1); + int256[] memory deltaLQTYVotes = new int256[](1); deltaLQTYVotes[0] = 1e18; //this should be 0 - int88[] memory deltaLQTYVetos = new int88[](1); + int256[] memory deltaLQTYVetos = new int256[](1); // should revert if the initiative has been registered in the current epoch vm.expectRevert("Governance: active-vote-fsm"); @@ -926,30 +930,22 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + governance.EPOCH_DURATION()); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); - (allocatedLQTY,) = governance.userStates(user); + (,, allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 1e18); - ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(baseInitiative1); + (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset,) = + governance.initiativeStates(baseInitiative1); // should update the `voteLQTY` and `vetoLQTY` variables assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); - // should update the average staking timestamp for the initiative based on the average staking timestamp of the user's - // voting and vetoing LQTY - assertEq(averageStakingTimestampVoteLQTY, (block.timestamp - governance.EPOCH_DURATION()) * 1e26); - assertEq(averageStakingTimestampVoteLQTY, averageStakingTimestampUser); - assertEq(averageStakingTimestampVetoLQTY, 0); + // TODO: assertions re: initiative vote & veto offsets // should remove or add the initiatives voting LQTY from the counter (countedVoteLQTY,) = governance.globalState(); assertEq(countedVoteLQTY, 1e18); - uint16 atEpoch; - (voteLQTY, vetoLQTY, atEpoch) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + uint256 atEpoch; + (voteLQTY,, vetoLQTY,, atEpoch) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); // should update the allocation mapping from user to initiative assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); @@ -957,7 +953,7 @@ abstract contract GovernanceTest is Test { assertGt(atEpoch, 0); // should snapshot the global and initiatives votes if there hasn't been a snapshot in the current epoch yet - (, uint16 forEpoch) = governance.votesSnapshot(); + (, uint256 forEpoch) = governance.votesSnapshot(); assertEq(forEpoch, governance.epoch() - 1); (, forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(forEpoch, governance.epoch() - 1); @@ -973,8 +969,15 @@ abstract contract GovernanceTest is Test { lqty.approve(address(user2Proxy), 1e18); governance.depositLQTY(1e18); - (, uint120 averageAge) = governance.userStates(user2); - assertEq(governance.lqtyToVotes(1e18, uint120(block.timestamp) * uint120(1e26), averageAge), 0); + IGovernance.UserState memory user2State; + (user2State.unallocatedLQTY, user2State.unallocatedOffset, user2State.allocatedLQTY, user2State.allocatedOffset) + = governance.userStates(user2); + assertEq(user2State.allocatedLQTY, 0); + assertEq(user2State.allocatedOffset, 0); + assertEq( + governance.lqtyToVotes(user2State.unallocatedLQTY, uint256(block.timestamp), user2State.unallocatedOffset), + 0 + ); deltaLQTYVetos[0] = 1e18; @@ -986,16 +989,13 @@ abstract contract GovernanceTest is Test { governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); // should update the user's allocated LQTY balance - (allocatedLQTY,) = governance.userStates(user2); + (,, allocatedLQTY,) = governance.userStates(user2); assertEq(allocatedLQTY, 1e18); - (voteLQTY, vetoLQTY, averageStakingTimestampVoteLQTY, averageStakingTimestampVetoLQTY,) = - governance.initiativeStates(baseInitiative1); + (voteLQTY, voteOffset, vetoLQTY, vetoOffset,) = governance.initiativeStates(baseInitiative1); assertEq(voteLQTY, 2e18); assertEq(vetoLQTY, 0); - assertEq(averageStakingTimestampVoteLQTY, (block.timestamp - governance.EPOCH_DURATION()) * 1e26); - assertGt(averageStakingTimestampVoteLQTY, averageStakingTimestampUser); - assertEq(averageStakingTimestampVetoLQTY, 0); + // TODO: assertions re: initiative vote + veto offsets // should revert if the user doesn't have enough unallocated LQTY available vm.expectRevert("Governance: must-allocate-zero"); @@ -1007,18 +1007,17 @@ abstract contract GovernanceTest is Test { initiatives[0] = baseInitiative1; governance.resetAllocations(initiatives, true); - (allocatedLQTY,) = governance.userStates(user2); + (,, allocatedLQTY,) = governance.userStates(user2); assertEq(allocatedLQTY, 0); (countedVoteLQTY,) = governance.globalState(); console.log("countedVoteLQTY: ", countedVoteLQTY); assertEq(countedVoteLQTY, 1e18); - (voteLQTY, vetoLQTY, averageStakingTimestampVoteLQTY, averageStakingTimestampVetoLQTY,) = - governance.initiativeStates(baseInitiative1); + (voteLQTY, voteOffset, vetoLQTY, vetoOffset,) = governance.initiativeStates(baseInitiative1); assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); - assertEq(averageStakingTimestampVoteLQTY, averageStakingTimestampUser); - assertEq(averageStakingTimestampVetoLQTY, 0); + // TODO: assertion re: vote offset + assertEq(vetoOffset, 0); vm.stopPrank(); } @@ -1031,17 +1030,17 @@ abstract contract GovernanceTest is Test { lqty.approve(address(userProxy), 1e18); governance.depositLQTY(1e18); - (uint88 allocatedLQTY, uint120 averageStakingTimestampUser) = governance.userStates(user); + (,, uint256 allocatedLQTY, uint256 allocatedOffset) = governance.userStates(user); assertEq(allocatedLQTY, 0); - (uint88 countedVoteLQTY,) = governance.globalState(); + (uint256 countedVoteLQTY,) = governance.globalState(); assertEq(countedVoteLQTY, 0); address[] memory initiativesToReset; address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaLQTYVotes = new int88[](1); + int256[] memory deltaLQTYVotes = new int256[](1); deltaLQTYVotes[0] = 1e18; //this should be 0 - int88[] memory deltaLQTYVetos = new int88[](1); + int256[] memory deltaLQTYVetos = new int256[](1); // should revert if the initiative has been registered in the current epoch vm.expectRevert("Governance: active-vote-fsm"); @@ -1050,30 +1049,24 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + governance.EPOCH_DURATION()); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); - (allocatedLQTY,) = governance.userStates(user); + (,, allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 1e18); - ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(baseInitiative1); + (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset,) = + governance.initiativeStates(baseInitiative1); // should update the `voteLQTY` and `vetoLQTY` variables assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); // should update the average staking timestamp for the initiative based on the average staking timestamp of the user's // voting and vetoing LQTY - assertEq(averageStakingTimestampVoteLQTY, (block.timestamp - governance.EPOCH_DURATION()) * 1e26, "TS"); - assertEq(averageStakingTimestampVoteLQTY, averageStakingTimestampUser); - assertEq(averageStakingTimestampVetoLQTY, 0); + // TODO: assertions re: vote + veto offsets // should remove or add the initiatives voting LQTY from the counter (countedVoteLQTY,) = governance.globalState(); assertEq(countedVoteLQTY, 1e18); - uint16 atEpoch; - (voteLQTY, vetoLQTY, atEpoch) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + uint256 atEpoch; + (voteLQTY,, vetoLQTY,, atEpoch) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); // should update the allocation mapping from user to initiative assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); @@ -1081,7 +1074,7 @@ abstract contract GovernanceTest is Test { assertGt(atEpoch, 0); // should snapshot the global and initiatives votes if there hasn't been a snapshot in the current epoch yet - (, uint16 forEpoch) = governance.votesSnapshot(); + (, uint256 forEpoch) = governance.votesSnapshot(); assertEq(forEpoch, governance.epoch() - 1); (, forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(forEpoch, governance.epoch() - 1); @@ -1097,8 +1090,8 @@ abstract contract GovernanceTest is Test { lqty.approve(address(user2Proxy), 1e18); governance.depositLQTY(1e18); - (, uint120 averageAge) = governance.userStates(user2); - assertEq(governance.lqtyToVotes(1e18, uint120(block.timestamp) * uint120(1e26), averageAge), 0); + (, uint256 unallocatedOffset,,) = governance.userStates(user2); + assertEq(governance.lqtyToVotes(1e18, block.timestamp, unallocatedOffset), 0); deltaLQTYVetos[0] = 1e18; @@ -1110,16 +1103,13 @@ abstract contract GovernanceTest is Test { governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); // should update the user's allocated LQTY balance - (allocatedLQTY,) = governance.userStates(user2); + (,, allocatedLQTY,) = governance.userStates(user2); assertEq(allocatedLQTY, 1e18); - (voteLQTY, vetoLQTY, averageStakingTimestampVoteLQTY, averageStakingTimestampVetoLQTY,) = - governance.initiativeStates(baseInitiative1); + (voteLQTY, voteOffset, vetoLQTY, vetoOffset,) = governance.initiativeStates(baseInitiative1); assertEq(voteLQTY, 2e18); assertEq(vetoLQTY, 0); - assertEq(averageStakingTimestampVoteLQTY, (block.timestamp - governance.EPOCH_DURATION()) * 1e26, "TS 2"); - assertGt(averageStakingTimestampVoteLQTY, averageStakingTimestampUser); - assertEq(averageStakingTimestampVetoLQTY, 0); + // TODO: offset vote + veto assertions // should revert if the user doesn't have enough unallocated LQTY available vm.expectRevert("Governance: must-allocate-zero"); @@ -1132,7 +1122,7 @@ abstract contract GovernanceTest is Test { // should only allow for unallocating votes or allocating vetos after the epoch voting cutoff // vm.expectRevert("Governance: epoch-voting-cutoff"); governance.allocateLQTY(initiatives, initiatives, deltaLQTYVotes, deltaLQTYVetos); - (allocatedLQTY,) = governance.userStates(msg.sender); + (,, allocatedLQTY,) = governance.userStates(msg.sender); // this no longer reverts but the user allocation doesn't increase either way assertEq(allocatedLQTY, 0, "user can allocate after voting cutoff"); @@ -1149,46 +1139,41 @@ abstract contract GovernanceTest is Test { lqty.approve(address(userProxy), 2e18); governance.depositLQTY(2e18); - (uint88 allocatedLQTY,) = governance.userStates(user); + (,, uint256 allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 0); - (uint88 countedVoteLQTY,) = governance.globalState(); + (uint256 countedVoteLQTY,) = governance.globalState(); assertEq(countedVoteLQTY, 0); address[] memory initiativesToReset; address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1e18; deltaLQTYVotes[1] = 1e18; - int88[] memory deltaLQTYVetos = new int88[](2); + int256[] memory deltaLQTYVetos = new int256[](2); vm.warp(block.timestamp + governance.EPOCH_DURATION()); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); - (allocatedLQTY,) = governance.userStates(user); + (,, allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 2e18); (countedVoteLQTY,) = governance.globalState(); assertEq(countedVoteLQTY, 2e18); - ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(baseInitiative1); + (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset,) = + governance.initiativeStates(baseInitiative1); assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); - (voteLQTY, vetoLQTY, averageStakingTimestampVoteLQTY, averageStakingTimestampVetoLQTY,) = - governance.initiativeStates(baseInitiative2); + (voteLQTY, voteOffset, vetoLQTY, vetoOffset,) = governance.initiativeStates(baseInitiative2); assertEq(voteLQTY, 1e18); assertEq(vetoLQTY, 0); } - function test_allocateLQTY_fuzz_deltaLQTYVotes(uint88 _deltaLQTYVotes) public { - vm.assume(_deltaLQTYVotes > 0 && _deltaLQTYVotes < uint88(type(int88).max)); + function test_allocateLQTY_fuzz_deltaLQTYVotes(uint256 _deltaLQTYVotes) public { + _deltaLQTYVotes = bound(_deltaLQTYVotes, 1, 100e6 ether); vm.startPrank(user); @@ -1201,9 +1186,9 @@ abstract contract GovernanceTest is Test { address[] memory initiativesToReset; address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaLQTYVotes = new int88[](1); - deltaLQTYVotes[0] = int88(uint88(_deltaLQTYVotes)); - int88[] memory deltaLQTYVetos = new int88[](1); + int256[] memory deltaLQTYVotes = new int256[](1); + deltaLQTYVotes[0] = int256(_deltaLQTYVotes); + int256[] memory deltaLQTYVetos = new int256[](1); vm.warp(block.timestamp + governance.EPOCH_DURATION()); @@ -1212,8 +1197,8 @@ abstract contract GovernanceTest is Test { vm.stopPrank(); } - function test_allocateLQTY_fuzz_deltaLQTYVetos(uint88 _deltaLQTYVetos) public { - vm.assume(_deltaLQTYVetos > 0 && _deltaLQTYVetos < uint88(type(int88).max)); + function test_allocateLQTY_fuzz_deltaLQTYVetos(uint256 _deltaLQTYVetos) public { + _deltaLQTYVetos = bound(_deltaLQTYVetos, 1, 100e6 ether); vm.startPrank(user); @@ -1226,9 +1211,9 @@ abstract contract GovernanceTest is Test { address[] memory initiativesToReset; address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaLQTYVotes = new int88[](1); - int88[] memory deltaLQTYVetos = new int88[](1); - deltaLQTYVetos[0] = int88(uint88(_deltaLQTYVetos)); + int256[] memory deltaLQTYVotes = new int256[](1); + int256[] memory deltaLQTYVetos = new int256[](1); + deltaLQTYVetos[0] = int256(_deltaLQTYVetos); vm.warp(block.timestamp + governance.EPOCH_DURATION()); @@ -1260,12 +1245,12 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaVoteLQTY = new int88[](2); + int256[] memory deltaVoteLQTY = new int256[](2); deltaVoteLQTY[0] = 500e18; deltaVoteLQTY[1] = 500e18; - int88[] memory deltaVetoLQTY = new int88[](2); + int256[] memory deltaVetoLQTY = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); - (uint88 allocatedLQTY,) = governance.userStates(user); + (,, uint256 allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 1000e18); vm.warp(block.timestamp + governance.EPOCH_DURATION() + 1); @@ -1294,8 +1279,8 @@ abstract contract GovernanceTest is Test { initiativesToReset[1] = baseInitiative2; initiatives = new address[](1); initiatives[0] = baseInitiative1; - deltaVoteLQTY = new int88[](1); - deltaVetoLQTY = new int88[](1); + deltaVoteLQTY = new int256[](1); + deltaVetoLQTY = new int256[](1); deltaVoteLQTY[0] = 495e18; // @audit user can't deallocate because votes already get reset // deltaVoteLQTY[1] = -495e18; @@ -1311,7 +1296,7 @@ abstract contract GovernanceTest is Test { (IGovernance.InitiativeStatus status,, uint256 claimable) = governance.getInitiativeState(baseInitiative2); console.log("res", uint8(status)); console.log("claimable", claimable); - (uint224 votes,,, uint224 vetos) = governance.votesForInitiativeSnapshot(baseInitiative2); + (uint256 votes,,, uint256 vetos) = governance.votesForInitiativeSnapshot(baseInitiative2); console.log("snapshot votes", votes); console.log("snapshot vetos", vetos); @@ -1350,12 +1335,12 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = EOAInitiative; // attempt for an EOA initiatives[1] = baseInitiative2; - int88[] memory deltaVoteLQTY = new int88[](2); + int256[] memory deltaVoteLQTY = new int256[](2); deltaVoteLQTY[0] = 500e18; deltaVoteLQTY[1] = 500e18; - int88[] memory deltaVetoLQTY = new int88[](2); + int256[] memory deltaVetoLQTY = new int256[](2); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); - (uint88 allocatedLQTY,) = governance.userStates(user); + (,, uint256 allocatedLQTY,) = governance.userStates(user); assertEq(allocatedLQTY, 1000e18); vm.warp(block.timestamp + governance.EPOCH_DURATION() + 1); @@ -1406,7 +1391,7 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + governance.EPOCH_DURATION()); - uint88 lqtyAmount = 1000e18; + uint256 lqtyAmount = 1000e18; uint256 lqtyBalance = lqty.balanceOf(user); lqty.approve(address(governance.deriveUserProxyAddress(user)), lqtyAmount); @@ -1415,17 +1400,17 @@ abstract contract GovernanceTest is Test { address[] memory initiativesToReset; address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaVoteLQTY = new int88[](1); - deltaVoteLQTY[0] = int88(uint88(lqtyAmount)); - int88[] memory deltaVetoLQTY = new int88[](1); + int256[] memory deltaVoteLQTY = new int256[](1); + deltaVoteLQTY[0] = int256(uint256(lqtyAmount)); + int256[] memory deltaVetoLQTY = new int256[](1); - int88[] memory deltaVoteLQTY_ = new int88[](1); + int256[] memory deltaVoteLQTY_ = new int256[](1); deltaVoteLQTY_[0] = 1; data[0] = abi.encodeWithSignature("deployUserProxy()"); - data[1] = abi.encodeWithSignature("depositLQTY(uint88)", lqtyAmount); + data[1] = abi.encodeWithSignature("depositLQTY(uint256)", lqtyAmount); data[2] = abi.encodeWithSignature( - "allocateLQTY(address[],address[],int88[],int88[])", + "allocateLQTY(address[],address[],int256[],int256[])", initiativesToReset, initiatives, deltaVoteLQTY, @@ -1434,13 +1419,17 @@ abstract contract GovernanceTest is Test { data[3] = abi.encodeWithSignature("userStates(address)", user); data[4] = abi.encodeWithSignature("snapshotVotesForInitiative(address)", baseInitiative1); data[5] = abi.encodeWithSignature( - "allocateLQTY(address[],address[],int88[],int88[])", initiatives, initiatives, deltaVoteLQTY_, deltaVetoLQTY + "allocateLQTY(address[],address[],int256[],int256[])", + initiatives, + initiatives, + deltaVoteLQTY_, + deltaVetoLQTY ); data[6] = abi.encodeWithSignature("resetAllocations(address[],bool)", initiatives, true); - data[7] = abi.encodeWithSignature("withdrawLQTY(uint88)", lqtyAmount); + data[7] = abi.encodeWithSignature("withdrawLQTY(uint256)", lqtyAmount); bytes[] memory response = governance.multiDelegateCall(data); - (uint88 allocatedLQTY,) = abi.decode(response[3], (uint88, uint120)); + (,, uint256 allocatedLQTY,) = abi.decode(response[3], (uint256, uint256, uint256, uint256)); assertEq(allocatedLQTY, lqtyAmount); (IGovernance.VoteSnapshot memory votes, IGovernance.InitiativeVoteSnapshot memory votesForInitiative) = abi.decode(response[4], (IGovernance.VoteSnapshot, IGovernance.InitiativeVoteSnapshot)); @@ -1475,15 +1464,15 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + governance.EPOCH_DURATION()); governance.registerInitiative(address(mockInitiative)); - uint16 atEpoch = governance.registeredInitiatives(address(mockInitiative)); + uint256 atEpoch = governance.registeredInitiatives(address(mockInitiative)); assertEq(atEpoch, governance.epoch()); vm.warp(block.timestamp + governance.EPOCH_DURATION()); address[] memory initiatives = new address[](1); initiatives[0] = address(mockInitiative); - int88[] memory deltaLQTYVotes = new int88[](1); - int88[] memory deltaLQTYVetos = new int88[](1); + int256[] memory deltaLQTYVotes = new int256[](1); + int256[] memory deltaLQTYVetos = new int256[](1); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); // check that votingThreshold is is high enough such that MIN_CLAIM is met @@ -1516,10 +1505,10 @@ abstract contract GovernanceTest is Test { initiatives[0] = baseInitiative1; initiatives[1] = baseInitiative2; - int88[] memory deltaLQTYVotes = new int88[](2); + int256[] memory deltaLQTYVotes = new int256[](2); deltaLQTYVotes[0] = 1; - deltaLQTYVotes[1] = type(int88).max; - int88[] memory deltaLQTYVetos = new int88[](2); + deltaLQTYVotes[1] = type(int256).max; + int256[] memory deltaLQTYVetos = new int256[](2); deltaLQTYVetos[0] = 0; deltaLQTYVetos[1] = 0; @@ -1530,7 +1519,7 @@ abstract contract GovernanceTest is Test { deltaLQTYVotes[0] = 0; deltaLQTYVotes[1] = 0; deltaLQTYVetos[0] = 1; - deltaLQTYVetos[1] = type(int88).max; + deltaLQTYVetos[1] = type(int256).max; vm.expectRevert("Governance: insufficient-or-allocated-lqty"); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); @@ -1553,7 +1542,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1562,19 +1551,16 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes liquity - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); - (uint88 allocatedLQTY0, uint120 averageStakingTimestamp0) = governance.userStates(user); - uint240 currentUserPower0 = - governance.lqtyToVotes(allocatedLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp0); + (,, uint256 allocatedLQTY0, uint256 allocatedOffset0) = governance.userStates(user); + uint256 currentUserPower0 = governance.lqtyToVotes(allocatedLQTY0, block.timestamp, allocatedOffset0); - (uint88 voteLQTY0,, uint120 averageStakingTimestampVoteLQTY0,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower0 = governance.lqtyToVotes( - voteLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY0 - ); + (uint256 voteLQTY0, uint256 voteOffset0,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower0 = governance.lqtyToVotes(voteLQTY0, block.timestamp, voteOffset0); - // (uint224 votes, uint16 forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + // (uint256 votes, uint256 forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); // console2.log("votes0: ", votes); // =========== epoch 2 ================== @@ -1584,21 +1570,18 @@ abstract contract GovernanceTest is Test { _allocateLQTY(user, lqtyAmount); // check user voting power for the current epoch - (uint88 allocatedLQTY1, uint120 averageStakingTimestamp1) = governance.userStates(user); - uint240 currentUserPower1 = - governance.lqtyToVotes(allocatedLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp1); - // user's allocated lqty should immediately increase their voting power + (,, uint256 allocatedLQTY1, uint256 allocatedOffset1) = governance.userStates(user); + uint256 currentUserPower1 = governance.lqtyToVotes(allocatedLQTY1, block.timestamp, allocatedOffset1); + // user's allocated lqty should have non-zero voting power assertGt(currentUserPower1, 0, "current user voting power is 0"); // check initiative voting power for the current epoch - (uint88 voteLQTY1,, uint120 averageStakingTimestampVoteLQTY1,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower1 = governance.lqtyToVotes( - voteLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY1 - ); + (uint256 voteLQTY1, uint256 votOffset1,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower1 = governance.lqtyToVotes(voteLQTY1, block.timestamp, votOffset1); assertGt(currentInitiativePower1, 0, "current initiative voting power is 0"); assertEq(currentUserPower1, currentInitiativePower1, "initiative and user voting power should be equal"); - // (uint224 votes, uint16 forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + // (uint256 votes, uint256 forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); // =========== epoch 2 (end) ================== // 3. warp to end of epoch 2 to see increase in voting power @@ -1607,22 +1590,19 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // user voting power should increase over a given chunk of time - (uint88 allocatedLQTY2, uint120 averageStakingTimestamp2) = governance.userStates(user); - uint240 currentUserPower2 = - governance.lqtyToVotes(allocatedLQTY2, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp2); + (,, uint256 allocatedLQTY2, uint256 allocatedOffset2) = governance.userStates(user); + uint256 currentUserPower2 = governance.lqtyToVotes(allocatedLQTY2, block.timestamp, allocatedOffset2); assertGt(currentUserPower2, currentUserPower1); // initiative voting power should increase over a given chunk of time - (uint88 voteLQTY2,, uint120 averageStakingTimestampVoteLQTY2,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower2 = governance.lqtyToVotes( - voteLQTY2, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY2 - ); + (uint256 voteLQTY2, uint256 voteOffset2,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower2 = governance.lqtyToVotes(voteLQTY2, block.timestamp, voteOffset2); assertEq( currentUserPower2, currentInitiativePower2, "user power and initiative power should increase by same amount" ); // votes should only get counted in the next epoch after they were allocated - (uint224 votes, uint16 forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes, uint256 forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(votes, 0, "votes get counted in epoch that they were allocated"); // =========== epoch 3 ================== @@ -1631,15 +1611,12 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // user voting power should increase - (uint88 allocatedLQTY3, uint120 averageStakingTimestamp3) = governance.userStates(user); - uint240 currentUserPower3 = - governance.lqtyToVotes(allocatedLQTY3, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp3); + (,, uint256 allocatedLQTY3, uint256 allocatedOffset) = governance.userStates(user); + uint256 currentUserPower3 = governance.lqtyToVotes(allocatedLQTY3, block.timestamp, allocatedOffset); // votes should match the voting power for the initiative and subsequently the user since they're the only one allocated - (uint88 voteLQTY3,, uint120 averageStakingTimestampVoteLQTY3,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower3 = governance.lqtyToVotes( - voteLQTY3, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY3 - ); + (uint256 voteLQTY3, uint256 voteOffset3,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower3 = governance.lqtyToVotes(voteLQTY3, block.timestamp, voteOffset3); // votes should be counted in this epoch (votes, forEpoch,,) = governance.votesForInitiativeSnapshot(baseInitiative1); @@ -1650,17 +1627,14 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + EPOCH_DURATION - 1); governance.snapshotVotesForInitiative(baseInitiative1); - (uint88 allocatedLQTY4, uint120 averageStakingTimestamp4) = governance.userStates(user); - uint240 currentUserPower4 = - governance.lqtyToVotes(allocatedLQTY4, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp4); + (,, uint256 allocatedLQTY4, uint256 allocatedOffset4) = governance.userStates(user); + uint256 currentUserPower4 = governance.lqtyToVotes(allocatedLQTY4, block.timestamp, allocatedOffset4); - (uint88 voteLQTY4,, uint120 averageStakingTimestampVoteLQTY4,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower4 = governance.lqtyToVotes( - voteLQTY4, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY4 - ); + (uint256 voteLQTY4, uint256 voteOffset4,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower4 = governance.lqtyToVotes(voteLQTY4, block.timestamp, voteOffset4); // checking if snapshotting at the end of an epoch increases the voting power - (uint224 votes2,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes2,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(votes, votes2, "votes for an initiative snapshot increase in same epoch"); // =========== epoch 3 (end) ================== @@ -1682,7 +1656,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1691,7 +1665,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes liquity - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 ================== @@ -1700,16 +1674,13 @@ abstract contract GovernanceTest is Test { assertEq(2, governance.epoch(), "not in epoch 2"); // check user voting power before allocation at epoch start - (uint88 allocatedLQTY0, uint120 averageStakingTimestamp0) = governance.userStates(user); - uint240 currentUserPower0 = - governance.lqtyToVotes(allocatedLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp0); + (,, uint256 allocatedLQTY0, uint256 allocatedOffset0) = governance.userStates(user); + uint256 currentUserPower0 = governance.lqtyToVotes(allocatedLQTY0, block.timestamp, allocatedOffset0); assertEq(currentUserPower0, 0, "user has voting power > 0"); // check initiative voting power before allocation at epoch start - (uint88 voteLQTY0,, uint120 averageStakingTimestampVoteLQTY0,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower0 = governance.lqtyToVotes( - voteLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY0 - ); + (uint256 voteLQTY0, uint256 voteOffset0,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower0 = governance.lqtyToVotes(voteLQTY0, block.timestamp, voteOffset0); assertEq(currentInitiativePower0, 0, "current initiative voting power is > 0"); _allocateLQTY(user, lqtyAmount); @@ -1718,16 +1689,13 @@ abstract contract GovernanceTest is Test { assertEq(2, governance.epoch(), "not in epoch 2"); // check user voting power after allocation at epoch end - (uint88 allocatedLQTY1, uint120 averageStakingTimestamp1) = governance.userStates(user); - uint240 currentUserPower1 = - governance.lqtyToVotes(allocatedLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp1); + (,, uint256 allocatedLQTY1, uint256 allocatedOffset1) = governance.userStates(user); + uint256 currentUserPower1 = governance.lqtyToVotes(allocatedLQTY1, block.timestamp, allocatedOffset1); assertGt(currentUserPower1, 0, "user has no voting power after allocation"); // check initiative voting power after allocation at epoch end - (uint88 voteLQTY1,, uint120 averageStakingTimestampVoteLQTY1,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower1 = governance.lqtyToVotes( - voteLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY1 - ); + (uint256 voteLQTY1, uint256 voteOffset1,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower1 = governance.lqtyToVotes(voteLQTY1, block.timestamp, voteOffset1); assertGt(currentInitiativePower1, 0, "initiative has no voting power after allocation"); // check that user and initiative voting power is equivalent at epoch end @@ -1737,16 +1705,13 @@ abstract contract GovernanceTest is Test { assertEq(42, governance.epoch(), "not in epoch 42"); // get user voting power after multiple epochs - (uint88 allocatedLQTY2, uint120 averageStakingTimestamp2) = governance.userStates(user); - uint240 currentUserPower2 = - governance.lqtyToVotes(allocatedLQTY2, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp2); + (,, uint256 allocatedLQTY2, uint256 allocatedOffset2) = governance.userStates(user); + uint256 currentUserPower2 = governance.lqtyToVotes(allocatedLQTY2, block.timestamp, allocatedOffset2); assertGt(currentUserPower2, currentUserPower1, "user voting power doesn't increase"); // get initiative voting power after multiple epochs - (uint88 voteLQTY2,, uint120 averageStakingTimestampVoteLQTY2,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower2 = governance.lqtyToVotes( - voteLQTY2, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY2 - ); + (uint256 voteLQTY2, uint256 voteOffset2,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower2 = governance.lqtyToVotes(voteLQTY2, block.timestamp, voteOffset2); assertGt(currentInitiativePower2, currentInitiativePower1, "initiative voting power doesn't increase"); // check that initiative and user voting always track each other @@ -1771,7 +1736,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1780,7 +1745,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -1788,10 +1753,8 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + EPOCH_DURATION); // warp to second epoch // get initiative voting power at start of epoch - (uint88 voteLQTY0,, uint120 averageStakingTimestampVoteLQTY0,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower0 = governance.lqtyToVotes( - voteLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY0 - ); + (uint256 voteLQTY0, uint256 voteOffset0,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower0 = governance.lqtyToVotes(voteLQTY0, block.timestamp, voteOffset0); assertEq(currentInitiativePower0, 0, "initiative voting power is > 0"); _allocateLQTY(user, lqtyAmount); @@ -1802,16 +1765,14 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // get initiative voting power at time of snapshot - (uint88 voteLQTY1,, uint120 averageStakingTimestampVoteLQTY1,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower1 = governance.lqtyToVotes( - voteLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY1 - ); + (uint256 voteLQTY1, uint256 voteOffset1,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower1 = governance.lqtyToVotes(voteLQTY1, block.timestamp, voteOffset1); assertGt(currentInitiativePower1, 0, "initiative voting power is 0"); - uint240 deltaInitiativeVotingPower = currentInitiativePower1 - currentInitiativePower0; + uint256 deltaInitiativeVotingPower = currentInitiativePower1 - currentInitiativePower0; // 4. votes should be counted in this epoch - (uint224 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(votes, deltaInitiativeVotingPower, "voting power should increase by amount user allocated"); } @@ -1831,7 +1792,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1840,7 +1801,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -1850,12 +1811,10 @@ abstract contract GovernanceTest is Test { _allocateLQTY(user, lqtyAmount); // get user voting power at start of epoch from lqtyAllocatedByUserToInitiative - (uint88 voteLQTY0,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); - (uint88 allocatedLQTY, uint120 averageStakingTimestamp) = governance.userStates(user); - uint240 currentInitiativePowerFrom1 = - governance.lqtyToVotes(voteLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp); - uint240 currentInitiativePowerFrom2 = - governance.lqtyToVotes(allocatedLQTY, uint120(block.timestamp) * uint120(1e26), averageStakingTimestamp); + (uint256 voteLQTY, uint256 voteOffset,,,) = governance.lqtyAllocatedByUserToInitiative(user, baseInitiative1); + (,, uint256 allocatedLQTY, uint256 allocatedOffset) = governance.userStates(user); + uint256 currentInitiativePowerFrom1 = governance.lqtyToVotes(voteLQTY, block.timestamp, voteOffset); + uint256 currentInitiativePowerFrom2 = governance.lqtyToVotes(allocatedLQTY, block.timestamp, allocatedOffset); assertEq( currentInitiativePowerFrom1, @@ -1864,8 +1823,8 @@ abstract contract GovernanceTest is Test { ); } - // checking if allocating to a different initiative in a different epoch modifies the avgStakingTimestamp - function test_average_timestamp() public { + // checking if allocating to a different initiative in a different epoch modifies the allocated offset + function test_allocated_offset() public { // =========== epoch 1 ================== governance = new GovernanceTester( address(lqty), @@ -1880,7 +1839,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1889,7 +1848,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 2e18; + uint256 lqtyAmount = 2e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -1899,8 +1858,8 @@ abstract contract GovernanceTest is Test { // user allocates to baseInitiative1 _allocateLQTY(user, 1e18); - // get user voting power at start of epoch 2 from lqtyAllocatedByUserToInitiative - (, uint120 averageStakingTimestamp1) = governance.userStates(user); + // get user voting power at start of epoch 2 + (,,, uint256 allocatedOffset1) = governance.userStates(user); // =========== epoch 3 (start) ================== // 3. user allocates to baseInitiative2 in epoch 3 @@ -1908,16 +1867,17 @@ abstract contract GovernanceTest is Test { address[] memory initiativesToReset = new address[](1); initiativesToReset[0] = address(baseInitiative1); + // this should reset all alloc to initiative1, and divert it to initative 2 _allocateLQTYToInitiative(user, baseInitiative2, 1e18, initiativesToReset); - // get user voting power at start of epoch 3 from lqtyAllocatedByUserToInitiative - (, uint120 averageStakingTimestamp2) = governance.userStates(user); - assertEq(averageStakingTimestamp1, averageStakingTimestamp2); + // check offsets are equal + (,,, uint256 allocatedOffset2) = governance.userStates(user); + assertEq(allocatedOffset1, allocatedOffset2); } // checking if allocating to same initiative modifies the average timestamp // forge test --match-test test_average_timestamp_same_initiative -vv - function test_average_timestamp_same_initiative() public { + function test_offset_same_initiative() public { // =========== epoch 1 ================== governance = new GovernanceTester( address(lqty), @@ -1932,7 +1892,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1941,7 +1901,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 2e18; + uint256 lqtyAmount = 2e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -1951,9 +1911,9 @@ abstract contract GovernanceTest is Test { // user allocates to baseInitiative1 _allocateLQTY(user, 1e18); - // get user voting power at start of epoch 2 from lqtyAllocatedByUserToInitiative - (, uint120 averageStakingTimestamp1) = governance.userStates(user); - console2.log("averageStakingTimestamp1: ", averageStakingTimestamp1); + // get user voting power at start of epoch 2 + (,,, uint256 allocatedOffset1) = governance.userStates(user); + console2.log("allocatedOffset1: ", allocatedOffset1); // =========== epoch 3 (start) ================== // 3. user allocates to baseInitiative1 in epoch 3 @@ -1961,13 +1921,13 @@ abstract contract GovernanceTest is Test { _allocateLQTY(user, 1e18); - // get user voting power at start of epoch 3 from lqtyAllocatedByUserToInitiative - (, uint120 averageStakingTimestamp2) = governance.userStates(user); - assertEq(averageStakingTimestamp1, averageStakingTimestamp2, "average timestamps differ"); + // get user voting power at start of epoch 3 + (,,, uint256 allocatedOffset2) = governance.userStates(user); + assertEq(allocatedOffset2, allocatedOffset1, "offsets differ"); } // checking if allocating to same initiative modifies the average timestamp - function test_average_timestamp_allocate_same_initiative_fuzz(uint256 allocateAmount) public { + function test_offset_allocate_same_initiative_fuzz(uint256 allocateAmount) public { // =========== epoch 1 ================== governance = new GovernanceTester( address(lqty), @@ -1982,7 +1942,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -1991,7 +1951,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = uint88(allocateAmount % lqty.balanceOf(user)); + uint256 lqtyAmount = uint256(allocateAmount % lqty.balanceOf(user)); vm.assume(lqtyAmount > 0); _stakeLQTY(user, lqtyAmount); @@ -2000,11 +1960,11 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + EPOCH_DURATION); // warp to second epoch // clamp lqtyAmount by half of what user staked - uint88 lqtyAmount2 = uint88(bound(allocateAmount, 1, lqtyAmount)); + uint256 lqtyAmount2 = uint256(bound(allocateAmount, 1, lqtyAmount)); _allocateLQTY(user, lqtyAmount2); - // get user voting power at start of epoch 2 from lqtyAllocatedByUserToInitiative - (, uint120 averageStakingTimestamp1) = governance.userStates(user); + // get user voting power at start of epoch 2 + (, uint256 unallocatedOffset1,, uint256 allocatedOffset1) = governance.userStates(user); // =========== epoch 3 (start) ================== // 3. user allocates to baseInitiative1 in epoch 3 @@ -2013,14 +1973,12 @@ abstract contract GovernanceTest is Test { // clamp lqtyAmount by amount user staked vm.assume(lqtyAmount > lqtyAmount2); vm.assume(lqtyAmount - lqtyAmount2 > 1); - uint88 lqtyAmount3 = uint88(bound(allocateAmount, 1, lqtyAmount - lqtyAmount2)); + uint256 lqtyAmount3 = uint256(bound(allocateAmount, 1, lqtyAmount - lqtyAmount2)); _allocateLQTY(user, lqtyAmount3); // get user voting power at start of epoch 3 from lqtyAllocatedByUserToInitiative - (, uint120 averageStakingTimestamp2) = governance.userStates(user); - assertEq( - averageStakingTimestamp1, averageStakingTimestamp2, "averageStakingTimestamp1 != averageStakingTimestamp2" - ); + (, uint256 unallocatedOffset2,, uint256 allocatedOffset2) = governance.userStates(user); + assertEq(unallocatedOffset2 + allocatedOffset2, unallocatedOffset1 + allocatedOffset1, "offset2 != offset1"); } function test_voting_snapshot_start_vs_end_epoch() public { @@ -2038,7 +1996,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -2047,7 +2005,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -2055,10 +2013,8 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + EPOCH_DURATION); // warp to second epoch // get initiative voting power at start of epoch - (uint88 voteLQTY0,, uint120 averageStakingTimestampVoteLQTY0,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower0 = governance.lqtyToVotes( - voteLQTY0, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY0 - ); + (uint256 voteLQTY0, uint256 voteOffset0,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower0 = governance.lqtyToVotes(voteLQTY0, block.timestamp, voteOffset0); assertEq(currentInitiativePower0, 0, "initiative voting power is > 0"); _allocateLQTY(user, lqtyAmount); @@ -2072,13 +2028,11 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // get initiative voting power at start of epoch - (uint88 voteLQTY1,, uint120 averageStakingTimestampVoteLQTY1,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower1 = governance.lqtyToVotes( - voteLQTY1, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY1 - ); + (uint256 voteLQTY1, uint256 voteOffset1,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower1 = governance.lqtyToVotes(voteLQTY1, block.timestamp, voteOffset1); // 4a. votes from snapshotting at begging of epoch - (uint224 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); console2.log("currentInitiativePower1: ", currentInitiativePower1); console2.log("votes: ", votes); @@ -2093,7 +2047,7 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // 4b. votes from snapshotting at end of epoch - (uint224 votes2,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes2,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(votes, votes2, "votes from snapshot are dependent on time at snapshot"); } @@ -2113,7 +2067,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -2122,7 +2076,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes liquity - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); uint256 stateBeforeAllocation = vm.snapshotState(); @@ -2139,7 +2093,7 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // get voting power from allocation in previous epoch - (uint224 votesFromAllocatingAtEpochStart,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votesFromAllocatingAtEpochStart,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); // ======================================== // ===== revert to initial state ========== @@ -2161,7 +2115,7 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // get voting power from allocation in previous epoch - (uint224 votesFromAllocatingAtEpochEnd,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votesFromAllocatingAtEpochEnd,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq( votesFromAllocatingAtEpochStart, votesFromAllocatingAtEpochEnd, @@ -2185,7 +2139,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -2194,7 +2148,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -2210,7 +2164,7 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // 4. votes should be counted in this epoch - (uint224 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertGt(votes, 0, "voting power should increase"); _deAllocateLQTY(user, 0); @@ -2218,7 +2172,7 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // 5. votes should still be counted in this epoch - (uint224 votes2,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes2,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertGt(votes2, 0, "voting power should not decrease this epoch"); // =========== epoch 4 ================== @@ -2227,12 +2181,11 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // 6. votes should be decreased in this epoch - (uint224 votes3,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes3,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(votes3, 0, "voting power should be decreased in this epoch"); } - // checking if deallocating changes the averageStakingTimestamp - function test_deallocating_decreases_avg_timestamp() public { + function test_deallocating_decreases_offset() public { // =========== epoch 1 ================== governance = new GovernanceTester( address(lqty), @@ -2247,7 +2200,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -2256,7 +2209,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // =========== epoch 2 (start) ================== @@ -2270,12 +2223,13 @@ abstract contract GovernanceTest is Test { vm.warp(block.timestamp + EPOCH_DURATION); governance.snapshotVotesForInitiative(baseInitiative1); - (, uint120 averageStakingTimestampBefore) = governance.userStates(user); + (,,, uint256 allocatedOffset) = governance.userStates(user); + assertGt(allocatedOffset, 0); _deAllocateLQTY(user, 0); - (, uint120 averageStakingTimestampAfter) = governance.userStates(user); - assertEq(averageStakingTimestampBefore, averageStakingTimestampAfter); + (,,, allocatedOffset) = governance.userStates(user); + assertEq(allocatedOffset, 0); } // vetoing shouldn't affect voting power of the initiative @@ -2294,7 +2248,7 @@ abstract contract GovernanceTest is Test { votingThresholdFactor: VOTING_THRESHOLD_FACTOR, minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp), + epochStart: uint256(block.timestamp), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -2303,7 +2257,7 @@ abstract contract GovernanceTest is Test { ); // 1. user stakes lqty - uint88 lqtyAmount = 1e18; + uint256 lqtyAmount = 1e18; _stakeLQTY(user, lqtyAmount); // 1. user2 stakes lqty @@ -2325,16 +2279,15 @@ abstract contract GovernanceTest is Test { governance.snapshotVotesForInitiative(baseInitiative1); // voting power for initiative should be the same as votes from snapshot - (uint88 voteLQTY,, uint120 averageStakingTimestampVoteLQTY,,) = governance.initiativeStates(baseInitiative1); - uint240 currentInitiativePower = - governance.lqtyToVotes(voteLQTY, uint120(block.timestamp) * uint120(1e26), averageStakingTimestampVoteLQTY); + (uint256 voteLQTY, uint256 voteOffset,,,) = governance.initiativeStates(baseInitiative1); + uint256 currentInitiativePower = governance.lqtyToVotes(voteLQTY, block.timestamp, voteOffset); // 4. votes should not affect accounting for votes - (uint224 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); + (uint256 votes,,,) = governance.votesForInitiativeSnapshot(baseInitiative1); assertEq(votes, currentInitiativePower, "voting power of initiative should not be affected by vetos"); } - function _stakeLQTY(address staker, uint88 amount) internal { + function _stakeLQTY(address staker, uint256 amount) internal { vm.startPrank(staker); address userProxy = governance.deriveUserProxyAddress(staker); lqty.approve(address(userProxy), amount); @@ -2343,11 +2296,11 @@ abstract contract GovernanceTest is Test { vm.stopPrank(); } - function _allocateLQTY(address allocator, uint88 amount) internal { + function _allocateLQTY(address allocator, uint256 amount) internal { vm.startPrank(allocator); address[] memory initiativesToReset; - (uint88 currentVote, uint88 currentVeto,) = + (uint256 currentVote,, uint256 currentVeto,,) = governance.lqtyAllocatedByUserToInitiative(allocator, address(baseInitiative1)); if (currentVote != 0 || currentVeto != 0) { initiativesToReset = new address[](1); @@ -2356,9 +2309,9 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaLQTYVotes = new int88[](1); - deltaLQTYVotes[0] = int88(amount); - int88[] memory deltaLQTYVetos = new int88[](1); + int256[] memory deltaLQTYVotes = new int256[](1); + deltaLQTYVotes[0] = int256(amount); + int256[] memory deltaLQTYVetos = new int256[](1); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); vm.stopPrank(); @@ -2367,26 +2320,26 @@ abstract contract GovernanceTest is Test { function _allocateLQTYToInitiative( address allocator, address initiative, - uint88 amount, + uint256 amount, address[] memory initiativesToReset ) internal { vm.startPrank(allocator); address[] memory initiatives = new address[](1); initiatives[0] = initiative; - int88[] memory deltaLQTYVotes = new int88[](1); - deltaLQTYVotes[0] = int88(amount); - int88[] memory deltaLQTYVetos = new int88[](1); + int256[] memory deltaLQTYVotes = new int256[](1); + deltaLQTYVotes[0] = int256(amount); + int256[] memory deltaLQTYVetos = new int256[](1); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); vm.stopPrank(); } - function _veto(address allocator, uint88 amount) internal { + function _veto(address allocator, uint256 amount) internal { vm.startPrank(allocator); address[] memory initiativesToReset; - (uint88 currentVote, uint88 currentVeto,) = + (uint256 currentVote,, uint256 currentVeto,,) = governance.lqtyAllocatedByUserToInitiative(allocator, address(baseInitiative1)); if (currentVote != 0 || currentVeto != 0) { initiativesToReset = new address[](1); @@ -2395,15 +2348,15 @@ abstract contract GovernanceTest is Test { address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; - int88[] memory deltaLQTYVotes = new int88[](1); - int88[] memory deltaLQTYVetos = new int88[](1); - deltaLQTYVetos[0] = int88(amount); + int256[] memory deltaLQTYVotes = new int256[](1); + int256[] memory deltaLQTYVetos = new int256[](1); + deltaLQTYVetos[0] = int256(amount); governance.allocateLQTY(initiativesToReset, initiatives, deltaLQTYVotes, deltaLQTYVetos); vm.stopPrank(); } - function _deAllocateLQTY(address allocator, uint88 amount) internal { + function _deAllocateLQTY(address allocator, uint256 amount) internal { address[] memory initiatives = new address[](1); initiatives[0] = baseInitiative1; diff --git a/test/GovernanceAttacks.t.sol b/test/GovernanceAttacks.t.sol index 476e3571..7629fd20 100644 --- a/test/GovernanceAttacks.t.sol +++ b/test/GovernanceAttacks.t.sol @@ -26,15 +26,15 @@ abstract contract GovernanceAttacksTest is Test { address internal constant user2 = address(0x10C9cff3c4Faa8A60cB8506a7A99411E6A199038); address internal constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - uint128 private constant REGISTRATION_FEE = 1e18; - uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; - uint32 private constant EPOCH_DURATION = 604800; - uint32 private constant EPOCH_VOTING_CUTOFF = 518400; + uint256 private constant REGISTRATION_FEE = 1e18; + uint256 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; + uint256 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; + uint256 private constant UNREGISTRATION_AFTER_EPOCHS = 4; + uint256 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; + uint256 private constant MIN_CLAIM = 500e18; + uint256 private constant MIN_ACCRUAL = 1000e18; + uint256 private constant EPOCH_DURATION = 604800; + uint256 private constant EPOCH_VOTING_CUTOFF = 518400; Governance private governance; address[] private initialInitiatives; @@ -59,7 +59,7 @@ abstract contract GovernanceAttacksTest is Test { minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, // backdate by 2 epochs to ensure new initiatives can be registered from the start - epochStart: uint32(block.timestamp - 2 * EPOCH_DURATION), + epochStart: uint256(block.timestamp - 2 * EPOCH_DURATION), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }); @@ -80,10 +80,10 @@ abstract contract GovernanceAttacksTest is Test { // deploy and deposit 1 LQTY governance.depositLQTY(1e18); assertEq(UserProxy(payable(userProxy)).staked(), 1e18); - (uint88 allocatedLQTY, uint120 averageStakingTimestamp) = governance.userStates(user); + (,, uint256 allocatedLQTY, uint256 allocatedOffset) = governance.userStates(user); assertEq(allocatedLQTY, 0); - // first deposit should have an averageStakingTimestamp if block.timestamp - assertEq(averageStakingTimestamp, block.timestamp * 1e26); // TODO: Normalize + // First deposit should have an unallocated offset of timestamp * deposit + assertEq(allocatedOffset, 0); vm.stopPrank(); vm.startPrank(lusdHolder); @@ -96,31 +96,31 @@ abstract contract GovernanceAttacksTest is Test { lusd.approve(address(governance), type(uint256).max); /// === REGISTRATION REVERTS === /// - uint256 registerNapshot = vm.snapshotState(); + uint256 registerNapshot = vm.snapshot(); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.REGISTER, MaliciousInitiative.RevertType.THROW ); governance.registerInitiative(address(maliciousInitiative2)); - vm.revertToState(registerNapshot); + vm.revertTo(registerNapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.REGISTER, MaliciousInitiative.RevertType.OOG ); governance.registerInitiative(address(maliciousInitiative2)); - vm.revertToState(registerNapshot); + vm.revertTo(registerNapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.REGISTER, MaliciousInitiative.RevertType.RETURN_BOMB ); governance.registerInitiative(address(maliciousInitiative2)); - vm.revertToState(registerNapshot); + vm.revertTo(registerNapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.REGISTER, MaliciousInitiative.RevertType.REVERT_BOMB ); governance.registerInitiative(address(maliciousInitiative2)); - vm.revertToState(registerNapshot); + vm.revertTo(registerNapshot); // Reset and continue maliciousInitiative2.setRevertBehaviour( @@ -139,38 +139,38 @@ abstract contract GovernanceAttacksTest is Test { address[] memory initiatives = new address[](2); initiatives[0] = address(maliciousInitiative2); initiatives[1] = address(eoaInitiative); - int88[] memory deltaVoteLQTY = new int88[](2); + int256[] memory deltaVoteLQTY = new int256[](2); deltaVoteLQTY[0] = 5e17; deltaVoteLQTY[1] = 5e17; - int88[] memory deltaVetoLQTY = new int88[](2); + int256[] memory deltaVetoLQTY = new int256[](2); /// === Allocate LQTY REVERTS === /// - uint256 allocateSnapshot = vm.snapshotState(); + uint256 allocateSnapshot = vm.snapshot(); vm.startPrank(user); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.ALLOCATE, MaliciousInitiative.RevertType.THROW ); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); - vm.revertToState(allocateSnapshot); + vm.revertTo(allocateSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.ALLOCATE, MaliciousInitiative.RevertType.OOG ); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); - vm.revertToState(allocateSnapshot); + vm.revertTo(allocateSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.ALLOCATE, MaliciousInitiative.RevertType.RETURN_BOMB ); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); - vm.revertToState(allocateSnapshot); + vm.revertTo(allocateSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.ALLOCATE, MaliciousInitiative.RevertType.REVERT_BOMB ); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); - vm.revertToState(allocateSnapshot); + vm.revertTo(allocateSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.ALLOCATE, MaliciousInitiative.RevertType.NONE @@ -180,31 +180,31 @@ abstract contract GovernanceAttacksTest is Test { vm.warp(block.timestamp + governance.EPOCH_DURATION() + 1); /// === Claim for initiative REVERTS === /// - uint256 claimShapsnot = vm.snapshotState(); + uint256 claimShapsnot = vm.snapshot(); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.CLAIM, MaliciousInitiative.RevertType.THROW ); governance.claimForInitiative(address(maliciousInitiative2)); - vm.revertToState(claimShapsnot); + vm.revertTo(claimShapsnot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.CLAIM, MaliciousInitiative.RevertType.OOG ); governance.claimForInitiative(address(maliciousInitiative2)); - vm.revertToState(claimShapsnot); + vm.revertTo(claimShapsnot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.CLAIM, MaliciousInitiative.RevertType.RETURN_BOMB ); governance.claimForInitiative(address(maliciousInitiative2)); - vm.revertToState(claimShapsnot); + vm.revertTo(claimShapsnot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.CLAIM, MaliciousInitiative.RevertType.REVERT_BOMB ); governance.claimForInitiative(address(maliciousInitiative2)); - vm.revertToState(claimShapsnot); + vm.revertTo(claimShapsnot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.CLAIM, MaliciousInitiative.RevertType.NONE @@ -221,9 +221,9 @@ abstract contract GovernanceAttacksTest is Test { initiativesToReset[1] = address(eoaInitiative); initiatives = new address[](1); initiatives[0] = address(maliciousInitiative1); - deltaVoteLQTY = new int88[](1); + deltaVoteLQTY = new int256[](1); deltaVoteLQTY[0] = 5e17; - deltaVetoLQTY = new int88[](1); + deltaVetoLQTY = new int256[](1); governance.allocateLQTY(initiativesToReset, initiatives, deltaVoteLQTY, deltaVetoLQTY); (Governance.VoteSnapshot memory v, Governance.InitiativeVoteSnapshot memory initData) = @@ -236,31 +236,31 @@ abstract contract GovernanceAttacksTest is Test { /// @audit needs 5? (v, initData) = governance.snapshotVotesForInitiative(address(maliciousInitiative2)); - uint256 unregisterSnapshot = vm.snapshotState(); + uint256 unregisterSnapshot = vm.snapshot(); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.UNREGISTER, MaliciousInitiative.RevertType.THROW ); governance.unregisterInitiative(address(maliciousInitiative2)); - vm.revertToState(unregisterSnapshot); + vm.revertTo(unregisterSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.UNREGISTER, MaliciousInitiative.RevertType.OOG ); governance.unregisterInitiative(address(maliciousInitiative2)); - vm.revertToState(unregisterSnapshot); + vm.revertTo(unregisterSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.UNREGISTER, MaliciousInitiative.RevertType.RETURN_BOMB ); governance.unregisterInitiative(address(maliciousInitiative2)); - vm.revertToState(unregisterSnapshot); + vm.revertTo(unregisterSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.UNREGISTER, MaliciousInitiative.RevertType.REVERT_BOMB ); governance.unregisterInitiative(address(maliciousInitiative2)); - vm.revertToState(unregisterSnapshot); + vm.revertTo(unregisterSnapshot); maliciousInitiative2.setRevertBehaviour( MaliciousInitiative.FunctionType.UNREGISTER, MaliciousInitiative.RevertType.NONE diff --git a/test/Math.t.sol b/test/Math.t.sol deleted file mode 100644 index 79e14aed..00000000 --- a/test/Math.t.sol +++ /dev/null @@ -1,139 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; - -import {Test} from "forge-std/Test.sol"; - -import {add, abs} from "src/utils/Math.sol"; - -contract AddComparer { - function libraryAdd(uint88 a, int88 b) public pure returns (uint88) { - return add(a, b); - } - // Differential test - // Verify that it will revert any time it overflows - // Verify we can never get a weird value - - function referenceAdd(uint88 a, int88 b) public pure returns (uint88) { - // Upscale both - int96 scaledA = int96(int256(uint256(a))); - int96 tempB = int96(b); - - int96 res = scaledA + tempB; - if (res < 0) { - revert("underflow"); - } - - if (res > int96(int256(uint256(type(uint88).max)))) { - revert("Too big"); - } - - return uint88(uint96(res)); - } -} - -contract AbsComparer { - function libraryAbs(int88 a) public pure returns (uint88) { - return abs(a); // by definition should fit, since input was int88 -> uint88 -> int88 - } - - event DebugEvent2(int256); - event DebugEvent(uint256); - - function referenceAbs(int88 a) public returns (uint88) { - int256 bigger = a; - uint256 ref = bigger < 0 ? uint256(-bigger) : uint256(bigger); - emit DebugEvent2(bigger); - emit DebugEvent(ref); - if (ref > type(uint88).max) { - revert("Too big"); - } - if (ref < type(uint88).min) { - revert("Too small"); - } - return uint88(ref); - } -} - -contract MathTests is Test { - // forge test --match-test test_math_fuzz_comparison -vv - function test_math_fuzz_comparison(uint88 a, int88 b) public { - vm.assume(a < uint88(type(int88).max)); - AddComparer tester = new AddComparer(); - - bool revertLib; - bool revertRef; - uint88 resultLib; - uint88 resultRef; - - try tester.libraryAdd(a, b) returns (uint88 x) { - resultLib = x; - } catch { - revertLib = true; - } - - try tester.referenceAdd(a, b) returns (uint88 x) { - resultRef = x; - } catch { - revertRef = true; - } - - // Negative overflow - if (revertLib == true && revertRef == false) { - // Check if we had a negative value - if (resultRef < 0) { - revertRef = true; - resultRef = uint88(0); - } - - // Check if we overflow on the positive - if (resultRef > uint88(type(int88).max)) { - // Overflow due to above limit - revertRef = true; - resultRef = uint88(0); - } - } - - assertEq(revertLib, revertRef, "Reverts"); // This breaks - assertEq(resultLib, resultRef, "Results"); // This should match excluding overflows - } - - /// @dev test that abs never incorrectly overflows - // forge test --match-test test_fuzz_abs_comparison -vv - /** - * [FAIL. Reason: reverts: false != true; counterexample: calldata=0x2c945365ffffffffffffffffffffffffffffffffffffffffff8000000000000000000000 args=[-154742504910672534362390528 [-1.547e26]]] - */ - function test_fuzz_abs_comparison(int88 a) public { - AbsComparer tester = new AbsComparer(); - - bool revertLib; - bool revertRef; - uint88 resultLib; - uint88 resultRef; - - try tester.libraryAbs(a) returns (uint88 x) { - resultLib = x; - } catch { - revertLib = true; - } - - try tester.referenceAbs(a) returns (uint88 x) { - resultRef = x; - } catch { - revertRef = true; - } - - assertEq(revertLib, revertRef, "reverts"); - assertEq(resultLib, resultRef, "results"); - } - - /// @dev Test that Abs never revert - /// It reverts on the smaller possible number - function test_fuzz_abs(int88 a) public { - /** - * Encountered 1 failing test in test/Math.t.sol:MathTests - * [FAIL. Reason: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=0x804d552cffffffffffffffffffffffffffffffffffffffff800000000000000000000000 args=[-39614081257132168796771975168 [-3.961e28]]] test_fuzz_abs(int88) (runs: 0, μ: 0, ~: 0) - */ - /// @audit Reverts at the absolute minimum due to overflow as it will remain negative - abs(a); - } -} diff --git a/test/UniV4Donations.t.sol b/test/UniV4Donations.t.sol index 68777039..e66c7409 100644 --- a/test/UniV4Donations.t.sol +++ b/test/UniV4Donations.t.sol @@ -61,15 +61,15 @@ abstract contract UniV4DonationsTest is Test, Deployers { address internal constant user = address(0xF977814e90dA44bFA03b6295A0616a897441aceC); address internal constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - uint128 private constant REGISTRATION_FEE = 1e18; - uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; - uint32 private constant EPOCH_DURATION = 604800; - uint32 private constant EPOCH_VOTING_CUTOFF = 518400; + uint256 private constant REGISTRATION_FEE = 1e18; + uint256 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; + uint256 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; + uint256 private constant UNREGISTRATION_AFTER_EPOCHS = 4; + uint256 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; + uint256 private constant MIN_CLAIM = 500e18; + uint256 private constant MIN_ACCRUAL = 1000e18; + uint256 private constant EPOCH_DURATION = 604800; + uint256 private constant EPOCH_VOTING_CUTOFF = 518400; Governance private governance; address[] private initialInitiatives; @@ -145,7 +145,7 @@ abstract contract UniV4DonationsTest is Test, Deployers { vm.startPrank(lusdHolder); assertEq(uniV4Donations.donateToPool(), 0, "d"); - (uint240 amount, uint16 epoch, uint256 released) = uniV4Donations.vesting(); + (uint256 amount, uint256 epoch, uint256 released) = uniV4Donations.vesting(); assertEq(amount, 1000e18, "amt"); assertEq(epoch, 1, "epoch"); assertEq(released, 0, "released"); @@ -196,7 +196,7 @@ abstract contract UniV4DonationsTest is Test, Deployers { vm.startPrank(lusdHolder); assertEq(uniV4Donations.donateToPool(), 0, "d"); - (uint240 amount, uint16 epoch, uint256 released) = uniV4Donations.vesting(); + (uint256 amount, uint256 epoch, uint256 released) = uniV4Donations.vesting(); assertEq(amount, amt, "amt"); assertEq(epoch, 1, "epoch"); assertEq(released, 0, "released"); diff --git a/test/VotingPower.t.sol b/test/VotingPower.t.sol index af969059..42408b79 100644 --- a/test/VotingPower.t.sol +++ b/test/VotingPower.t.sol @@ -1,500 +1,466 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.24; - -import {Test} from "forge-std/Test.sol"; -import {console} from "forge-std/console.sol"; - -import {IERC20} from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; - -import {IGovernance} from "../src/interfaces/IGovernance.sol"; -import {ILQTYStaking} from "../src/interfaces/ILQTYStaking.sol"; - -import {BribeInitiative} from "../src/BribeInitiative.sol"; -import {Governance} from "../src/Governance.sol"; - -import {MockERC20Tester} from "./mocks/MockERC20Tester.sol"; -import {MockStakingV1} from "./mocks/MockStakingV1.sol"; -import {MockStakingV1Deployer} from "./mocks/MockStakingV1Deployer.sol"; -import "./constants.sol"; - -abstract contract VotingPowerTest is Test { - IERC20 internal lqty; - IERC20 internal lusd; - ILQTYStaking internal stakingV1; - - address internal constant user = address(0xF977814e90dA44bFA03b6295A0616a897441aceC); - address internal constant user2 = address(0x10C9cff3c4Faa8A60cB8506a7A99411E6A199038); - address internal constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); - - uint128 private constant REGISTRATION_FEE = 1e18; - uint128 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 private constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 private constant MIN_CLAIM = 500e18; - uint88 private constant MIN_ACCRUAL = 1000e18; - uint32 private constant EPOCH_DURATION = 604800; - uint32 private constant EPOCH_VOTING_CUTOFF = 518400; - - Governance private governance; - address[] private initialInitiatives; - address private baseInitiative1; - - function setUp() public virtual { - IGovernance.Configuration memory config = IGovernance.Configuration({ - registrationFee: REGISTRATION_FEE, - registrationThresholdFactor: REGISTRATION_THRESHOLD_FACTOR, - unregistrationThresholdFactor: UNREGISTRATION_THRESHOLD_FACTOR, - unregistrationAfterEpochs: UNREGISTRATION_AFTER_EPOCHS, - votingThresholdFactor: VOTING_THRESHOLD_FACTOR, - minClaim: MIN_CLAIM, - minAccrual: MIN_ACCRUAL, - epochStart: uint32(block.timestamp - EPOCH_DURATION), - epochDuration: EPOCH_DURATION, - epochVotingCutoff: EPOCH_VOTING_CUTOFF - }); - - governance = new Governance( - address(lqty), address(lusd), address(stakingV1), address(lusd), config, address(this), new address[](0) - ); - - baseInitiative1 = address(new BribeInitiative(address(governance), address(lusd), address(lqty))); - initialInitiatives.push(baseInitiative1); - - governance.registerInitialInitiatives(initialInitiatives); - } - - /// Compare with removing all and re-allocating all at the 2nd epoch - // forge test --match-test test_math_soundness -vv - function test_math_soundness() public { - // Given a Multiplier, I can wait 8 times more time - // Or use 8 times more amt - uint8 multiplier = 2; - - uint88 lqtyAmount = 1e18; - - uint256 powerInTheFuture = governance.lqtyToVotes(lqtyAmount, multiplier + 1, 1); - // Amt when delta is 1 - // 0 when delta is 0 - uint256 powerFromMoreDeposits = - governance.lqtyToVotes(lqtyAmount * multiplier, uint32(block.timestamp + 1), uint32(block.timestamp)); - - assertEq(powerInTheFuture, powerFromMoreDeposits, "Same result"); - } - - function test_math_soundness_fuzz(uint32 multiplier) public view { - vm.assume(multiplier < type(uint32).max - 1); - uint88 lqtyAmount = 1e10; - - uint256 powerInTheFuture = governance.lqtyToVotes(lqtyAmount, multiplier + 1, 1); - - // Amt when delta is 1 - // 0 when delta is 0 - uint256 powerFromMoreDeposits = - governance.lqtyToVotes(lqtyAmount * multiplier, uint32(block.timestamp + 1), uint32(block.timestamp)); - - assertEq(powerInTheFuture, powerFromMoreDeposits, "Same result"); - } - - function _averageAge(uint32 _currentTimestamp, uint32 _averageTimestamp) internal pure returns (uint32) { - if (_averageTimestamp == 0 || _currentTimestamp < _averageTimestamp) return 0; - return _currentTimestamp - _averageTimestamp; - } - - function _calculateAverageTimestamp( - uint32 _prevOuterAverageTimestamp, - uint32 _newInnerAverageTimestamp, - uint88 _prevLQTYBalance, - uint88 _newLQTYBalance - ) internal view returns (uint32) { - if (_newLQTYBalance == 0) return 0; - - uint32 prevOuterAverageAge = _averageAge(uint32(block.timestamp), _prevOuterAverageTimestamp); - uint32 newInnerAverageAge = _averageAge(uint32(block.timestamp), _newInnerAverageTimestamp); - - uint88 newOuterAverageAge; - if (_prevLQTYBalance <= _newLQTYBalance) { - uint88 deltaLQTY = _newLQTYBalance - _prevLQTYBalance; - uint240 prevVotes = uint240(_prevLQTYBalance) * uint240(prevOuterAverageAge); - uint240 newVotes = uint240(deltaLQTY) * uint240(newInnerAverageAge); - uint240 votes = prevVotes + newVotes; - newOuterAverageAge = uint32(votes / uint240(_newLQTYBalance)); - } else { - uint88 deltaLQTY = _prevLQTYBalance - _newLQTYBalance; - uint240 prevVotes = uint240(_prevLQTYBalance) * uint240(prevOuterAverageAge); - uint240 newVotes = uint240(deltaLQTY) * uint240(newInnerAverageAge); - uint240 votes = (prevVotes >= newVotes) ? prevVotes - newVotes : 0; - newOuterAverageAge = uint32(votes / uint240(_newLQTYBalance)); - } - - if (newOuterAverageAge > block.timestamp) return 0; - return uint32(block.timestamp - newOuterAverageAge); - } - - // This test prepares for comparing votes and vetos for state - // forge test --match-test test_we_can_compare_votes_and_vetos -vv - // function test_we_can_compare_votes_and_vetos() public { - /// TODO AUDIT Known bug with rounding math - // uint32 current_time = 123123123; - // vm.warp(current_time); - // // State at X - // // State made of X and Y - // uint32 time = current_time - 124; - // uint88 votes = 124; - // uint240 power = governance.lqtyToVotes(votes, current_time, time); - - // assertEq(power, (_averageAge(current_time, time)) * votes, "simple product"); +// // SPDX-License-Identifier: UNLICENSED +// pragma solidity ^0.8.24; + +// import {Test} from "forge-std/Test.sol"; +// import {console} from "forge-std/console.sol"; + +// import {IERC20} from "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; + +// import {IGovernance} from "../src/interfaces/IGovernance.sol"; +// import {ILQTYStaking} from "../src/interfaces/ILQTYStaking.sol"; + +// import {BribeInitiative} from "../src/BribeInitiative.sol"; +// import {Governance} from "../src/Governance.sol"; + +// import {MockERC20Tester} from "./mocks/MockERC20Tester.sol"; +// import {MockStakingV1} from "./mocks/MockStakingV1.sol"; +// import {MockStakingV1Deployer} from "./mocks/MockStakingV1Deployer.sol"; +// import "./constants.sol"; + +// abstract contract VotingPowerTest is Test { +// IERC20 internal lqty; +// IERC20 internal lusd; +// ILQTYStaking internal stakingV1; + +// address internal constant user = address(0xF977814e90dA44bFA03b6295A0616a897441aceC); +// address internal constant user2 = address(0x10C9cff3c4Faa8A60cB8506a7A99411E6A199038); +// address internal constant lusdHolder = address(0xcA7f01403C4989d2b1A9335A2F09dD973709957c); + +// uint256 private constant REGISTRATION_FEE = 1e18; +// uint256 private constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; +// uint256 private constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; +// uint256 private constant UNREGISTRATION_AFTER_EPOCHS = 4; +// uint256 private constant VOTING_THRESHOLD_FACTOR = 0.04e18; +// uint256 private constant MIN_CLAIM = 500e18; +// uint256 private constant MIN_ACCRUAL = 1000e18; +// uint256 private constant EPOCH_DURATION = 604800; +// uint256 private constant EPOCH_VOTING_CUTOFF = 518400; + +// Governance private governance; +// address[] private initialInitiatives; +// address private baseInitiative1; + +// function setUp() public virtual { +// IGovernance.Configuration memory config = IGovernance.Configuration({ +// registrationFee: REGISTRATION_FEE, +// registrationThresholdFactor: REGISTRATION_THRESHOLD_FACTOR, +// unregistrationThresholdFactor: UNREGISTRATION_THRESHOLD_FACTOR, +// unregistrationAfterEpochs: UNREGISTRATION_AFTER_EPOCHS, +// votingThresholdFactor: VOTING_THRESHOLD_FACTOR, +// minClaim: MIN_CLAIM, +// minAccrual: MIN_ACCRUAL, +// epochStart: uint32(block.timestamp - EPOCH_DURATION), +// epochDuration: EPOCH_DURATION, +// epochVotingCutoff: EPOCH_VOTING_CUTOFF +// }); - // // if it's a simple product we have the properties of multiplication, we can get back the value by dividing the tiem - // uint88 resultingVotes = uint88(power / _averageAge(current_time, time)); +// governance = new Governance( +// address(lqty), address(lusd), address(stakingV1), address(lusd), config, address(this), new address[](0) +// ); + +// baseInitiative1 = address(new BribeInitiative(address(governance), address(lusd), address(lqty))); +// initialInitiatives.push(baseInitiative1); - // assertEq(resultingVotes, votes, "We can get it back"); +// governance.registerInitialInitiatives(initialInitiatives); +// } - // // If we can get it back, then we can also perform other operations like addition and subtraction - // // Easy when same TS +// /// Compare with removing all and re-allocating all at the 2nd epoch +// // forge test --match-test test_math_soundness -vv +// function test_math_soundness() public { +// // Given a Multiplier, I can wait 8 times more time +// // Or use 8 times more amt +// uint8 multiplier = 2; - // // // But how do we sum stuff with different TS? - // // // We need to sum the total and sum the % of average ts - // uint88 votes_2 = 15; - // uint32 time_2 = current_time - 15; +// uint256 lqtyAmount = 1e18; - // uint240 power_2 = governance.lqtyToVotes(votes_2, current_time, time_2); +// uint256 powerInTheFuture = governance.lqtyToVotes(lqtyAmount, multiplier + 1, 1); +// // Amt when delta is 1 +// // 0 when delta is 0 +// uint256 powerFromMoreDeposits = +// governance.lqtyToVotes(lqtyAmount * multiplier, uint32(block.timestamp + 1), uint32(block.timestamp)); - // uint240 total_power = power + power_2; +// assertEq(powerInTheFuture, powerFromMoreDeposits, "Same result"); +// } + +// function test_math_soundness_fuzz(uint32 multiplier) public view { +// vm.assume(multiplier < type(uint32).max - 1); +// uint256 lqtyAmount = 1e10; + +// uint256 powerInTheFuture = governance.lqtyToVotes(lqtyAmount, multiplier + 1, 1); + +// // Amt when delta is 1 +// // 0 when delta is 0 +// uint256 powerFromMoreDeposits = +// governance.lqtyToVotes(lqtyAmount * multiplier, uint32(block.timestamp + 1), uint32(block.timestamp)); - // assertLe(total_power, uint240(type(uint88).max), "LT"); +// assertEq(powerInTheFuture, powerFromMoreDeposits, "Same result"); +// } - // uint88 total_liquity = votes + votes_2; +// // This test prepares for comparing votes and vetos for state +// // forge test --match-test test_we_can_compare_votes_and_vetos -vv +// // function test_we_can_compare_votes_and_vetos() public { +// /// TODO AUDIT Known bug with rounding math +// // uint32 current_time = 123123123; +// // vm.warp(current_time); +// // // State at X +// // // State made of X and Y +// // uint32 time = current_time - 124; +// // uint256 votes = 124; +// // uint256 power = governance.lqtyToVotes(votes, current_time, time); - // uint32 avgTs = _calculateAverageTimestamp(time, time_2, votes, total_liquity); +// // assertEq(power, (_averageAge(current_time, time)) * votes, "simple product"); - // console.log("votes", votes); - // console.log("time", current_time - time); - // console.log("power", power); +// // // if it's a simple product we have the properties of multiplication, we can get back the value by dividing the tiem +// // uint256 resultingVotes = uint256(power / _averageAge(current_time, time)); - // console.log("votes_2", votes_2); - // console.log("time_2", current_time - time_2); - // console.log("power_2", power_2); +// // assertEq(resultingVotes, votes, "We can get it back"); - // uint256 total_power_from_avg = governance.lqtyToVotes(total_liquity, current_time, avgTs); +// // // If we can get it back, then we can also perform other operations like addition and subtraction +// // // Easy when same TS - // console.log("total_liquity", total_liquity); - // console.log("avgTs", current_time - avgTs); - // console.log("total_power_from_avg", total_power_from_avg); +// // // // But how do we sum stuff with different TS? +// // // // We need to sum the total and sum the % of average ts +// // uint256 votes_2 = 15; +// // uint32 time_2 = current_time - 15; - // // Now remove the same math so we show that the rounding can be weaponized, let's see +// // uint256 power_2 = governance.lqtyToVotes(votes_2, current_time, time_2); - // // WTF +// // uint256 total_power = power + power_2; - // // Prev, new, prev new - // // AVG TS is the prev outer - // // New Inner is time - // uint32 attacked_avg_ts = _calculateAverageTimestamp( - // avgTs, - // time_2, // User removes their time - // total_liquity, - // votes // Votes = total_liquity - Vote_2 - // ); +// // assertLe(total_power, uint256(type(uint256).max), "LT"); - // // NOTE: != time due to rounding error - // console.log("attacked_avg_ts", current_time - attacked_avg_ts); +// // uint256 total_liquity = votes + votes_2; - // // BASIC VOTING TEST - // // AFTER VOTING POWER IS X - // // AFTER REMOVING VOTING IS 0 +// // uint32 avgTs = _calculateAverageTimestamp(time, time_2, votes, total_liquity); - // // Add a middle of random shit - // // Show that the math remains sound +// // console.log("votes", votes); +// // console.log("time", current_time - time); +// // console.log("power", power); - // // Off by 40 BPS????? WAYY TOO MUCH | SOMETHING IS WRONG +// // console.log("votes_2", votes_2); +// // console.log("time_2", current_time - time_2); +// // console.log("power_2", power_2); - // // It doesn't sum up exactly becasue of rounding errors - // // But we need the rounding error to be in favour of the protocol - // // And currently they are not - // assertEq(total_power, total_power_from_avg, "Sums up"); +// // uint256 total_power_from_avg = governance.lqtyToVotes(total_liquity, current_time, avgTs); - // // From those we can find the average timestamp - // uint88 resultingReturnedVotes = uint88(total_power_from_avg / _averageAge(current_time, time)); - // assertEq(resultingReturnedVotes, total_liquity, "Lqty matches"); - // } +// // console.log("total_liquity", total_liquity); +// // console.log("avgTs", current_time - avgTs); +// // console.log("total_power_from_avg", total_power_from_avg); - // forge test --match-test test_crit_user_can_dilute_total_votes -vv - function test_crit_user_can_dilute_total_votes() public { - // User A deposits normaly - vm.startPrank(user); +// // // Now remove the same math so we show that the rounding can be weaponized, let's see - _stakeLQTY(user, 124); +// // // WTF - vm.warp(block.timestamp + 124 - 15); +// // // Prev, new, prev new +// // // AVG TS is the prev outer +// // // New Inner is time +// // uint32 attacked_avg_ts = _calculateAverageTimestamp( +// // avgTs, +// // time_2, // User removes their time +// // total_liquity, +// // votes // Votes = total_liquity - Vote_2 +// // ); - vm.startPrank(user2); - _stakeLQTY(user2, 15); +// // // NOTE: != time due to rounding error +// // console.log("attacked_avg_ts", current_time - attacked_avg_ts); - vm.warp(block.timestamp + 15); +// // // BASIC VOTING TEST +// // // AFTER VOTING POWER IS X +// // // AFTER REMOVING VOTING IS 0 - vm.startPrank(user); - _allocate(address(baseInitiative1), 124, 0); - uint256 user1_avg = _getAverageTS(baseInitiative1); +// // // Add a middle of random shit +// // // Show that the math remains sound - vm.startPrank(user2); - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); +// // // Off by 40 BPS????? WAYY TOO MUCH | SOMETHING IS WRONG - uint256 griefed_avg = _getAverageTS(baseInitiative1); +// // // It doesn't sum up exactly becasue of rounding errors +// // // But we need the rounding error to be in favour of the protocol +// // // And currently they are not +// // assertEq(total_power, total_power_from_avg, "Sums up"); - uint256 vote_power_1 = governance.lqtyToVotes(124, uint32(block.timestamp), uint32(user1_avg)); - uint256 vote_power_2 = governance.lqtyToVotes(124, uint32(block.timestamp), uint32(griefed_avg)); +// // // From those we can find the average timestamp +// // uint256 resultingReturnedVotes = uint256(total_power_from_avg / _averageAge(current_time, time)); +// // assertEq(resultingReturnedVotes, total_liquity, "Lqty matches"); +// // } - console.log("vote_power_1", vote_power_1); - console.log("vote_power_2", vote_power_2); +// // forge test --match-test test_crit_user_can_dilute_total_votes -vv +// // TODO: convert to an offset-based test +// // function test_crit_user_can_dilute_total_votes() public { +// // // User A deposits normaly +// // vm.startPrank(user); - // assertEq(user1_avg, griefed_avg, "same avg"); // BREAKS, OFF BY ONE +// // _stakeLQTY(user, 124); - // Causes a loss of power of 1 second per time this is done +// // vm.warp(block.timestamp + 124 - 15); - vm.startPrank(user); - _reset(address(baseInitiative1)); +// // vm.startPrank(user2); +// // _stakeLQTY(user2, 15); - uint256 final_avg = _getAverageTS(baseInitiative1); - console.log("final_avg", final_avg); +// // vm.warp(block.timestamp + 15); - // This is not an issue, except for bribes, bribes can get the last claimer DOSS - } +// // vm.startPrank(user); +// // _allocate(address(baseInitiative1), 124, 0); +// // uint256 user1_avg = _getAverageTS(baseInitiative1); - // forge test --match-test test_can_we_spam_to_revert -vv - function test_can_we_spam_to_revert() public { - // User A deposits normaly - vm.startPrank(user); +// // vm.startPrank(user2); +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); - _stakeLQTY(user, 124); +// // uint256 griefed_avg = _getAverageTS(baseInitiative1); - vm.warp(block.timestamp + 124); +// // uint256 vote_power_1 = governance.lqtyToVotes(124, uint32(block.timestamp), uint32(user1_avg)); +// // uint256 vote_power_2 = governance.lqtyToVotes(124, uint32(block.timestamp), uint32(griefed_avg)); - vm.startPrank(user2); - _stakeLQTY(user2, 15); +// // console.log("vote_power_1", vote_power_1); +// // console.log("vote_power_2", vote_power_2); - vm.startPrank(user); - _allocate(address(baseInitiative1), 124, 0); +// // // assertEq(user1_avg, griefed_avg, "same avg"); // BREAKS, OFF BY ONE - vm.startPrank(user2); - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); +// // // Causes a loss of power of 1 second per time this is done - uint256 griefed_avg = _getAverageTS(baseInitiative1); - console.log("griefed_avg", griefed_avg); - console.log("block.timestamp", block.timestamp); +// // vm.startPrank(user); +// // _reset(address(baseInitiative1)); - console.log("0?"); +// // uint256 final_avg = _getAverageTS(baseInitiative1); +// // console.log("final_avg", final_avg); - uint256 currentMagnifiedTs = uint120(block.timestamp) * uint120(1e26); +// // // This is not an issue, except for bribes, bribes can get the last claimer DOSS +// // } - vm.startPrank(user2); - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); +// // forge test --match-test test_can_we_spam_to_revert -vv +// // function test_can_we_spam_to_revert() public { +// // // User A deposits normaly +// // vm.startPrank(user); - uint256 ts = _getAverageTS(baseInitiative1); - uint256 delta = currentMagnifiedTs - ts; - console.log("griefed_avg", ts); - console.log("delta", delta); - console.log("currentMagnifiedTs", currentMagnifiedTs); +// // _stakeLQTY(user, 124); - console.log("0?"); - uint256 i; - while (i++ < 122) { - console.log("i", i); - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); - } +// // vm.warp(block.timestamp + 124); - console.log("1?"); +// // vm.startPrank(user2); +// // _stakeLQTY(user2, 15); - ts = _getAverageTS(baseInitiative1); - delta = currentMagnifiedTs - ts; - console.log("griefed_avg", ts); - console.log("delta", delta); - console.log("currentMagnifiedTs", currentMagnifiedTs); +// // vm.startPrank(user); +// // _allocate(address(baseInitiative1), 124, 0); - // One more time - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); - _allocate(address(baseInitiative1), 15, 0); - _reset(address(baseInitiative1)); - _allocate(address(baseInitiative1), 15, 0); +// // vm.startPrank(user2); +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); - /// NOTE: Keep 1 wei to keep rounding error - _allocate(address(baseInitiative1), 1, 0); - - ts = _getAverageTS(baseInitiative1); - console.log("griefed_avg", ts); - - vm.startPrank(user); - _reset(address(baseInitiative1)); - _allocate(address(baseInitiative1), 124, 0); - - ts = _getAverageTS(baseInitiative1); - console.log("end_ts", ts); - } - - // forge test --match-test test_basic_reset_flow -vv - function test_basic_reset_flow() public { - vm.startPrank(user); - // =========== epoch 1 ================== - // 1. user stakes lqty - int88 lqtyAmount = 2e18; - _stakeLQTY(user, uint88(lqtyAmount / 2)); - - // user allocates to baseInitiative1 - _allocate(address(baseInitiative1), lqtyAmount / 2, 0); // 50% to it - (uint88 allocatedLQTY,) = governance.userStates(user); - assertEq(allocatedLQTY, uint88(lqtyAmount / 2), "half"); - - _allocate(address(baseInitiative1), lqtyAmount / 2, 0); // 50% to it - assertEq(allocatedLQTY, uint88(lqtyAmount / 2), "still half, the math is absolute now"); - } - - // forge test --match-test test_cutoff_logic -vv - function test_cutoff_logic() public { - vm.startPrank(user); - // =========== epoch 1 ================== - // 1. user stakes lqty - int88 lqtyAmount = 2e18; - _stakeLQTY(user, uint88(lqtyAmount)); - - // user allocates to baseInitiative1 - _allocate(address(baseInitiative1), lqtyAmount / 2, 0); // 50% to it - (uint88 allocatedLQTY,) = governance.userStates(user); - assertEq(allocatedLQTY, uint88(lqtyAmount / 2), "Half"); - - // Go to Cutoff - // See that you can reduce - // See that you can Veto as much as you want - vm.warp(block.timestamp + (EPOCH_DURATION) - governance.EPOCH_VOTING_CUTOFF() + 1); // warp to end of second epoch before the voting cutoff - - // Go to end of epoch, lazy math - while (!(governance.secondsWithinEpoch() > governance.EPOCH_VOTING_CUTOFF())) { - vm.warp(block.timestamp + 6 hours); - } - assertTrue( - governance.secondsWithinEpoch() > governance.EPOCH_VOTING_CUTOFF(), "We should not be able to vote more" - ); - - // Should fail to allocate more - _tryAllocate(address(baseInitiative1), lqtyAmount, 0, "Cannot increase"); - - // Can allocate less - _allocate(address(baseInitiative1), lqtyAmount / 2 - 1, 0); - - // Can Veto more than allocate - _allocate(address(baseInitiative1), 0, lqtyAmount); - } - - // Check if Flashloan can be used to cause issues? - // A flashloan would cause issues in the measure in which it breaks any specific property - // Or expectation - - // Remove votes - // Removing votes would force you to exclusively remove - // You can always remove at any time afacit - // Removing just updates that + the weights - // The weights are the avg time * the number - - function _getAverageTS(address initiative) internal view returns (uint256) { - (,, uint120 averageStakingTimestampVoteLQTY,,) = governance.initiativeStates(initiative); - - return averageStakingTimestampVoteLQTY; - } - - function _stakeLQTY(address _user, uint88 amount) internal { - address userProxy = governance.deriveUserProxyAddress(_user); - lqty.approve(address(userProxy), amount); - - governance.depositLQTY(amount); - } - - // Helper function to get the current prank address - function currentUser() external view returns (address) { - return msg.sender; - } - - function _prepareAllocateParams(address initiative, int88 votes, int88 vetos) - internal - view - returns ( - address[] memory initiativesToReset, - address[] memory initiatives, - int88[] memory absoluteLQTYVotes, - int88[] memory absoluteLQTYVetos - ) - { - (uint88 currentVote, uint88 currentVeto,) = - governance.lqtyAllocatedByUserToInitiative(this.currentUser(), address(initiative)); - if (currentVote != 0 || currentVeto != 0) { - initiativesToReset = new address[](1); - initiativesToReset[0] = address(initiative); - } - - initiatives = new address[](1); - initiatives[0] = initiative; - absoluteLQTYVotes = new int88[](1); - absoluteLQTYVotes[0] = votes; - absoluteLQTYVetos = new int88[](1); - absoluteLQTYVetos[0] = vetos; - } - - function _allocate(address initiative, int88 votes, int88 vetos) internal { - ( - address[] memory initiativesToReset, - address[] memory initiatives, - int88[] memory absoluteLQTYVotes, - int88[] memory absoluteLQTYVetos - ) = _prepareAllocateParams(initiative, votes, vetos); - - governance.allocateLQTY(initiativesToReset, initiatives, absoluteLQTYVotes, absoluteLQTYVetos); - } - - function _tryAllocate(address initiative, int88 votes, int88 vetos, bytes memory expectedError) internal { - ( - address[] memory initiativesToReset, - address[] memory initiatives, - int88[] memory absoluteLQTYVotes, - int88[] memory absoluteLQTYVetos - ) = _prepareAllocateParams(initiative, votes, vetos); - - vm.expectRevert(expectedError); - governance.allocateLQTY(initiativesToReset, initiatives, absoluteLQTYVotes, absoluteLQTYVetos); - } - - function _reset(address initiative) internal { - address[] memory initiativesToReset = new address[](1); - initiativesToReset[0] = initiative; - governance.resetAllocations(initiativesToReset, true); - } -} - -contract MockedVotingPowerTest is VotingPowerTest, MockStakingV1Deployer { - function setUp() public override { - (MockStakingV1 mockStakingV1, MockERC20Tester mockLQTY, MockERC20Tester mockLUSD) = deployMockStakingV1(); - mockLQTY.mint(user, 2e18); - mockLQTY.mint(user2, 15); - - lqty = mockLQTY; - lusd = mockLUSD; - stakingV1 = mockStakingV1; - - super.setUp(); - } -} - -contract ForkedVotingPowerTest is VotingPowerTest { - function setUp() public override { - vm.createSelectFork(vm.rpcUrl("mainnet"), 20430000); - - lqty = IERC20(MAINNET_LQTY); - lusd = IERC20(MAINNET_LUSD); - stakingV1 = ILQTYStaking(MAINNET_LQTY_STAKING); - - super.setUp(); - } -} +// // uint256 griefed_avg = _getAverageTS(baseInitiative1); +// // console.log("griefed_avg", griefed_avg); +// // console.log("block.timestamp", block.timestamp); + +// // console.log("0?"); + +// // uint256 currentMagnifiedTs = uint256(block.timestamp) * uint256(1e26); + +// // vm.startPrank(user2); +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); + +// // uint256 ts = _getAverageTS(baseInitiative1); +// // uint256 delta = currentMagnifiedTs - ts; +// // console.log("griefed_avg", ts); +// // console.log("delta", delta); +// // console.log("currentMagnifiedTs", currentMagnifiedTs); + +// // console.log("0?"); +// // uint256 i; +// // while (i++ < 122) { +// // console.log("i", i); +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); +// // } + +// // console.log("1?"); + +// // ts = _getAverageTS(baseInitiative1); +// // delta = currentMagnifiedTs - ts; +// // console.log("griefed_avg", ts); +// // console.log("delta", delta); +// // console.log("currentMagnifiedTs", currentMagnifiedTs); + +// // // One more time +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); +// // _allocate(address(baseInitiative1), 15, 0); +// // _reset(address(baseInitiative1)); +// // _allocate(address(baseInitiative1), 15, 0); + +// // /// NOTE: Keep 1 wei to keep rounding error +// // _allocate(address(baseInitiative1), 1, 0); + +// // ts = _getAverageTS(baseInitiative1); +// // console.log("griefed_avg", ts); + +// // vm.startPrank(user); +// // _reset(address(baseInitiative1)); +// // _allocate(address(baseInitiative1), 124, 0); + +// // ts = _getAverageTS(baseInitiative1); +// // console.log("end_ts", ts); +// // } + +// // forge test --match-test test_basic_reset_flow -vv +// function test_basic_reset_flow() public { +// vm.startPrank(user); +// // =========== epoch 1 ================== +// // 1. user stakes lqty +// int256 lqtyAmount = 2e18; +// _stakeLQTY(user, uint256(lqtyAmount / 2)); + +// // user allocates to baseInitiative1 +// _allocate(address(baseInitiative1), lqtyAmount / 2, 0); // 50% to it +// (,,uint256 allocatedLQTY,) = governance.userStates(user); +// assertEq(allocatedLQTY, uint256(lqtyAmount / 2), "half"); + +// _allocate(address(baseInitiative1), lqtyAmount / 2, 0); // 50% to it +// assertEq(allocatedLQTY, uint256(lqtyAmount / 2), "still half, the math is absolute now"); +// } + +// // forge test --match-test test_cutoff_logic -vv +// function test_cutoff_logic() public { +// vm.startPrank(user); +// // =========== epoch 1 ================== +// // 1. user stakes lqty +// int256 lqtyAmount = 2e18; +// _stakeLQTY(user, uint256(lqtyAmount)); + +// // user allocates to baseInitiative1 +// _allocate(address(baseInitiative1), lqtyAmount / 2, 0); // 50% to it +// (,,uint256 allocatedLQTY,) = governance.userStates(user); +// assertEq(allocatedLQTY, uint256(lqtyAmount / 2), "Half"); + +// // Go to Cutoff +// // See that you can reduce +// // See that you can Veto as much as you want +// vm.warp(block.timestamp + (EPOCH_DURATION) - governance.EPOCH_VOTING_CUTOFF() + 1); // warp to end of second epoch before the voting cutoff + +// // Go to end of epoch, lazy math +// while (!(governance.secondsWithinEpoch() > governance.EPOCH_VOTING_CUTOFF())) { +// vm.warp(block.timestamp + 6 hours); +// } +// assertTrue( +// governance.secondsWithinEpoch() > governance.EPOCH_VOTING_CUTOFF(), "We should not be able to vote more" +// ); + +// // Should fail to allocate more +// _tryAllocate(address(baseInitiative1), lqtyAmount, 0, "Cannot increase"); + +// // Can allocate less +// _allocate(address(baseInitiative1), lqtyAmount / 2 - 1, 0); + +// // Can Veto more than allocate +// _allocate(address(baseInitiative1), 0, lqtyAmount); +// } + +// // Check if Flashloan can be used to cause issues? +// // A flashloan would cause issues in the measure in which it breaks any specific property +// // Or expectation + +// // Remove votes +// // Removing votes would force you to exclusively remove +// // You can always remove at any time afacit +// // Removing just updates that + the weights +// // The weights are the avg time * the number + +// function _getInitiativeOffset(address initiative) internal view returns (uint256) { +// (,uint256 voteOffset,,,) = governance.initiativeStates(initiative); + +// return voteOffset; +// } + +// function _stakeLQTY(address _user, uint256 amount) internal { +// address userProxy = governance.deriveUserProxyAddress(_user); +// lqty.approve(address(userProxy), amount); + +// governance.depositLQTY(amount); +// } + +// // Helper function to get the current prank address +// function currentUser() external view returns (address) { +// return msg.sender; +// } + +// function _prepareAllocateParams(address initiative, int256 votes, int256 vetos) +// internal +// view +// returns ( +// address[] memory initiativesToReset, +// address[] memory initiatives, +// int256[] memory absoluteLQTYVotes, +// int256[] memory absoluteLQTYVetos +// ) +// { +// (uint256 currentVote, uint256 currentVeto,) = +// governance.lqtyAllocatedByUserToInitiative(this.currentUser(), address(initiative)); +// if (currentVote != 0 || currentVeto != 0) { +// initiativesToReset = new address[](1); +// initiativesToReset[0] = address(initiative); +// } + +// initiatives = new address[](1); +// initiatives[0] = initiative; +// absoluteLQTYVotes = new int256[](1); +// absoluteLQTYVotes[0] = votes; +// absoluteLQTYVetos = new int256[](1); +// absoluteLQTYVetos[0] = vetos; +// } + +// function _allocate(address initiative, int256 votes, int256 vetos) internal { +// ( +// address[] memory initiativesToReset, +// address[] memory initiatives, +// int256[] memory absoluteLQTYVotes, +// int256[] memory absoluteLQTYVetos +// ) = _prepareAllocateParams(initiative, votes, vetos); + +// governance.allocateLQTY(initiativesToReset, initiatives, absoluteLQTYVotes, absoluteLQTYVetos); +// } + +// function _tryAllocate(address initiative, int256 votes, int256 vetos, bytes memory expectedError) internal { +// ( +// address[] memory initiativesToReset, +// address[] memory initiatives, +// int256[] memory absoluteLQTYVotes, +// int256[] memory absoluteLQTYVetos +// ) = _prepareAllocateParams(initiative, votes, vetos); + +// vm.expectRevert(expectedError); +// governance.allocateLQTY(initiativesToReset, initiatives, absoluteLQTYVotes, absoluteLQTYVetos); +// } + +// function _reset(address initiative) internal { +// address[] memory initiativesToReset = new address[](1); +// initiativesToReset[0] = initiative; +// governance.resetAllocations(initiativesToReset, true); +// } +// } + +// contract MockedVotingPowerTest is VotingPowerTest, MockStakingV1Deployer { +// function setUp() public override { +// (MockStakingV1 mockStakingV1, MockERC20Tester mockLQTY, MockERC20Tester mockLUSD) = deployMockStakingV1(); +// mockLQTY.mint(user, 2e18); +// mockLQTY.mint(user2, 15); + +// lqty = mockLQTY; +// lusd = mockLUSD; +// stakingV1 = mockStakingV1; + +// super.setUp(); +// } +// } + +// contract ForkedVotingPowerTest is VotingPowerTest { +// function setUp() public override { +// vm.createSelectFork(vm.rpcUrl("mainnet"), 20430000); + +// lqty = IERC20(MAINNET_LQTY); +// lusd = IERC20(MAINNET_LUSD); +// stakingV1 = ILQTYStaking(MAINNET_LQTY_STAKING); + +// super.setUp(); +// } +// } diff --git a/test/mocks/MaliciousInitiative.sol b/test/mocks/MaliciousInitiative.sol index 494d9284..ffb3e82a 100644 --- a/test/mocks/MaliciousInitiative.sol +++ b/test/mocks/MaliciousInitiative.sol @@ -29,16 +29,16 @@ contract MaliciousInitiative is IInitiative { } // Do stuff on each hook - function onRegisterInitiative(uint16) external view override { + function onRegisterInitiative(uint256) external view override { _performRevertBehaviour(revertBehaviours[FunctionType.REGISTER]); } - function onUnregisterInitiative(uint16) external view override { + function onUnregisterInitiative(uint256) external view override { _performRevertBehaviour(revertBehaviours[FunctionType.UNREGISTER]); } function onAfterAllocateLQTY( - uint16, + uint256, address, IGovernance.UserState calldata, IGovernance.Allocation calldata, @@ -47,7 +47,7 @@ contract MaliciousInitiative is IInitiative { _performRevertBehaviour(revertBehaviours[FunctionType.ALLOCATE]); } - function onClaimForInitiative(uint16, uint256) external view override { + function onClaimForInitiative(uint256, uint256) external view override { _performRevertBehaviour(revertBehaviours[FunctionType.CLAIM]); } diff --git a/test/mocks/MockGovernance.sol b/test/mocks/MockGovernance.sol index ee94c8c7..045f2ee7 100644 --- a/test/mocks/MockGovernance.sol +++ b/test/mocks/MockGovernance.sol @@ -2,33 +2,33 @@ pragma solidity ^0.8.24; contract MockGovernance { - uint16 private __epoch; + uint256 private __epoch; - uint32 public constant EPOCH_START = 0; - uint32 public constant EPOCH_DURATION = 7 days; + uint256 public constant EPOCH_START = 0; + uint256 public constant EPOCH_DURATION = 7 days; function claimForInitiative(address) external pure returns (uint256) { return 1000e18; } - function setEpoch(uint16 _epoch) external { + function setEpoch(uint256 _epoch) external { __epoch = _epoch; } - function epoch() external view returns (uint16) { + function epoch() external view returns (uint256) { return __epoch; } - function _averageAge(uint120 _currentTimestamp, uint120 _averageTimestamp) internal pure returns (uint120) { + function _averageAge(uint256 _currentTimestamp, uint256 _averageTimestamp) internal pure returns (uint256) { if (_averageTimestamp == 0 || _currentTimestamp < _averageTimestamp) return 0; return _currentTimestamp - _averageTimestamp; } - function lqtyToVotes(uint88 _lqtyAmount, uint120 _currentTimestamp, uint120 _averageTimestamp) + function lqtyToVotes(uint256 _lqtyAmount, uint256 _currentTimestamp, uint256 _averageTimestamp) public pure - returns (uint208) + returns (uint256) { - return uint208(_lqtyAmount) * uint208(_averageAge(_currentTimestamp, _averageTimestamp)); + return uint256(_lqtyAmount) * uint256(_averageAge(_currentTimestamp, _averageTimestamp)); } } diff --git a/test/mocks/MockInitiative.sol b/test/mocks/MockInitiative.sol index 47205589..91030dda 100644 --- a/test/mocks/MockInitiative.sol +++ b/test/mocks/MockInitiative.sol @@ -12,31 +12,31 @@ contract MockInitiative is IInitiative { } /// @inheritdoc IInitiative - function onRegisterInitiative(uint16) external virtual override { + function onRegisterInitiative(uint256) external virtual override { governance.registerInitiative(address(0)); } /// @inheritdoc IInitiative - function onUnregisterInitiative(uint16) external virtual override { + function onUnregisterInitiative(uint256) external virtual override { governance.unregisterInitiative(address(0)); } /// @inheritdoc IInitiative function onAfterAllocateLQTY( - uint16, + uint256, address, IGovernance.UserState calldata, IGovernance.Allocation calldata, IGovernance.InitiativeState calldata ) external virtual { address[] memory initiatives = new address[](0); - int88[] memory deltaLQTYVotes = new int88[](0); - int88[] memory deltaLQTYVetos = new int88[](0); + int256[] memory deltaLQTYVotes = new int256[](0); + int256[] memory deltaLQTYVetos = new int256[](0); governance.allocateLQTY(initiatives, initiatives, deltaLQTYVotes, deltaLQTYVetos); } /// @inheritdoc IInitiative - function onClaimForInitiative(uint16, uint256) external virtual override { + function onClaimForInitiative(uint256, uint256) external virtual override { governance.claimForInitiative(address(0)); } } diff --git a/test/recon/BeforeAfter.sol b/test/recon/BeforeAfter.sol index b704dcad..c2a93fdd 100644 --- a/test/recon/BeforeAfter.sol +++ b/test/recon/BeforeAfter.sol @@ -9,12 +9,12 @@ import {Governance} from "src/Governance.sol"; abstract contract BeforeAfter is Setup, Asserts { struct Vars { - uint16 epoch; + uint256 epoch; mapping(address => IGovernance.InitiativeStatus) initiativeStatus; // initiative => user => epoch => claimed - mapping(address => mapping(address => mapping(uint16 => bool))) claimedBribeForInitiativeAtEpoch; - mapping(address user => uint128 lqtyBalance) userLqtyBalance; - mapping(address user => uint128 lusdBalance) userLusdBalance; + mapping(address => mapping(address => mapping(uint256 => bool))) claimedBribeForInitiativeAtEpoch; + mapping(address user => uint256 lqtyBalance) userLqtyBalance; + mapping(address user => uint256 lusdBalance) userLusdBalance; } Vars internal _before; @@ -27,7 +27,7 @@ abstract contract BeforeAfter is Setup, Asserts { } function __before() internal { - uint16 currentEpoch = governance.epoch(); + uint256 currentEpoch = governance.epoch(); _before.epoch = currentEpoch; for (uint8 i; i < deployedInitiatives.length; i++) { address initiative = deployedInitiatives[i]; @@ -38,13 +38,13 @@ abstract contract BeforeAfter is Setup, Asserts { } for (uint8 j; j < users.length; j++) { - _before.userLqtyBalance[users[j]] = uint128(lqty.balanceOf(user)); - _before.userLusdBalance[users[j]] = uint128(lusd.balanceOf(user)); + _before.userLqtyBalance[users[j]] = uint256(lqty.balanceOf(user)); + _before.userLusdBalance[users[j]] = uint256(lusd.balanceOf(user)); } } function __after() internal { - uint16 currentEpoch = governance.epoch(); + uint256 currentEpoch = governance.epoch(); _after.epoch = currentEpoch; for (uint8 i; i < deployedInitiatives.length; i++) { address initiative = deployedInitiatives[i]; @@ -55,8 +55,8 @@ abstract contract BeforeAfter is Setup, Asserts { } for (uint8 j; j < users.length; j++) { - _after.userLqtyBalance[users[j]] = uint128(lqty.balanceOf(user)); - _after.userLusdBalance[users[j]] = uint128(lusd.balanceOf(user)); + _after.userLqtyBalance[users[j]] = uint256(lqty.balanceOf(user)); + _after.userLusdBalance[users[j]] = uint256(lusd.balanceOf(user)); } } } diff --git a/test/recon/Setup.sol b/test/recon/Setup.sol index ff4ffb8a..1182bd5d 100644 --- a/test/recon/Setup.sol +++ b/test/recon/Setup.sol @@ -29,17 +29,17 @@ abstract contract Setup is BaseSetup, MockStakingV1Deployer { bool internal claimedTwice; bool internal unableToClaim; - uint128 internal constant REGISTRATION_FEE = 1e18; - uint128 internal constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; - uint128 internal constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; - uint16 internal constant UNREGISTRATION_AFTER_EPOCHS = 4; - uint128 internal constant VOTING_THRESHOLD_FACTOR = 0.04e18; - uint88 internal constant MIN_CLAIM = 500e18; - uint88 internal constant MIN_ACCRUAL = 1000e18; - uint32 internal constant EPOCH_DURATION = 604800; - uint32 internal constant EPOCH_VOTING_CUTOFF = 518400; - - uint120 magnifiedStartTS; + uint256 internal constant REGISTRATION_FEE = 1e18; + uint256 internal constant REGISTRATION_THRESHOLD_FACTOR = 0.01e18; + uint256 internal constant UNREGISTRATION_THRESHOLD_FACTOR = 4e18; + uint256 internal constant UNREGISTRATION_AFTER_EPOCHS = 4; + uint256 internal constant VOTING_THRESHOLD_FACTOR = 0.04e18; + uint256 internal constant MIN_CLAIM = 500e18; + uint256 internal constant MIN_ACCRUAL = 1000e18; + uint256 internal constant EPOCH_DURATION = 604800; + uint256 internal constant EPOCH_VOTING_CUTOFF = 518400; + + uint256 magnifiedStartTS; function setup() internal virtual override { vm.warp(block.timestamp + EPOCH_DURATION * 4); // Somehow Medusa goes back after the constructor @@ -68,7 +68,7 @@ abstract contract Setup is BaseSetup, MockStakingV1Deployer { minClaim: MIN_CLAIM, minAccrual: MIN_ACCRUAL, // backdate by 2 epochs to ensure new initiatives can be registered from the start - epochStart: uint32(block.timestamp - 2 * EPOCH_DURATION), + epochStart: uint256(block.timestamp - 2 * EPOCH_DURATION), epochDuration: EPOCH_DURATION, epochVotingCutoff: EPOCH_VOTING_CUTOFF }), @@ -91,7 +91,7 @@ abstract contract Setup is BaseSetup, MockStakingV1Deployer { governance.registerInitiative(address(initiative1)); - magnifiedStartTS = uint120(block.timestamp) * uint120(1e18); + magnifiedStartTS = uint256(block.timestamp) * uint256(1e18); } function _getDeployedInitiative(uint8 index) internal view returns (address initiative) { diff --git a/test/recon/TargetFunctions.sol b/test/recon/TargetFunctions.sol index f1a7335a..2d07e757 100644 --- a/test/recon/TargetFunctions.sol +++ b/test/recon/TargetFunctions.sol @@ -24,8 +24,8 @@ abstract contract TargetFunctions is GovernanceTargets, BribeInitiativeTargets { } // helper to simulate bold accrual in Governance contract - function helper_accrueBold(uint88 boldAmount) public withChecks { - boldAmount = uint88(boldAmount % lusd.balanceOf(user)); + function helper_accrueBold(uint256 boldAmount) public withChecks { + boldAmount = uint256(boldAmount % lusd.balanceOf(user)); // target contract is the user so it can transfer directly lusd.transfer(address(governance), boldAmount); } diff --git a/test/recon/properties/BribeInitiativeProperties.sol b/test/recon/properties/BribeInitiativeProperties.sol index 6c041115..676f4b8d 100644 --- a/test/recon/properties/BribeInitiativeProperties.sol +++ b/test/recon/properties/BribeInitiativeProperties.sol @@ -6,38 +6,38 @@ import {IBribeInitiative} from "../../../src/interfaces/IBribeInitiative.sol"; abstract contract BribeInitiativeProperties is BeforeAfter { function property_BI01() public { - uint16 currentEpoch = governance.epoch(); + uint256 currentEpoch = governance.epoch(); - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { address initiative = deployedInitiatives[i]; - for (uint8 j; j < users.length; j++) { + for (uint256 j; j < users.length; j++) { // if the bool switches, the user has claimed their bribe for the epoch if ( _before.claimedBribeForInitiativeAtEpoch[initiative][users[j]][currentEpoch] != _after.claimedBribeForInitiativeAtEpoch[initiative][user][currentEpoch] ) { // calculate user balance delta of the bribe tokens - uint128 userLqtyBalanceDelta = _after.userLqtyBalance[users[j]] - _before.userLqtyBalance[users[j]]; - uint128 userLusdBalanceDelta = _after.userLusdBalance[users[j]] - _before.userLusdBalance[users[j]]; + uint256 userLqtyBalanceDelta = _after.userLqtyBalance[users[j]] - _before.userLqtyBalance[users[j]]; + uint256 userLusdBalanceDelta = _after.userLusdBalance[users[j]] - _before.userLusdBalance[users[j]]; // calculate balance delta as a percentage of the total bribe for this epoch // this is what user DOES receive - (uint128 bribeBoldAmount, uint128 bribeBribeTokenAmount) = + (uint256 bribeBoldAmount, uint256 bribeBribeTokenAmount) = IBribeInitiative(initiative).bribeByEpoch(currentEpoch); - uint128 lqtyPercentageOfBribe = (userLqtyBalanceDelta * 10_000) / bribeBribeTokenAmount; - uint128 lusdPercentageOfBribe = (userLusdBalanceDelta * 10_000) / bribeBoldAmount; + uint256 lqtyPercentageOfBribe = (userLqtyBalanceDelta * 10_000) / bribeBribeTokenAmount; + uint256 lusdPercentageOfBribe = (userLusdBalanceDelta * 10_000) / bribeBoldAmount; // Shift right by 40 bits (128 - 88) to get the 88 most significant bits for needed downcasting to compare with lqty allocations - uint88 lqtyPercentageOfBribe88 = uint88(lqtyPercentageOfBribe >> 40); - uint88 lusdPercentageOfBribe88 = uint88(lusdPercentageOfBribe >> 40); + uint256 lqtyPercentageOfBribe88 = uint256(lqtyPercentageOfBribe >> 40); + uint256 lusdPercentageOfBribe88 = uint256(lusdPercentageOfBribe >> 40); // calculate user allocation percentage of total for this epoch // this is what user SHOULD receive - (uint88 lqtyAllocatedByUserAtEpoch,) = + (uint256 lqtyAllocatedByUserAtEpoch,) = IBribeInitiative(initiative).lqtyAllocatedByUserAtEpoch(users[j], currentEpoch); - (uint88 totalLQTYAllocatedAtEpoch,) = + (uint256 totalLQTYAllocatedAtEpoch,) = IBribeInitiative(initiative).totalLQTYAllocatedByEpoch(currentEpoch); - uint88 allocationPercentageOfTotal = + uint256 allocationPercentageOfTotal = (lqtyAllocatedByUserAtEpoch * 10_000) / totalLQTYAllocatedAtEpoch; // check that allocation percentage and received bribe percentage match @@ -61,12 +61,13 @@ abstract contract BribeInitiativeProperties is BeforeAfter { } function property_BI03() public { - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); - (uint88 voteLQTY,, uint16 epoch) = governance.lqtyAllocatedByUserToInitiative(user, deployedInitiatives[i]); + (uint256 voteLQTY,,,, uint256 epoch) = + governance.lqtyAllocatedByUserToInitiative(user, deployedInitiatives[i]); - try initiative.lqtyAllocatedByUserAtEpoch(user, epoch) returns (uint88 amt, uint120) { + try initiative.lqtyAllocatedByUserAtEpoch(user, epoch) returns (uint256 amt, uint256) { eq(voteLQTY, amt, "Allocation must match"); } catch { t(false, "Allocation doesn't match governance"); @@ -75,28 +76,28 @@ abstract contract BribeInitiativeProperties is BeforeAfter { } function property_BI04() public { - uint16 currentEpoch = governance.epoch(); - for (uint8 i; i < deployedInitiatives.length; i++) { + uint256 currentEpoch = governance.epoch(); + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); // NOTE: This doesn't revert in the future! - uint88 lastKnownLQTYAlloc = _getLastLQTYAllocationKnown(initiative, currentEpoch); + uint256 lastKnownLQTYAlloc = _getLastLQTYAllocationKnown(initiative, currentEpoch); // We compare when we don't get a revert (a change happened this epoch) - (uint88 voteLQTY,,,,) = governance.initiativeStates(deployedInitiatives[i]); + (uint256 voteLQTY,,,,) = governance.initiativeStates(deployedInitiatives[i]); eq(lastKnownLQTYAlloc, voteLQTY, "BI-04: Initiative Account matches governace"); } } - function _getLastLQTYAllocationKnown(IBribeInitiative initiative, uint16 targetEpoch) + function _getLastLQTYAllocationKnown(IBribeInitiative initiative, uint256 targetEpoch) internal view - returns (uint88) + returns (uint256) { - uint16 mostRecentTotalEpoch = initiative.getMostRecentTotalEpoch(); - (uint88 totalLQTYAllocatedAtEpoch,) = initiative.totalLQTYAllocatedByEpoch( + uint256 mostRecentTotalEpoch = initiative.getMostRecentTotalEpoch(); + (uint256 totalLQTYAllocatedAtEpoch,) = initiative.totalLQTYAllocatedByEpoch( (targetEpoch < mostRecentTotalEpoch) ? targetEpoch : mostRecentTotalEpoch ); return totalLQTYAllocatedAtEpoch; @@ -110,16 +111,16 @@ abstract contract BribeInitiativeProperties is BeforeAfter { // Dust cap check // function property_BI05() public { // // users can't claim for current epoch so checking for previous - // uint16 checkEpoch = governance.epoch() - 1; + // uint256 checkEpoch = governance.epoch() - 1; - // for (uint8 i; i < deployedInitiatives.length; i++) { + // for (uint256 i; i < deployedInitiatives.length; i++) { // address initiative = deployedInitiatives[i]; // // for any epoch: expected balance = Bribe - claimed bribes, actual balance = bribe token balance of initiative // // so if the delta between the expected and actual is > 0, dust is being collected // uint256 lqtyClaimedAccumulator; // uint256 lusdClaimedAccumulator; - // for (uint8 j; j < users.length; j++) { + // for (uint256 j; j < users.length; j++) { // // if the bool switches, the user has claimed their bribe for the epoch // if ( // _before.claimedBribeForInitiativeAtEpoch[initiative][user][checkEpoch] @@ -131,18 +132,18 @@ abstract contract BribeInitiativeProperties is BeforeAfter { // } // } - // (uint128 boldAmount, uint128 bribeTokenAmount) = IBribeInitiative(initiative).bribeByEpoch(checkEpoch); + // (uint256 boldAmount, uint256 bribeTokenAmount) = IBribeInitiative(initiative).bribeByEpoch(checkEpoch); // // shift 128 bit to the right to get the most significant bits of the accumulator (256 - 128 = 128) - // uint128 lqtyClaimedAccumulator128 = uint128(lqtyClaimedAccumulator >> 128); - // uint128 lusdClaimedAccumulator128 = uint128(lusdClaimedAccumulator >> 128); + // uint256 lqtyClaimedAccumulator128 = uint256(lqtyClaimedAccumulator >> 128); + // uint256 lusdClaimedAccumulator128 = uint256(lusdClaimedAccumulator >> 128); // // find delta between bribe and claimed amount (how much should be remaining in contract) - // uint128 lusdDelta = boldAmount - lusdClaimedAccumulator128; - // uint128 lqtyDelta = bribeTokenAmount - lqtyClaimedAccumulator128; + // uint256 lusdDelta = boldAmount - lusdClaimedAccumulator128; + // uint256 lqtyDelta = bribeTokenAmount - lqtyClaimedAccumulator128; - // uint128 initiativeLusdBalance = uint128(lusd.balanceOf(initiative) >> 128); - // uint128 initiativeLqtyBalance = uint128(lqty.balanceOf(initiative) >> 128); + // uint256 initiativeLusdBalance = uint256(lusd.balanceOf(initiative) >> 128); + // uint256 initiativeLqtyBalance = uint256(lqty.balanceOf(initiative) >> 128); // lte( // lusdDelta - initiativeLusdBalance, @@ -160,19 +161,19 @@ abstract contract BribeInitiativeProperties is BeforeAfter { function property_BI07() public { // sum user allocations for an epoch // check that this matches the total allocation for the epoch - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); - uint16 currentEpoch = initiative.getMostRecentTotalEpoch(); + uint256 currentEpoch = initiative.getMostRecentTotalEpoch(); - uint88 sumLqtyAllocated; - for (uint8 j; j < users.length; j++) { + uint256 sumLqtyAllocated; + for (uint256 j; j < users.length; j++) { // NOTE: We need to grab user latest - uint16 userEpoch = initiative.getMostRecentUserEpoch(users[j]); - (uint88 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], userEpoch); + uint256 userEpoch = initiative.getMostRecentUserEpoch(users[j]); + (uint256 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], userEpoch); sumLqtyAllocated += lqtyAllocated; } - (uint88 totalLQTYAllocated,) = initiative.totalLQTYAllocatedByEpoch(currentEpoch); + (uint256 totalLQTYAllocated,) = initiative.totalLQTYAllocatedByEpoch(currentEpoch); eq( sumLqtyAllocated, totalLQTYAllocated, @@ -182,20 +183,20 @@ abstract contract BribeInitiativeProperties is BeforeAfter { } function property_sum_of_votes_in_bribes_match() public { - uint16 currentEpoch = governance.epoch(); + uint256 currentEpoch = governance.epoch(); // sum user allocations for an epoch // check that this matches the total allocation for the epoch - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); uint256 sumOfPower; - for (uint8 j; j < users.length; j++) { - (uint88 lqtyAllocated, uint120 userTS) = initiative.lqtyAllocatedByUserAtEpoch(users[j], currentEpoch); - sumOfPower += governance.lqtyToVotes(lqtyAllocated, userTS, uint32(block.timestamp)); + for (uint256 j; j < users.length; j++) { + (uint256 lqtyAllocated, uint256 userTS) = initiative.lqtyAllocatedByUserAtEpoch(users[j], currentEpoch); + sumOfPower += governance.lqtyToVotes(lqtyAllocated, userTS, uint256(block.timestamp)); } - (uint88 totalLQTYAllocated, uint120 totalTS) = initiative.totalLQTYAllocatedByEpoch(currentEpoch); + (uint256 totalLQTYAllocated, uint256 totalTS) = initiative.totalLQTYAllocatedByEpoch(currentEpoch); - uint256 totalRecordedPower = governance.lqtyToVotes(totalLQTYAllocated, totalTS, uint32(block.timestamp)); + uint256 totalRecordedPower = governance.lqtyToVotes(totalLQTYAllocated, totalTS, uint256(block.timestamp)); gte(totalRecordedPower, sumOfPower, "property_sum_of_votes_in_bribes_match"); } @@ -203,14 +204,14 @@ abstract contract BribeInitiativeProperties is BeforeAfter { function property_BI08() public { // users can only claim for epoch that has already passed - uint16 checkEpoch = governance.epoch() - 1; + uint256 checkEpoch = governance.epoch() - 1; // use lqtyAllocatedByUserAtEpoch to determine if a user is allocated for an epoch // use claimedBribeForInitiativeAtEpoch to determine if user has claimed bribe for an epoch (would require the value changing from false -> true) - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); - for (uint8 j; j < users.length; j++) { - (uint88 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], checkEpoch); + for (uint256 j; j < users.length; j++) { + (uint256 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], checkEpoch); // check that user had no lqtyAllocated for the epoch and therefore shouldn't be able to claim for it if (lqtyAllocated == 0) { @@ -231,12 +232,12 @@ abstract contract BribeInitiativeProperties is BeforeAfter { // BI-09: User can’t be allocated for future epoch function property_BI09() public { // get one past current epoch in governance - uint16 checkEpoch = governance.epoch() + 1; + uint256 checkEpoch = governance.epoch() + 1; // check if any user is allocated for the epoch - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); - for (uint8 j; j < users.length; j++) { - (uint88 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], checkEpoch); + for (uint256 j; j < users.length; j++) { + (uint256 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], checkEpoch); eq(lqtyAllocated, 0, "BI-09: User cannot be allocated for future epoch"); } @@ -245,14 +246,14 @@ abstract contract BribeInitiativeProperties is BeforeAfter { // BI-10: totalLQTYAllocatedByEpoch ≥ lqtyAllocatedByUserAtEpoch function property_BI10() public { - uint16 checkEpoch = governance.epoch(); + uint256 checkEpoch = governance.epoch(); // check each user allocation for the epoch against the total for the epoch - for (uint8 i; i < deployedInitiatives.length; i++) { + for (uint256 i; i < deployedInitiatives.length; i++) { IBribeInitiative initiative = IBribeInitiative(deployedInitiatives[i]); - for (uint8 j; j < users.length; j++) { - (uint88 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], checkEpoch); - (uint88 totalLQTYAllocated,) = initiative.totalLQTYAllocatedByEpoch(checkEpoch); + for (uint256 j; j < users.length; j++) { + (uint256 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(users[j], checkEpoch); + (uint256 totalLQTYAllocated,) = initiative.totalLQTYAllocatedByEpoch(checkEpoch); gte(totalLQTYAllocated, lqtyAllocated, "BI-10: totalLQTYAllocatedByEpoch >= lqtyAllocatedByUserAtEpoch"); } diff --git a/test/recon/properties/GovernanceProperties.sol b/test/recon/properties/GovernanceProperties.sol index 3cb8fda2..df12eb01 100644 --- a/test/recon/properties/GovernanceProperties.sol +++ b/test/recon/properties/GovernanceProperties.sol @@ -63,7 +63,7 @@ abstract contract GovernanceProperties is BeforeAfter { address userProxyAddress = governance.deriveUserProxyAddress(users[i]); uint256 stake = MockStakingV1(stakingV1).stakes(userProxyAddress); - (uint88 user_allocatedLQTY,) = governance.userStates(users[i]); + (,, uint256 user_allocatedLQTY,) = governance.userStates(users[i]); lte(user_allocatedLQTY, stake, "User can never allocated more than stake"); } } @@ -113,15 +113,12 @@ abstract contract GovernanceProperties is BeforeAfter { } function _getGlobalLQTYAndUserSum() internal returns (uint256, uint256) { - ( - uint88 totalCountedLQTY, - // uint32 after_user_countedVoteLQTYAverageTimestamp // TODO: How do we do this? - ) = governance.globalState(); + (uint256 totalCountedLQTY,) = governance.globalState(); uint256 totalUserCountedLQTY; for (uint256 i; i < users.length; i++) { // Only sum up user votes - (uint88 user_voteLQTY,) = _getAllUserAllocations(users[i], true); + (uint256 user_voteLQTY,) = _getAllUserAllocations(users[i], true); totalUserCountedLQTY += user_voteLQTY; } @@ -132,9 +129,9 @@ abstract contract GovernanceProperties is BeforeAfter { function property_ensure_user_alloc_cannot_dos() public { for (uint256 i; i < users.length; i++) { // Only sum up user votes - (uint88 user_voteLQTY,) = _getAllUserAllocations(users[i], false); + (uint256 user_voteLQTY,) = _getAllUserAllocations(users[i], false); - lte(user_voteLQTY, uint88(type(int88).max), "User can never allocate more than int88"); + lte(user_voteLQTY, uint256(type(int256).max), "User can never allocate more than int256"); } } @@ -147,14 +144,14 @@ abstract contract GovernanceProperties is BeforeAfter { uint256 totalInitiativesCountedVoteLQTY; uint256 totalInitiativesCountedVetoLQTY; for (uint256 i; i < deployedInitiatives.length; i++) { - (uint88 voteLQTY, uint88 vetoLQTY,,,) = governance.initiativeStates(deployedInitiatives[i]); + (uint256 voteLQTY, uint256 vetoLQTY,,,) = governance.initiativeStates(deployedInitiatives[i]); totalInitiativesCountedVoteLQTY += voteLQTY; totalInitiativesCountedVetoLQTY += vetoLQTY; } uint256 totalUserCountedLQTY; for (uint256 i; i < users.length; i++) { - (uint88 user_allocatedLQTY,) = governance.userStates(users[i]); + (,, uint256 user_allocatedLQTY,) = governance.userStates(users[i]); totalUserCountedLQTY += user_allocatedLQTY; } @@ -169,14 +166,14 @@ abstract contract GovernanceProperties is BeforeAfter { // For each user, for each initiative, allocation is correct function property_sum_of_user_initiative_allocations() public { for (uint256 i; i < deployedInitiatives.length; i++) { - (uint88 initiative_voteLQTY, uint88 initiative_vetoLQTY,,,) = + (uint256 initiative_voteLQTY, uint256 initiative_vetoLQTY,,,) = governance.initiativeStates(deployedInitiatives[i]); // Grab all users and sum up their participations uint256 totalUserVotes; uint256 totalUserVetos; for (uint256 j; j < users.length; j++) { - (uint88 vote_allocated, uint88 veto_allocated) = _getUserAllocation(users[j], deployedInitiatives[i]); + (uint256 vote_allocated, uint256 veto_allocated) = _getUserAllocation(users[j], deployedInitiatives[i]); totalUserVotes += vote_allocated; totalUserVetos += veto_allocated; } @@ -234,22 +231,18 @@ abstract contract GovernanceProperties is BeforeAfter { function _getUserVotesSumAndInitiativesVotes() internal returns (VotesSumAndInitiativeSum[] memory) { VotesSumAndInitiativeSum[] memory acc = new VotesSumAndInitiativeSum[](deployedInitiatives.length); for (uint256 i; i < deployedInitiatives.length; i++) { - uint240 userWeightAccumulatorForInitiative; + uint256 userWeightAccumulatorForInitiative; for (uint256 j; j < users.length; j++) { - (uint88 userVoteLQTY,,) = governance.lqtyAllocatedByUserToInitiative(users[j], deployedInitiatives[i]); - // TODO: double check that okay to use this average timestamp - (, uint120 averageStakingTimestamp) = governance.userStates(users[j]); + (uint256 userVoteLQTY, uint256 userVoteOffset,,,) = + governance.lqtyAllocatedByUserToInitiative(users[j], deployedInitiatives[i]); // add the weight calculated for each user's allocation to the accumulator - userWeightAccumulatorForInitiative += governance.lqtyToVotes( - userVoteLQTY, uint120(block.timestamp) * uint120(1e18), averageStakingTimestamp - ); + userWeightAccumulatorForInitiative += + governance.lqtyToVotes(userVoteLQTY, uint256(block.timestamp), userVoteOffset); } - (uint88 initiativeVoteLQTY,, uint120 initiativeAverageStakingTimestampVoteLQTY,,) = + (uint256 initiativeVoteLQTY, uint256 initiativeVoteOffset,,,) = governance.initiativeStates(deployedInitiatives[i]); - uint240 initiativeWeight = governance.lqtyToVotes( - initiativeVoteLQTY, uint120(block.timestamp) * uint120(1e18), initiativeAverageStakingTimestampVoteLQTY - ); + uint256 initiativeWeight = governance.lqtyToVotes(initiativeVoteLQTY, block.timestamp, initiativeVoteOffset); acc[i].userSum = userWeightAccumulatorForInitiative; acc[i].initiativeWeight = initiativeWeight; @@ -261,9 +254,9 @@ abstract contract GovernanceProperties is BeforeAfter { function property_allocations_are_never_dangerously_high() public { for (uint256 i; i < deployedInitiatives.length; i++) { for (uint256 j; j < users.length; j++) { - (uint88 vote_allocated, uint88 veto_allocated) = _getUserAllocation(users[j], deployedInitiatives[i]); - lte(vote_allocated, uint88(type(int88).max), "Vote is never above int88.max"); - lte(veto_allocated, uint88(type(int88).max), "Veto is Never above int88.max"); + (uint256 vote_allocated, uint256 veto_allocated) = _getUserAllocation(users[j], deployedInitiatives[i]); + lte(vote_allocated, uint256(type(int256).max), "Vote is never above int256.max"); + lte(veto_allocated, uint256(type(int256).max), "Veto is Never above int256.max"); } } } @@ -298,7 +291,7 @@ abstract contract GovernanceProperties is BeforeAfter { } function _getInitiativeStateAndGlobalState() internal returns (uint256, uint256, uint256, uint256) { - (uint88 totalCountedLQTY, uint120 global_countedVoteLQTYAverageTimestamp) = governance.globalState(); + (uint256 totalCountedLQTY, uint256 global_countedVoteOffset) = governance.globalState(); // Can sum via projection I guess @@ -307,12 +300,8 @@ abstract contract GovernanceProperties is BeforeAfter { uint256 allocatedLQTYSum; uint256 votedPowerSum; for (uint256 i; i < deployedInitiatives.length; i++) { - ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(deployedInitiatives[i]); + (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset,) = + governance.initiativeStates(deployedInitiatives[i]); // Conditional, only if not DISABLED (IGovernance.InitiativeStatus status,,) = governance.getInitiativeState(deployedInitiatives[i]); @@ -320,19 +309,11 @@ abstract contract GovernanceProperties is BeforeAfter { if (status != IGovernance.InitiativeStatus.DISABLED) { allocatedLQTYSum += voteLQTY; // Sum via projection - votedPowerSum += governance.lqtyToVotes( - voteLQTY, - uint120(block.timestamp) * uint120(governance.TIMESTAMP_PRECISION()), - averageStakingTimestampVoteLQTY - ); + votedPowerSum += governance.lqtyToVotes(voteLQTY, block.timestamp, voteOffset); } } - uint256 govPower = governance.lqtyToVotes( - totalCountedLQTY, - uint120(block.timestamp) * uint120(governance.TIMESTAMP_PRECISION()), - global_countedVoteLQTYAverageTimestamp - ); + uint256 govPower = governance.lqtyToVotes(totalCountedLQTY, block.timestamp, global_countedVoteOffset); return (allocatedLQTYSum, totalCountedLQTY, votedPowerSum, govPower); } @@ -456,14 +437,17 @@ abstract contract GovernanceProperties is BeforeAfter { function _getUserAllocation(address theUser, address initiative) internal view - returns (uint88 votes, uint88 vetos) + returns (uint256 votes, uint256 vetos) { - (votes, vetos,) = governance.lqtyAllocatedByUserToInitiative(theUser, initiative); + (votes, vetos,,,) = governance.lqtyAllocatedByUserToInitiative(theUser, initiative); } - function _getAllUserAllocations(address theUser, bool skipDisabled) internal returns (uint88 votes, uint88 vetos) { + function _getAllUserAllocations(address theUser, bool skipDisabled) + internal + returns (uint256 votes, uint256 vetos) + { for (uint256 i; i < deployedInitiatives.length; i++) { - (uint88 allocVotes, uint88 allocVetos,) = + (uint256 allocVotes, uint256 allocVetos,,,) = governance.lqtyAllocatedByUserToInitiative(theUser, deployedInitiatives[i]); if (skipDisabled) { (IGovernance.InitiativeStatus status,,) = governance.getInitiativeState(deployedInitiatives[i]); @@ -483,9 +467,9 @@ abstract contract GovernanceProperties is BeforeAfter { function property_alloc_deposit_reset_is_idempotent( uint8 initiativesIndex, - uint96 deltaLQTYVotes, - uint96 deltaLQTYVetos, - uint88 lqtyAmount + uint256 deltaLQTYVotes, + uint256 deltaLQTYVetos, + uint256 lqtyAmount ) public withChecks { address targetInitiative = _getDeployedInitiative(initiativesIndex); @@ -493,69 +477,60 @@ abstract contract GovernanceProperties is BeforeAfter { // TODO: prob unnecessary // Cause we always reset anyway { - int88[] memory zeroes = new int88[](deployedInitiatives.length); + int256[] memory zeroes = new int256[](deployedInitiatives.length); governance.allocateLQTY(deployedInitiatives, deployedInitiatives, zeroes, zeroes); } // GET state and initiative data before allocation - (uint88 totalCountedLQTY, uint120 user_countedVoteLQTYAverageTimestamp) = governance.globalState(); - ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(targetInitiative); + (uint256 totalCountedLQTY, uint256 user_countedVoteOffset) = governance.globalState(); + (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset,) = + governance.initiativeStates(targetInitiative); // Allocate { - uint96 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); + uint256 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); address[] memory initiatives = new address[](1); initiatives[0] = targetInitiative; - int88[] memory deltaLQTYVotesArray = new int88[](1); - deltaLQTYVotesArray[0] = int88(uint88(deltaLQTYVotes % stakedAmount)); - int88[] memory deltaLQTYVetosArray = new int88[](1); - deltaLQTYVetosArray[0] = int88(uint88(deltaLQTYVetos % stakedAmount)); + int256[] memory deltaLQTYVotesArray = new int256[](1); + deltaLQTYVotesArray[0] = int256(uint256(deltaLQTYVotes % stakedAmount)); + int256[] memory deltaLQTYVetosArray = new int256[](1); + deltaLQTYVetosArray[0] = int256(uint256(deltaLQTYVetos % stakedAmount)); governance.allocateLQTY(deployedInitiatives, initiatives, deltaLQTYVotesArray, deltaLQTYVetosArray); } // Deposit (Changes total LQTY an hopefully also changes ts) { - (, uint120 averageStakingTimestamp1) = governance.userStates(user); + (, uint256 unallocatedOffset1,,) = governance.userStates(user); - lqtyAmount = uint88(lqtyAmount % lqty.balanceOf(user)); + lqtyAmount = uint256(lqtyAmount % lqty.balanceOf(user)); governance.depositLQTY(lqtyAmount); - (, uint120 averageStakingTimestamp2) = governance.userStates(user); + (, uint256 unallocatedOffset2,,) = governance.userStates(user); - require(averageStakingTimestamp2 > averageStakingTimestamp1, "Must have changed"); + require(unallocatedOffset2 > unallocatedOffset1, "Must have changed"); } // REMOVE STUFF to remove the user data { - int88[] memory zeroes = new int88[](deployedInitiatives.length); + int256[] memory zeroes = new int256[](deployedInitiatives.length); governance.allocateLQTY(deployedInitiatives, deployedInitiatives, zeroes, zeroes); } // Check total allocation and initiative allocation { - (uint88 after_totalCountedLQTY, uint120 after_user_countedVoteLQTYAverageTimestamp) = - governance.globalState(); - ( - uint88 after_voteLQTY, - uint88 after_vetoLQTY, - uint120 after_averageStakingTimestampVoteLQTY, - uint120 after_averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(targetInitiative); + (uint256 after_totalCountedLQTY, uint256 after_user_countedVoteOffset) = governance.globalState(); + (uint256 after_voteLQTY, uint256 after_voteOffset, uint256 after_vetoLQTY, uint256 after_vetoOffset,) = + governance.initiativeStates(targetInitiative); eq(voteLQTY, after_voteLQTY, "Same vote"); eq(vetoLQTY, after_vetoLQTY, "Same veto"); - eq(averageStakingTimestampVoteLQTY, after_averageStakingTimestampVoteLQTY, "Same ts vote"); - eq(averageStakingTimestampVetoLQTY, after_averageStakingTimestampVetoLQTY, "Same ts veto"); + eq(voteOffset, after_voteOffset, "Same vote offset"); + eq(vetoOffset, after_vetoOffset, "Same veto offset"); eq(totalCountedLQTY, after_totalCountedLQTY, "Same total LQTY"); - eq(user_countedVoteLQTYAverageTimestamp, after_user_countedVoteLQTYAverageTimestamp, "Same total ts"); + eq(user_countedVoteOffset, after_user_countedVoteOffset, "Same total ts"); } } } diff --git a/test/recon/properties/RevertProperties.sol b/test/recon/properties/RevertProperties.sol index 6d73d5e6..e7d46ec3 100644 --- a/test/recon/properties/RevertProperties.sol +++ b/test/recon/properties/RevertProperties.sol @@ -9,13 +9,10 @@ import {IBribeInitiative} from "src/interfaces/IBribeInitiative.sol"; // The are view functions that should never revert abstract contract RevertProperties is BeforeAfter { function property_computingGlobalPowerNeverReverts() public { - (uint88 totalCountedLQTY, uint120 global_countedVoteLQTYAverageTimestamp) = governance.globalState(); + (uint256 totalCountedLQTY, uint256 global_countedVoteOffset) = governance.globalState(); - try governance.lqtyToVotes( - totalCountedLQTY, - uint120(block.timestamp) * uint120(governance.TIMESTAMP_PRECISION()), - global_countedVoteLQTYAverageTimestamp - ) {} catch { + try governance.lqtyToVotes(totalCountedLQTY, block.timestamp, global_countedVoteOffset) {} + catch { t(false, "Should never revert"); } } @@ -23,21 +20,13 @@ abstract contract RevertProperties is BeforeAfter { function property_summingInitiativesPowerNeverReverts() public { uint256 votedPowerSum; for (uint256 i; i < deployedInitiatives.length; i++) { - ( - uint88 voteLQTY, - uint88 vetoLQTY, - uint120 averageStakingTimestampVoteLQTY, - uint120 averageStakingTimestampVetoLQTY, - ) = governance.initiativeStates(deployedInitiatives[i]); + (uint256 voteLQTY, uint256 voteOffset, uint256 vetoLQTY, uint256 vetoOffset,) = + governance.initiativeStates(deployedInitiatives[i]); // Sum via projection uint256 prevSum = votedPowerSum; unchecked { - try governance.lqtyToVotes( - voteLQTY, - uint120(block.timestamp) * uint120(governance.TIMESTAMP_PRECISION()), - averageStakingTimestampVoteLQTY - ) returns (uint208 res) { + try governance.lqtyToVotes(voteLQTY, block.timestamp, voteOffset) returns (uint256 res) { votedPowerSum += res; } catch { t(false, "Should never revert"); diff --git a/test/recon/properties/SynchProperties.sol b/test/recon/properties/SynchProperties.sol index 1414c64c..2cbc62e5 100644 --- a/test/recon/properties/SynchProperties.sol +++ b/test/recon/properties/SynchProperties.sol @@ -8,34 +8,33 @@ import {IBribeInitiative} from "src/interfaces/IBribeInitiative.sol"; abstract contract SynchProperties is BeforeAfter { // Properties that ensure that the states are synched - // Go through each initiative // Go through each user - // Ensure that a non zero vote uses the user latest TS + // Ensure that a non zero vote uses the user latest offset // This ensures that the math is correct in removal and addition - function property_initiative_ts_matches_user_when_non_zero() public { + // TODO: check whether this property really holds for offsets, since they are sums + function property_initiative_offset_matches_user_when_non_zero() public { // For all strategies for (uint256 i; i < deployedInitiatives.length; i++) { for (uint256 j; j < users.length; j++) { - (uint88 votes,, uint16 epoch) = + (uint256 votes,,,, uint256 epoch) = governance.lqtyAllocatedByUserToInitiative(users[j], deployedInitiatives[i]); // Grab epoch from initiative - (uint88 lqtyAllocatedByUserAtEpoch, uint120 ts) = + (uint256 lqtyAllocatedByUserAtEpoch, uint256 allocOffset) = IBribeInitiative(deployedInitiatives[i]).lqtyAllocatedByUserAtEpoch(users[j], epoch); - // Check that TS matches (only for votes) + // Check that votes match eq(lqtyAllocatedByUserAtEpoch, votes, "Votes must match at all times"); if (votes != 0) { // if we're voting and the votes are different from 0 - // then we check user TS - (, uint120 averageStakingTimestamp) = governance.userStates(users[j]); + // then we check user offset + (,,, uint256 allocatedOffset) = governance.userStates(users[j]); - eq(averageStakingTimestamp, ts, "Timestamp must be most recent when it's non zero"); + eq(allocatedOffset, allocOffset, "Offsets must match"); } else { - // NOTE: If votes are zero the TS is passed, but it is not a useful value - // This is left here as a note for the reviewer + // NOTE: If votes are zero the offset is zero } } } diff --git a/test/recon/properties/TsProperties.sol b/test/recon/properties/TsProperties.sol index 1fa84773..cd56e113 100644 --- a/test/recon/properties/TsProperties.sol +++ b/test/recon/properties/TsProperties.sol @@ -9,17 +9,17 @@ import {IBribeInitiative} from "src/interfaces/IBribeInitiative.sol"; abstract contract TsProperties is BeforeAfter { // Properties that ensure that a user TS is somewhat sound - function property_user_ts_is_always_greater_than_start() public { + function property_user_offset_is_always_greater_than_start() public { for (uint256 i; i < users.length; i++) { - (uint88 user_allocatedLQTY, uint120 userTs) = governance.userStates(users[i]); + (,, uint256 user_allocatedLQTY, uint256 userAllocatedOffset) = governance.userStates(users[i]); if (user_allocatedLQTY > 0) { - gte(userTs, magnifiedStartTS, "User ts must always be GTE than start"); + gte(userAllocatedOffset, magnifiedStartTS, "User ts must always be GTE than start"); } } } - function property_global_ts_is_always_greater_than_start() public { - (uint88 totalCountedLQTY, uint120 globalTs) = governance.globalState(); + function property_global_offset_is_always_greater_than_start() public { + (uint256 totalCountedLQTY, uint256 globalTs) = governance.globalState(); if (totalCountedLQTY > 0) { gte(globalTs, magnifiedStartTS, "Global ts must always be GTE than start"); diff --git a/test/recon/targets/BribeInitiativeTargets.sol b/test/recon/targets/BribeInitiativeTargets.sol index 694c7e0e..63ef2201 100644 --- a/test/recon/targets/BribeInitiativeTargets.sol +++ b/test/recon/targets/BribeInitiativeTargets.sol @@ -15,24 +15,24 @@ abstract contract BribeInitiativeTargets is Test, BaseTargetFunctions, Propertie // NOTE: initiatives that get called here are deployed but not necessarily registered - function initiative_depositBribe(uint128 boldAmount, uint128 bribeTokenAmount, uint16 epoch, uint8 initiativeIndex) + function initiative_depositBribe(uint256 boldAmount, uint256 bribeTokenAmount, uint256 epoch, uint8 initiativeIndex) public withChecks { IBribeInitiative initiative = IBribeInitiative(_getDeployedInitiative(initiativeIndex)); // clamp token amounts using user balance - boldAmount = uint128(boldAmount % lusd.balanceOf(user)); - bribeTokenAmount = uint128(bribeTokenAmount % lqty.balanceOf(user)); + boldAmount = uint256(boldAmount % lusd.balanceOf(user)); + bribeTokenAmount = uint256(bribeTokenAmount % lqty.balanceOf(user)); lusd.approve(address(initiative), boldAmount); lqty.approve(address(initiative), bribeTokenAmount); - (uint128 boldAmountB4, uint128 bribeTokenAmountB4) = IBribeInitiative(initiative).bribeByEpoch(epoch); + (uint256 boldAmountB4, uint256 bribeTokenAmountB4) = IBribeInitiative(initiative).bribeByEpoch(epoch); initiative.depositBribe(boldAmount, bribeTokenAmount, epoch); - (uint128 boldAmountAfter, uint128 bribeTokenAmountAfter) = IBribeInitiative(initiative).bribeByEpoch(epoch); + (uint256 boldAmountAfter, uint256 bribeTokenAmountAfter) = IBribeInitiative(initiative).bribeByEpoch(epoch); eq(boldAmountB4 + boldAmount, boldAmountAfter, "Bold amount tracking is sound"); eq(bribeTokenAmountB4 + bribeTokenAmount, bribeTokenAmountAfter, "Bribe amount tracking is sound"); @@ -40,10 +40,10 @@ abstract contract BribeInitiativeTargets is Test, BaseTargetFunctions, Propertie // Canaries are no longer necessary // function canary_bribeWasThere(uint8 initiativeIndex) public { - // uint16 epoch = governance.epoch(); + // uint256 epoch = governance.epoch(); // IBribeInitiative initiative = IBribeInitiative(_getDeployedInitiative(initiativeIndex)); - // (uint128 boldAmount, uint128 bribeTokenAmount) = initiative.bribeByEpoch(epoch); + // (uint256 boldAmount, uint256 bribeTokenAmount) = initiative.bribeByEpoch(epoch); // t(boldAmount == 0 && bribeTokenAmount == 0, "A bribe was found"); // } @@ -55,15 +55,15 @@ abstract contract BribeInitiativeTargets is Test, BaseTargetFunctions, Propertie function clamped_claimBribes(uint8 initiativeIndex) public { IBribeInitiative initiative = IBribeInitiative(_getDeployedInitiative(initiativeIndex)); - uint16 userEpoch = initiative.getMostRecentUserEpoch(user); - uint16 stateEpoch = initiative.getMostRecentTotalEpoch(); + uint256 userEpoch = initiative.getMostRecentUserEpoch(user); + uint256 stateEpoch = initiative.getMostRecentTotalEpoch(); initiative_claimBribes(governance.epoch() - 1, userEpoch, stateEpoch, initiativeIndex); } function initiative_claimBribes( - uint16 epoch, - uint16 prevAllocationEpoch, - uint16 prevTotalAllocationEpoch, + uint256 epoch, + uint256 prevAllocationEpoch, + uint256 prevTotalAllocationEpoch, uint8 initiativeIndex ) public withChecks { IBribeInitiative initiative = IBribeInitiative(_getDeployedInitiative(initiativeIndex)); @@ -92,14 +92,14 @@ abstract contract BribeInitiativeTargets is Test, BaseTargetFunctions, Propertie // NOTE: This is not a full check, but a sufficient check for some cases /// Specifically we may have to look at the user last epoch /// And see if we need to port over that balance from then - (uint88 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(user, epoch); + (uint256 lqtyAllocated,) = initiative.lqtyAllocatedByUserAtEpoch(user, epoch); bool claimedBribe = initiative.claimedBribeAtEpoch(user, epoch); if (initiative.getMostRecentTotalEpoch() != prevTotalAllocationEpoch) { return; // We are in a edge case } // Check if there are bribes - (uint128 boldAmount, uint128 bribeTokenAmount) = initiative.bribeByEpoch(epoch); + (uint256 boldAmount, uint256 bribeTokenAmount) = initiative.bribeByEpoch(epoch); bool bribeWasThere; if (boldAmount != 0 || bribeTokenAmount != 0) { bribeWasThere = true; diff --git a/test/recon/targets/GovernanceTargets.sol b/test/recon/targets/GovernanceTargets.sol index d73d4e5d..e5eb583d 100644 --- a/test/recon/targets/GovernanceTargets.sol +++ b/test/recon/targets/GovernanceTargets.sol @@ -20,14 +20,14 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { // clamps to a single initiative to ensure coverage in case both haven't been registered yet function governance_allocateLQTY_clamped_single_initiative( uint8 initiativesIndex, - uint96 deltaLQTYVotes, - uint96 deltaLQTYVetos + uint256 deltaLQTYVotes, + uint256 deltaLQTYVetos ) public withChecks { - uint96 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); // clamp using the user's staked balance + uint256 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); // clamp using the user's staked balance address initiative = _getDeployedInitiative(initiativesIndex); address[] memory initiativesToReset; - (uint88 currentVote, uint88 currentVeto,) = + (uint256 currentVote,, uint256 currentVeto,,) = governance.lqtyAllocatedByUserToInitiative(user, address(initiative)); if (currentVote != 0 || currentVeto != 0) { initiativesToReset = new address[](1); @@ -35,15 +35,15 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { } address[] memory initiatives = new address[](1); initiatives[0] = initiative; - int88[] memory deltaLQTYVotesArray = new int88[](1); - deltaLQTYVotesArray[0] = int88(uint88(deltaLQTYVotes % (stakedAmount + 1))); - int88[] memory deltaLQTYVetosArray = new int88[](1); - deltaLQTYVetosArray[0] = int88(uint88(deltaLQTYVetos % (stakedAmount + 1))); + int256[] memory deltaLQTYVotesArray = new int256[](1); + deltaLQTYVotesArray[0] = int256(uint256(deltaLQTYVotes % (stakedAmount + 1))); + int256[] memory deltaLQTYVetosArray = new int256[](1); + deltaLQTYVetosArray[0] = int256(uint256(deltaLQTYVetos % (stakedAmount + 1))); // User B4 - // (uint88 b4_user_allocatedLQTY,) = governance.userStates(user); // TODO + // (uint256 b4_user_allocatedLQTY,) = governance.userStates(user); // TODO // StateB4 - (uint88 b4_global_allocatedLQTY,) = governance.globalState(); + (uint256 b4_global_allocatedLQTY,) = governance.globalState(); (IGovernance.InitiativeStatus status,,) = governance.getInitiativeState(initiatives[0]); @@ -61,8 +61,8 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { // If Initiative was anything else // Global state and user state accounting should change - // (uint88 after_user_allocatedLQTY,) = governance.userStates(user); // TODO - (uint88 after_global_allocatedLQTY,) = governance.globalState(); + // (uint256 after_user_allocatedLQTY,) = governance.userStates(user); // TODO + (uint256 after_global_allocatedLQTY,) = governance.globalState(); if (status == IGovernance.InitiativeStatus.DISABLED) { // NOTE: It could be 0 @@ -72,14 +72,14 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { function governance_allocateLQTY_clamped_single_initiative_2nd_user( uint8 initiativesIndex, - uint96 deltaLQTYVotes, - uint96 deltaLQTYVetos + uint256 deltaLQTYVotes, + uint256 deltaLQTYVetos ) public withChecks { - uint96 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user2)).staked(); // clamp using the user's staked balance + uint256 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user2)).staked(); // clamp using the user's staked balance address initiative = _getDeployedInitiative(initiativesIndex); address[] memory initiativesToReset; - (uint88 currentVote, uint88 currentVeto,) = + (uint256 currentVote,, uint256 currentVeto,,) = governance.lqtyAllocatedByUserToInitiative(user2, address(initiative)); if (currentVote != 0 || currentVeto != 0) { initiativesToReset = new address[](1); @@ -87,10 +87,10 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { } address[] memory initiatives = new address[](1); initiatives[0] = initiative; - int88[] memory deltaLQTYVotesArray = new int88[](1); - deltaLQTYVotesArray[0] = int88(uint88(deltaLQTYVotes % stakedAmount)); - int88[] memory deltaLQTYVetosArray = new int88[](1); - deltaLQTYVetosArray[0] = int88(uint88(deltaLQTYVetos % stakedAmount)); + int256[] memory deltaLQTYVotesArray = new int256[](1); + deltaLQTYVotesArray[0] = int256(uint256(deltaLQTYVotes % stakedAmount)); + int256[] memory deltaLQTYVetosArray = new int256[](1); + deltaLQTYVetosArray[0] = int256(uint256(deltaLQTYVetos % stakedAmount)); require(stakedAmount > 0, "0 stake"); @@ -116,47 +116,47 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { t(false, "must never revert"); } - (uint88 user_allocatedLQTY,) = governance.userStates(user); + (,, uint256 user_allocatedLQTY,) = governance.userStates(user); eq(user_allocatedLQTY, 0, "User has 0 allocated on a reset"); } - function depositTsIsRational(uint88 lqtyAmount) public withChecks { - uint88 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); // clamp using the user's staked balance + function offsetIsRational(uint256 lqtyAmount) public withChecks { + uint256 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); // clamp using the user's staked balance // Deposit on zero if (stakedAmount == 0) { - lqtyAmount = uint88(lqtyAmount % lqty.balanceOf(user)); + lqtyAmount = uint256(lqtyAmount % lqty.balanceOf(user)); governance.depositLQTY(lqtyAmount); - // assert that user TS is now * WAD - (, uint120 ts) = governance.userStates(user); - eq(ts, block.timestamp * 1e26, "User TS is scaled by WAD"); + // assert that user's offset TS is now * deposited LQTY + (, uint256 offset,,) = governance.userStates(user); + eq(offset, block.timestamp * lqtyAmount, "User unallocated offset is now * lqty deposited"); } else { // Make sure the TS can never bo before itself - (, uint120 ts_b4) = governance.userStates(user); - lqtyAmount = uint88(lqtyAmount % lqty.balanceOf(user)); + (, uint256 offset_b4,,) = governance.userStates(user); + lqtyAmount = uint256(lqtyAmount % lqty.balanceOf(user)); governance.depositLQTY(lqtyAmount); - (, uint120 ts_after) = governance.userStates(user); + (, uint256 offset_after,,) = governance.userStates(user); - gte(ts_after, ts_b4, "User TS must always increase"); + gte(offset_after, offset_b4, "User unallocated offset must always increase"); } } - function depositMustFailOnNonZeroAlloc(uint88 lqtyAmount) public withChecks { - (uint88 user_allocatedLQTY,) = governance.userStates(user); + function depositMustFailOnNonZeroAlloc(uint256 lqtyAmount) public withChecks { + (uint256 user_allocatedLQTY,,,) = governance.userStates(user); require(user_allocatedLQTY != 0, "0 alloc"); - lqtyAmount = uint88(lqtyAmount % lqty.balanceOf(user)); + lqtyAmount = uint256(lqtyAmount % lqty.balanceOf(user)); try governance.depositLQTY(lqtyAmount) { t(false, "Deposit Must always revert when user is not reset"); } catch {} } - function withdrwaMustFailOnNonZeroAcc(uint88 _lqtyAmount) public withChecks { - (uint88 user_allocatedLQTY,) = governance.userStates(user); + function withdrwaMustFailOnNonZeroAcc(uint256 _lqtyAmount) public withChecks { + (uint256 user_allocatedLQTY,,,) = governance.userStates(user); require(user_allocatedLQTY != 0); @@ -169,7 +169,7 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { // For every initiative, make ghost values and ensure they match // For all operations, you also need to add the VESTED AMT? - function governance_allocateLQTY(int88[] memory _deltaLQTYVotes, int88[] memory _deltaLQTYVetos) + function governance_allocateLQTY(int256[] memory _deltaLQTYVotes, int256[] memory _deltaLQTYVetos) public withChecks { @@ -217,25 +217,25 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { governance.deployUserProxy(); } - function governance_depositLQTY(uint88 lqtyAmount) public withChecks { - lqtyAmount = uint88(lqtyAmount % lqty.balanceOf(user)); + function governance_depositLQTY(uint256 lqtyAmount) public withChecks { + lqtyAmount = uint256(lqtyAmount % lqty.balanceOf(user)); governance.depositLQTY(lqtyAmount); } - function governance_depositLQTY_2(uint88 lqtyAmount) public withChecks { + function governance_depositLQTY_2(uint256 lqtyAmount) public withChecks { // Deploy and approve since we don't do it in constructor vm.prank(user2); try governance.deployUserProxy() returns (address proxy) { vm.prank(user2); - lqty.approve(proxy, type(uint88).max); + lqty.approve(proxy, type(uint256).max); } catch {} - lqtyAmount = uint88(lqtyAmount % lqty.balanceOf(user2)); + lqtyAmount = uint256(lqtyAmount % lqty.balanceOf(user2)); vm.prank(user2); governance.depositLQTY(lqtyAmount); } - function governance_depositLQTYViaPermit(uint88 _lqtyAmount) public withChecks { + function governance_depositLQTYViaPermit(uint256 _lqtyAmount) public withChecks { // Get the current block timestamp for the deadline uint256 deadline = block.timestamp + 1 hours; @@ -273,12 +273,12 @@ abstract contract GovernanceTargets is BaseTargetFunctions, Properties { governance.unregisterInitiative(initiative); } - function governance_withdrawLQTY(uint88 _lqtyAmount) public withChecks { + function governance_withdrawLQTY(uint256 _lqtyAmount) public withChecks { governance.withdrawLQTY(_lqtyAmount); } - function governance_withdrawLQTY_shouldRevertWhenClamped(uint88 _lqtyAmount) public withChecks { - uint88 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); // clamp using the user's staked balance + function governance_withdrawLQTY_shouldRevertWhenClamped(uint256 _lqtyAmount) public withChecks { + uint256 stakedAmount = IUserProxy(governance.deriveUserProxyAddress(user)).staked(); // clamp using the user's staked balance // Ensure we have 0 votes try governance.resetAllocations(deployedInitiatives, true) {} diff --git a/test/recon/trophies/SecondTrophiesToFoundry.sol b/test/recon/trophies/SecondTrophiesToFoundry.sol index c2bac8ba..b7c9d45c 100644 --- a/test/recon/trophies/SecondTrophiesToFoundry.sol +++ b/test/recon/trophies/SecondTrophiesToFoundry.sol @@ -224,7 +224,6 @@ contract SecondTrophiesToFoundry is Test, TargetFunctions, FoundryAsserts { console.log("snapshot.votes", snapshot.votes); console.log("state.countedVoteLQTY", state.countedVoteLQTY); - console.log("state.countedVoteLQTYAverageTimestamp", state.countedVoteLQTYAverageTimestamp); for (uint256 i; i < deployedInitiatives.length; i++) { ( @@ -233,9 +232,6 @@ contract SecondTrophiesToFoundry is Test, TargetFunctions, FoundryAsserts { ) = governance.getInitiativeSnapshotAndState(deployedInitiatives[i]); console.log("initiativeState.voteLQTY", initiativeState.voteLQTY); - console.log( - "initiativeState.averageStakingTimestampVoteLQTY", initiativeState.averageStakingTimestampVoteLQTY - ); assertEq(snapshot.forEpoch, initiativeSnapshot.forEpoch, "No desynch"); console.log("initiativeSnapshot.votes", initiativeSnapshot.votes); diff --git a/test/recon/trophies/TrophiesToFoundry.sol b/test/recon/trophies/TrophiesToFoundry.sol index c26a8632..ca8382c1 100644 --- a/test/recon/trophies/TrophiesToFoundry.sol +++ b/test/recon/trophies/TrophiesToFoundry.sol @@ -34,14 +34,14 @@ contract TrophiesToFoundry is Test, TargetFunctions, FoundryAsserts { // uint256 state = _getInitiativeStatus(_getDeployedInitiative(0)); // assertEq(state, 5, "Should not be this tbh"); // // check_unregisterable_consistecy(0); - // uint16 epoch = _getLastEpochClaim(_getDeployedInitiative(0)); + // uint256 epoch = _getLastEpochClaim(_getDeployedInitiative(0)); // console.log(epoch + governance.UNREGISTRATION_AFTER_EPOCHS() < governance.epoch() - 1); // vm.warp(block.timestamp + governance.EPOCH_DURATION()); // uint256 newState = _getInitiativeStatus(_getDeployedInitiative(0)); - // uint16 lastEpochClaim = _getLastEpochClaim(_getDeployedInitiative(0)); + // uint256 lastEpochClaim = _getLastEpochClaim(_getDeployedInitiative(0)); // console.log("governance.UNREGISTRATION_AFTER_EPOCHS()", governance.UNREGISTRATION_AFTER_EPOCHS()); // console.log("governance.epoch()", governance.epoch()); @@ -54,8 +54,8 @@ contract TrophiesToFoundry is Test, TargetFunctions, FoundryAsserts { // assertEq(newState, state, "??"); // } - function _getLastEpochClaim(address _initiative) internal returns (uint16) { - (, uint16 epoch,) = governance.getInitiativeState(_initiative); + function _getLastEpochClaim(address _initiative) internal returns (uint256) { + (, uint256 epoch,) = governance.getInitiativeState(_initiative); return epoch; } }