diff --git a/src/BribeInitiative.sol b/src/BribeInitiative.sol index b115c23..11a4755 100644 --- a/src/BribeInitiative.sol +++ b/src/BribeInitiative.sol @@ -9,11 +9,15 @@ import {IInitiative} from "./interfaces/IInitiative.sol"; import {IBribeInitiative} from "./interfaces/IBribeInitiative.sol"; import {DoubleLinkedList} from "./utils/DoubleLinkedList.sol"; +import {_lqtyToVotes} from "./utils/VotingPower.sol"; contract BribeInitiative is IInitiative, IBribeInitiative { using SafeERC20 for IERC20; using DoubleLinkedList for DoubleLinkedList.List; + uint256 internal immutable EPOCH_START; + uint256 internal immutable EPOCH_DURATION; + /// @inheritdoc IBribeInitiative IGovernance public immutable governance; /// @inheritdoc IBribeInitiative @@ -37,6 +41,9 @@ contract BribeInitiative is IInitiative, IBribeInitiative { governance = IGovernance(_governance); bold = IERC20(_bold); bribeToken = IERC20(_bribeToken); + + EPOCH_START = governance.EPOCH_START(); + EPOCH_DURATION = governance.EPOCH_DURATION(); } modifier onlyGovernance() { @@ -46,12 +53,15 @@ contract BribeInitiative is IInitiative, IBribeInitiative { /// @inheritdoc IBribeInitiative function totalLQTYAllocatedByEpoch(uint256 _epoch) external view returns (uint256, uint256) { - return _loadTotalLQTYAllocation(_epoch); + return (totalLQTYAllocationByEpoch.items[_epoch].lqty, totalLQTYAllocationByEpoch.items[_epoch].offset); } /// @inheritdoc IBribeInitiative function lqtyAllocatedByUserAtEpoch(address _user, uint256 _epoch) external view returns (uint256, uint256) { - return _loadLQTYAllocation(_user, _epoch); + return ( + lqtyAllocationByUserAtEpoch[_user].items[_epoch].lqty, + lqtyAllocationByUserAtEpoch[_user].items[_epoch].offset + ); } /// @inheritdoc IBribeInitiative @@ -59,10 +69,8 @@ contract BribeInitiative is IInitiative, IBribeInitiative { uint256 epoch = governance.epoch(); require(_epoch >= epoch, "BribeInitiative: now-or-future-epochs"); - Bribe memory bribe = bribeByEpoch[_epoch]; - bribe.boldAmount += _boldAmount; - bribe.bribeTokenAmount += _bribeTokenAmount; - bribeByEpoch[_epoch] = bribe; + bribeByEpoch[_epoch].remainingBoldAmount += _boldAmount; + bribeByEpoch[_epoch].remainingBribeTokenAmount += _bribeTokenAmount; emit DepositBribe(msg.sender, _boldAmount, _bribeTokenAmount, _epoch); @@ -80,7 +88,7 @@ contract BribeInitiative is IInitiative, IBribeInitiative { require(!claimedBribeAtEpoch[_user][_epoch], "BribeInitiative: already-claimed"); Bribe memory bribe = bribeByEpoch[_epoch]; - require(bribe.boldAmount != 0 || bribe.bribeTokenAmount != 0, "BribeInitiative: no-bribe"); + require(bribe.remainingBoldAmount != 0 || bribe.remainingBribeTokenAmount != 0, "BribeInitiative: no-bribe"); DoubleLinkedList.Item memory lqtyAllocation = lqtyAllocationByUserAtEpoch[_user].getItem(_prevLQTYAllocationEpoch); @@ -98,18 +106,25 @@ contract BribeInitiative is IInitiative, IBribeInitiative { ); require(totalLQTYAllocation.lqty > 0, "BribeInitiative: total-lqty-allocation-zero"); + require(lqtyAllocation.lqty > 0, "BribeInitiative: lqty-allocation-zero"); - uint256 epochEnd = governance.EPOCH_START() + _epoch * governance.EPOCH_DURATION(); + // `Governance` guarantees that `votes` evaluates to 0 or greater for each initiative at the time of allocation. + // Since the last possible moment to allocate within this epoch is 1 second before `epochEnd`, we have that: + // - `lqtyAllocation.lqty > 0` implies `votes > 0` + // - `totalLQTYAllocation.lqty > 0` implies `totalVotes > 0` - uint256 totalVotes = governance.lqtyToVotes(totalLQTYAllocation.lqty, epochEnd, totalLQTYAllocation.offset); - if (totalVotes != 0) { - require(lqtyAllocation.lqty > 0, "BribeInitiative: lqty-allocation-zero"); + uint256 epochEnd = EPOCH_START + _epoch * EPOCH_DURATION; + uint256 totalVotes = _lqtyToVotes(totalLQTYAllocation.lqty, epochEnd, totalLQTYAllocation.offset); + uint256 votes = _lqtyToVotes(lqtyAllocation.lqty, epochEnd, lqtyAllocation.offset); + uint256 remainingVotes = totalVotes - bribe.claimedVotes; - uint256 votes = governance.lqtyToVotes(lqtyAllocation.lqty, epochEnd, lqtyAllocation.offset); - boldAmount = bribe.boldAmount * votes / totalVotes; - bribeTokenAmount = bribe.bribeTokenAmount * votes / totalVotes; - } + boldAmount = bribe.remainingBoldAmount * votes / remainingVotes; + bribeTokenAmount = bribe.remainingBribeTokenAmount * votes / remainingVotes; + bribe.remainingBoldAmount -= boldAmount; + bribe.remainingBribeTokenAmount -= bribeTokenAmount; + bribe.claimedVotes += votes; + bribeByEpoch[_epoch] = bribe; claimedBribeAtEpoch[_user][_epoch] = true; emit ClaimBribe(_user, _epoch, boldAmount, bribeTokenAmount); @@ -129,23 +144,8 @@ contract BribeInitiative is IInitiative, IBribeInitiative { bribeTokenAmount += bribeTokenAmount_; } - // NOTE: Due to rounding errors, bribes may slightly overpay compared to what they have allocated - // We cap to the available amount for this reason - if (boldAmount != 0) { - uint256 max = bold.balanceOf(address(this)); - if (boldAmount > max) { - boldAmount = max; - } - bold.safeTransfer(msg.sender, boldAmount); - } - - if (bribeTokenAmount != 0) { - uint256 max = bribeToken.balanceOf(address(this)); - if (bribeTokenAmount > max) { - bribeTokenAmount = max; - } - bribeToken.safeTransfer(msg.sender, bribeTokenAmount); - } + if (boldAmount != 0) bold.safeTransfer(msg.sender, boldAmount); + if (bribeTokenAmount != 0) bribeToken.safeTransfer(msg.sender, bribeTokenAmount); } /// @inheritdoc IInitiative @@ -180,20 +180,6 @@ contract BribeInitiative is IInitiative, IBribeInitiative { emit ModifyLQTYAllocation(_user, _epoch, _lqty, _offset); } - function _loadTotalLQTYAllocation(uint256 _epoch) private view returns (uint256, uint256) { - require(_epoch <= governance.epoch(), "No future Lookup"); - DoubleLinkedList.Item memory totalLqtyAllocation = totalLQTYAllocationByEpoch.items[_epoch]; - - return (totalLqtyAllocation.lqty, totalLqtyAllocation.offset); - } - - function _loadLQTYAllocation(address _user, uint256 _epoch) private view returns (uint256, uint256) { - require(_epoch <= governance.epoch(), "No future Lookup"); - DoubleLinkedList.Item memory lqtyAllocation = lqtyAllocationByUserAtEpoch[_user].items[_epoch]; - - return (lqtyAllocation.lqty, lqtyAllocation.offset); - } - /// @inheritdoc IBribeInitiative function getMostRecentUserEpoch(address _user) external view returns (uint256) { uint256 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); diff --git a/src/Governance.sol b/src/Governance.sol index b2dbf1d..4d1177a 100644 --- a/src/Governance.sol +++ b/src/Governance.sol @@ -18,6 +18,7 @@ import {MultiDelegateCall} from "./utils/MultiDelegateCall.sol"; import {WAD, PermitParams} from "./utils/Types.sol"; import {safeCallWithMinGas} from "./utils/SafeCallMinGas.sol"; import {Ownable} from "./utils/Ownable.sol"; +import {_lqtyToVotes} from "./utils/VotingPower.sol"; /// @title Governance: Modular Initiative based Governance contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Ownable, IGovernance { @@ -266,8 +267,7 @@ contract Governance is MultiDelegateCall, UserProxyFactory, ReentrancyGuard, Own /// @inheritdoc IGovernance function lqtyToVotes(uint256 _lqtyAmount, uint256 _timestamp, uint256 _offset) public pure returns (uint256) { - uint256 prod = _lqtyAmount * _timestamp; - return prod > _offset ? prod - _offset : 0; + return _lqtyToVotes(_lqtyAmount, _timestamp, _offset); } /*////////////////////////////////////////////////////////////// diff --git a/src/interfaces/IBribeInitiative.sol b/src/interfaces/IBribeInitiative.sol index af8c593..64053f9 100644 --- a/src/interfaces/IBribeInitiative.sol +++ b/src/interfaces/IBribeInitiative.sol @@ -22,15 +22,20 @@ interface IBribeInitiative { function bribeToken() external view returns (IERC20 bribeToken); struct Bribe { - uint256 boldAmount; - uint256 bribeTokenAmount; // [scaled as 10 ** bribeToken.decimals()] + uint256 remainingBoldAmount; + uint256 remainingBribeTokenAmount; // [scaled as 10 ** bribeToken.decimals()] + uint256 claimedVotes; } /// @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(uint256 _epoch) external view returns (uint256 boldAmount, uint256 bribeTokenAmount); + /// @return remainingBoldAmount Amount of BOLD tokens that haven't been claimed yet + /// @return remainingBribeTokenAmount Amount of bribe tokens that haven't been claimed yet + /// @return claimedVotes Sum of voting power of users who have already claimed their bribes + function bribeByEpoch(uint256 _epoch) + external + view + returns (uint256 remainingBoldAmount, uint256 remainingBribeTokenAmount, uint256 claimedVotes); /// @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 diff --git a/src/utils/VotingPower.sol b/src/utils/VotingPower.sol new file mode 100644 index 0000000..23c70ff --- /dev/null +++ b/src/utils/VotingPower.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +function _lqtyToVotes(uint256 _lqtyAmount, uint256 _timestamp, uint256 _offset) pure returns (uint256) { + uint256 prod = _lqtyAmount * _timestamp; + return prod > _offset ? prod - _offset : 0; +} diff --git a/test/BribeInitiative.t.sol b/test/BribeInitiative.t.sol index 2afc2ec..02ee969 100644 --- a/test/BribeInitiative.t.sol +++ b/test/BribeInitiative.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.24; import {Test, console2} from "forge-std/Test.sol"; +import {Strings} from "openzeppelin/contracts/utils/Strings.sol"; import {IGovernance} from "../src/interfaces/IGovernance.sol"; import {IBribeInitiative} from "../src/interfaces/IBribeInitiative.sol"; @@ -14,6 +15,8 @@ import {MockStakingV1} from "./mocks/MockStakingV1.sol"; import {MockStakingV1Deployer} from "./mocks/MockStakingV1Deployer.sol"; contract BribeInitiativeTest is Test, MockStakingV1Deployer { + using Strings for uint256; + MockERC20Tester private lqty; MockERC20Tester private lusd; MockStakingV1 private stakingV1; @@ -342,13 +345,13 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { assertEq(5, governance.epoch(), "not in epoch 5"); // check amount of bribes in epoch 3 - (uint256 boldAmountFromStorage, uint256 bribeTokenAmountFromStorage) = + (uint256 boldAmountFromStorage, uint256 bribeTokenAmountFromStorage,) = IBribeInitiative(bribeInitiative).bribeByEpoch(governance.epoch() - 2); assertEq(boldAmountFromStorage, 1e18, "boldAmountFromStorage != 1e18"); assertEq(bribeTokenAmountFromStorage, 1e18, "bribeTokenAmountFromStorage != 1e18"); // check amount of bribes in epoch 4 - (boldAmountFromStorage, bribeTokenAmountFromStorage) = + (boldAmountFromStorage, bribeTokenAmountFromStorage,) = IBribeInitiative(bribeInitiative).bribeByEpoch(governance.epoch() - 1); assertEq(boldAmountFromStorage, 1e18, "boldAmountFromStorage != 1e18"); assertEq(bribeTokenAmountFromStorage, 1e18, "bribeTokenAmountFromStorage != 1e18"); @@ -403,61 +406,44 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { (uint256 boldAmount, uint256 bribeTokenAmount) = _claimBribe(user1, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); - // calculate user share of total allocation for initiative for the given epoch as percentage - (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 - (uint256 boldAmountForEpoch, uint256 bribeTokenAmountForEpoch) = bribeInitiative.bribeByEpoch(3); - uint256 userShareOfTotalBoldForEpoch = (boldAmount * 10_000) / uint256(boldAmountForEpoch); - uint256 userShareOfTotalBribeForEpoch = (bribeTokenAmount * 10_000) / uint256(bribeTokenAmountForEpoch); - - // check that they're equivalent - assertEq( - userShareOfTotalAllocated, - userShareOfTotalBoldForEpoch, - "userShareOfTotalAllocated != userShareOfTotalBoldForEpoch" - ); - assertEq( - userShareOfTotalAllocated, - userShareOfTotalBribeForEpoch, - "userShareOfTotalAllocated != userShareOfTotalBribeForEpoch" - ); + assertEq(boldAmount, 0.5e18, "wrong BOLD amount"); + assertEq(bribeTokenAmount, 0.5e18, "wrong bribe token amount"); } function test_claimedBribes_fraction_fuzz( - uint256 user1StakeAmount, - uint256 user2StakeAmount, - uint256 user3StakeAmount + uint256[3] memory userStakeAmount, + uint256 boldAmount, + uint256 bribeTokenAmount ) public { + address[3] memory user = [user1, user2, user3]; + assertEq(user.length, userStakeAmount.length, "user.length != userStakeAmount.length"); + // =========== epoch 1 ================== - 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))); + boldAmount = bound(boldAmount, 1, lusd.balanceOf(lusdHolder)); + bribeTokenAmount = bound(bribeTokenAmount, 1, lqty.balanceOf(lusdHolder)); // all users stake in epoch 1 - _stakeLQTY(user1, user1StakeAmount); - _stakeLQTY(user2, user2StakeAmount); - _stakeLQTY(user3, user3StakeAmount); + uint256 totalStakeAmount; + for (uint256 i = 0; i < user.length; ++i) { + totalStakeAmount += userStakeAmount[i] = bound(userStakeAmount[i], 1, lqty.balanceOf(user[i])); + _stakeLQTY(user[i], userStakeAmount[i]); + } // =========== 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(1e18, 1e18, governance.epoch() + 1); + _depositBribe(boldAmount, bribeTokenAmount, governance.epoch() + 1); // =========== epoch 3 ================== vm.warp(block.timestamp + EPOCH_DURATION); assertEq(3, governance.epoch(), "not in epoch 3"); // users all vote on bribeInitiative - _allocateLQTY(user1, int256(user1StakeAmount), 0); - _allocateLQTY(user2, int256(user2StakeAmount), 0); - _allocateLQTY(user3, int256(user3StakeAmount), 0); + for (uint256 i = 0; i < user.length; ++i) { + _allocateLQTY(user[i], int256(userStakeAmount[i]), 0); + } // =========== epoch 4 ================== vm.warp(block.timestamp + EPOCH_DURATION); @@ -466,60 +452,31 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { // all users claim bribes for 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) = - _claimBribe(user2, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); - (uint256 boldAmount3, uint256 bribeTokenAmount3) = - _claimBribe(user3, claimEpoch, prevAllocationEpoch, prevAllocationEpoch); - - // calculate user share of total allocation for initiative for the given epoch as percentage - uint256 userShareOfTotalAllocated1 = _getUserShareOfAllocationAsPercentage(user1, 3); - uint256 userShareOfTotalAllocated2 = _getUserShareOfAllocationAsPercentage(user2, 3); - uint256 userShareOfTotalAllocated3 = _getUserShareOfAllocationAsPercentage(user3, 3); - - // calculate user received bribes as share of total bribes as percentage - (uint256 userShareOfTotalBoldForEpoch1, uint256 userShareOfTotalBribeForEpoch1) = - _getBribesAsPercentageOfTotal(3, boldAmount1, bribeTokenAmount1); - (uint256 userShareOfTotalBoldForEpoch2, uint256 userShareOfTotalBribeForEpoch2) = - _getBribesAsPercentageOfTotal(3, boldAmount2, bribeTokenAmount2); - (uint256 userShareOfTotalBoldForEpoch3, uint256 userShareOfTotalBribeForEpoch3) = - _getBribesAsPercentageOfTotal(3, boldAmount3, bribeTokenAmount3); - - // check that they're equivalent - // user1 - assertEq( - userShareOfTotalAllocated1, - userShareOfTotalBoldForEpoch1, - "userShareOfTotalAllocated1 != userShareOfTotalBoldForEpoch1" - ); - assertEq( - userShareOfTotalAllocated1, - userShareOfTotalBribeForEpoch1, - "userShareOfTotalAllocated1 != userShareOfTotalBribeForEpoch1" - ); - // user2 - assertEq( - userShareOfTotalAllocated2, - userShareOfTotalBoldForEpoch2, - "userShareOfTotalAllocated2 != userShareOfTotalBoldForEpoch2" - ); - assertEq( - userShareOfTotalAllocated2, - userShareOfTotalBribeForEpoch2, - "userShareOfTotalAllocated2 != userShareOfTotalBribeForEpoch2" - ); - // user3 - assertEq( - userShareOfTotalAllocated3, - userShareOfTotalBoldForEpoch3, - "userShareOfTotalAllocated3 != userShareOfTotalBoldForEpoch3" - ); - assertEq( - userShareOfTotalAllocated3, - userShareOfTotalBribeForEpoch3, - "userShareOfTotalAllocated3 != userShareOfTotalBribeForEpoch3" - ); + uint256 totalClaimedBoldAmount; + uint256 totalClaimedBribeTokenAmount; + + for (uint256 i = 0; i < user.length; ++i) { + (uint256 claimedBoldAmount, uint256 claimedBribeTokenAmount) = + _claimBribe(user[i], claimEpoch, prevAllocationEpoch, prevAllocationEpoch); + + assertApproxEqAbs( + claimedBoldAmount, + boldAmount * userStakeAmount[i] / totalStakeAmount, + // we expect `claimedBoldAmount` to be within `idealAmount +/- 1` + // where `idealAmount = boldAmount * userStakeAmount[i] / totalStakeAmount`, + // however our calculation of `idealAmount` itself has a rounding error of `(-1, 0]`, + // so the total difference can add up to 2 + 2, + string.concat("wrong BOLD amount for user[", i.toString(), "]") + ); + + totalClaimedBoldAmount += claimedBoldAmount; + totalClaimedBribeTokenAmount += claimedBribeTokenAmount; + } + + // total + assertEq(totalClaimedBoldAmount, boldAmount, "there should be no BOLD dust left"); + assertEq(totalClaimedBribeTokenAmount, bribeTokenAmount, "there should be no bribe token dust left"); } // only users that voted receive bribe, vetoes shouldn't receive anything @@ -1038,18 +995,18 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { vm.stopPrank(); } - function _depositBribe(uint128 boldAmount, uint256 bribeAmount, uint256 epoch) public { + function _depositBribe(uint256 boldAmount, uint256 bribeAmount, uint256 epoch) public { vm.startPrank(lusdHolder); - lqty.approve(address(bribeInitiative), boldAmount); - lusd.approve(address(bribeInitiative), bribeAmount); + lusd.approve(address(bribeInitiative), boldAmount); + lqty.approve(address(bribeInitiative), bribeAmount); bribeInitiative.depositBribe(boldAmount, bribeAmount, epoch); vm.stopPrank(); } function _depositBribe(address _initiative, uint256 boldAmount, uint256 bribeAmount, uint256 epoch) public { vm.startPrank(lusdHolder); - lqty.approve(_initiative, boldAmount); - lusd.approve(_initiative, bribeAmount); + lusd.approve(_initiative, boldAmount); + lqty.approve(_initiative, bribeAmount); BribeInitiative(_initiative).depositBribe(boldAmount, bribeAmount, epoch); vm.stopPrank(); } @@ -1081,23 +1038,4 @@ contract BribeInitiativeTest is Test, MockStakingV1Deployer { (boldAmount, bribeTokenAmount) = bribeInitiative.claimBribes(epochs); vm.stopPrank(); } - - function _getUserShareOfAllocationAsPercentage(address user, uint256 epoch) - internal - returns (uint256 userShareOfTotalAllocated) - { - (uint256 userLqtyAllocated,) = bribeInitiative.lqtyAllocatedByUserAtEpoch(user, epoch); - (uint256 totalLqtyAllocated,) = bribeInitiative.totalLQTYAllocatedByEpoch(epoch); - userShareOfTotalAllocated = (uint256(userLqtyAllocated) * 10_000) / uint256(totalLqtyAllocated); - } - - function _getBribesAsPercentageOfTotal(uint256 epoch, uint256 userBoldAmount, uint256 userBribeTokenAmount) - internal - returns (uint256 userShareOfTotalBoldForEpoch, uint256 userShareOfTotalBribeForEpoch) - { - (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/CurveV2GaugeRewards.t.sol b/test/CurveV2GaugeRewards.t.sol index 7a1c491..99ff636 100644 --- a/test/CurveV2GaugeRewards.t.sol +++ b/test/CurveV2GaugeRewards.t.sol @@ -39,11 +39,26 @@ contract ForkedCurveV2GaugeRewardsTest is Test { ILiquidityGauge private gauge; CurveV2GaugeRewards private curveV2GaugeRewards; - address mockGovernance = address(0x123123); - function setUp() public { vm.createSelectFork(vm.rpcUrl("mainnet"), 20430000); + 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), + epochDuration: EPOCH_DURATION, + epochVotingCutoff: EPOCH_VOTING_CUTOFF + }); + + governance = new Governance( + address(lqty), address(lusd), stakingV1, address(lusd), config, address(this), initialInitiatives + ); + address[] memory _coins = new address[](2); _coins[0] = address(lusd); _coins[1] = address(usdc); @@ -67,7 +82,7 @@ contract ForkedCurveV2GaugeRewardsTest is Test { curveV2GaugeRewards = new CurveV2GaugeRewards( // address(vm.computeCreateAddress(address(this), vm.getNonce(address(this)) + 1)), - address(mockGovernance), + address(governance), address(lusd), address(lqty), address(gauge), @@ -75,23 +90,7 @@ contract ForkedCurveV2GaugeRewardsTest is Test { ); initialInitiatives.push(address(curveV2GaugeRewards)); - - 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), - epochDuration: EPOCH_DURATION, - epochVotingCutoff: EPOCH_VOTING_CUTOFF - }); - - governance = new Governance( - address(lqty), address(lusd), stakingV1, address(lusd), config, address(this), initialInitiatives - ); + governance.registerInitialInitiatives(initialInitiatives); vm.startPrank(curveFactory.admin()); gauge.add_reward(address(lusd), address(curveV2GaugeRewards)); @@ -112,11 +111,11 @@ contract ForkedCurveV2GaugeRewardsTest is Test { } function test_claimAndDepositIntoGaugeFuzz(uint128 amt) public { - deal(address(lusd), mockGovernance, amt); + deal(address(lusd), address(governance), amt); vm.assume(amt > 604800); // Pretend a Proposal has passed - vm.startPrank(address(mockGovernance)); + vm.startPrank(address(governance)); lusd.transfer(address(curveV2GaugeRewards), amt); assertEq(lusd.balanceOf(address(curveV2GaugeRewards)), amt); @@ -127,10 +126,10 @@ contract ForkedCurveV2GaugeRewardsTest is Test { /// @dev If the amount rounds down below 1 per second it reverts function test_claimAndDepositIntoGaugeGrief() public { uint256 amt = 604800 - 1; - deal(address(lusd), mockGovernance, amt); + deal(address(lusd), address(governance), amt); // Pretend a Proposal has passed - vm.startPrank(address(mockGovernance)); + vm.startPrank(address(governance)); lusd.transfer(address(curveV2GaugeRewards), amt); assertEq(lusd.balanceOf(address(curveV2GaugeRewards)), amt); @@ -141,10 +140,10 @@ contract ForkedCurveV2GaugeRewardsTest is Test { /// @dev Fuzz test that shows that given a total = amt + dust, the dust is lost permanently function test_noDustGriefFuzz(uint128 amt, uint128 dust) public { uint256 total = uint256(amt) + uint256(dust); - deal(address(lusd), mockGovernance, total); + deal(address(lusd), address(governance), total); // Pretend a Proposal has passed - vm.startPrank(address(mockGovernance)); + vm.startPrank(address(governance)); // Dust amount lusd.transfer(address(curveV2GaugeRewards), amt); // Rest diff --git a/test/recon/properties/BribeInitiativeProperties.sol b/test/recon/properties/BribeInitiativeProperties.sol index 676f4b8..07cb48c 100644 --- a/test/recon/properties/BribeInitiativeProperties.sol +++ b/test/recon/properties/BribeInitiativeProperties.sol @@ -22,7 +22,7 @@ abstract contract BribeInitiativeProperties is BeforeAfter { // calculate balance delta as a percentage of the total bribe for this epoch // this is what user DOES receive - (uint256 bribeBoldAmount, uint256 bribeBribeTokenAmount) = + (uint256 bribeBoldAmount, uint256 bribeBribeTokenAmount,) = IBribeInitiative(initiative).bribeByEpoch(currentEpoch); uint256 lqtyPercentageOfBribe = (userLqtyBalanceDelta * 10_000) / bribeBribeTokenAmount; uint256 lusdPercentageOfBribe = (userLusdBalanceDelta * 10_000) / bribeBoldAmount; diff --git a/test/recon/targets/BribeInitiativeTargets.sol b/test/recon/targets/BribeInitiativeTargets.sol index 63ef220..4ab6be9 100644 --- a/test/recon/targets/BribeInitiativeTargets.sol +++ b/test/recon/targets/BribeInitiativeTargets.sol @@ -28,11 +28,11 @@ abstract contract BribeInitiativeTargets is Test, BaseTargetFunctions, Propertie lusd.approve(address(initiative), boldAmount); lqty.approve(address(initiative), bribeTokenAmount); - (uint256 boldAmountB4, uint256 bribeTokenAmountB4) = IBribeInitiative(initiative).bribeByEpoch(epoch); + (uint256 boldAmountB4, uint256 bribeTokenAmountB4,) = IBribeInitiative(initiative).bribeByEpoch(epoch); initiative.depositBribe(boldAmount, bribeTokenAmount, epoch); - (uint256 boldAmountAfter, uint256 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"); @@ -99,7 +99,7 @@ abstract contract BribeInitiativeTargets is Test, BaseTargetFunctions, Propertie } // Check if there are bribes - (uint256 boldAmount, uint256 bribeTokenAmount) = initiative.bribeByEpoch(epoch); + (uint256 boldAmount, uint256 bribeTokenAmount,) = initiative.bribeByEpoch(epoch); bool bribeWasThere; if (boldAmount != 0 || bribeTokenAmount != 0) { bribeWasThere = true;