Skip to content

Commit

Permalink
Merge branch 'dev-governance-refactor' into bribe-initiative-gov-inva…
Browse files Browse the repository at this point in the history
…r-tester
  • Loading branch information
GalloDaSballo committed Oct 14, 2024
2 parents d93e6ec + 12f94ed commit 26cb261
Show file tree
Hide file tree
Showing 24 changed files with 2,137 additions and 524 deletions.
5 changes: 1 addition & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
[submodule "lib/v4-core"]
path = lib/v4-core
url = https://github.com/Uniswap/v4-core
[submodule "lib/solmate"]
path = lib/solmate
url = https://github.com/transmissions11/solmate
[submodule "lib/chimera"]
path = lib/chimera
url = https://github.com/Recon-Fuzz/chimera
url = https://github.com/Recon-Fuzz/chimera
12 changes: 12 additions & 0 deletions INTEGRATION.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Risks to integrators

Somebody could claim on your behalf

Votes not meeting the threshold may result in 0 rewards

Claiming more than once will return 0

## INVARIANT: You can only claim for previous epoch

assert(votesSnapshot_.forEpoch == epoch() - 1); /// @audit INVARIANT: You can only claim for previous epoch
/// All unclaimed rewards are always recycled
1 change: 0 additions & 1 deletion lib/solmate
Submodule solmate deleted from 97bdb2
153 changes: 72 additions & 81 deletions src/BribeInitiative.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ 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;
Expand Down Expand Up @@ -43,13 +47,13 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
}

/// @inheritdoc IBribeInitiative
function totalLQTYAllocatedByEpoch(uint16 _epoch) external view returns (uint88) {
return totalLQTYAllocationByEpoch.getValue(_epoch);
function totalLQTYAllocatedByEpoch(uint16 _epoch) external view returns (uint88, uint32) {
return _loadTotalLQTYAllocation(_epoch);
}

/// @inheritdoc IBribeInitiative
function lqtyAllocatedByUserAtEpoch(address _user, uint16 _epoch) external view returns (uint88) {
return lqtyAllocationByUserAtEpoch[_user].getValue(_epoch);
function lqtyAllocatedByUserAtEpoch(address _user, uint16 _epoch) external view returns (uint88, uint32) {
return _loadLQTYAllocation(_user, _epoch);
}

/// @inheritdoc IBribeInitiative
Expand Down Expand Up @@ -96,9 +100,14 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
"BribeInitiative: invalid-prev-total-lqty-allocation-epoch"
);

boldAmount = uint256(bribe.boldAmount) * uint256(lqtyAllocation.value) / uint256(totalLQTYAllocation.value);
bribeTokenAmount =
uint256(bribe.bribeTokenAmount) * uint256(lqtyAllocation.value) / uint256(totalLQTYAllocation.value);
(uint88 totalLQTY, uint32 totalAverageTimestamp) = _decodeLQTYAllocation(totalLQTYAllocation.value);
uint240 totalVotes = governance.lqtyToVotes(totalLQTY, block.timestamp, totalAverageTimestamp);
if (totalVotes != 0) {
(uint88 lqty, uint32 averageTimestamp) = _decodeLQTYAllocation(lqtyAllocation.value);
uint240 votes = governance.lqtyToVotes(lqty, block.timestamp, averageTimestamp);
boldAmount = uint256(bribe.boldAmount) * uint256(votes) / uint256(totalVotes);
bribeTokenAmount = uint256(bribe.bribeTokenAmount) * uint256(votes) / uint256(totalVotes);
}

claimedBribeAtEpoch[_user][_epoch] = true;

Expand Down Expand Up @@ -129,93 +138,75 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
/// @inheritdoc IInitiative
function onUnregisterInitiative(uint16) external virtual override onlyGovernance {}

function _setTotalLQTYAllocationByEpoch(uint16 _epoch, uint88 _value, bool _insert) private {
function _setTotalLQTYAllocationByEpoch(uint16 _epoch, uint88 _lqty, uint32 _averageTimestamp, bool _insert)
private
{
uint224 value = (uint224(_lqty) << 32) | _averageTimestamp;
if (_insert) {
totalLQTYAllocationByEpoch.insert(_epoch, _value, 0);
totalLQTYAllocationByEpoch.insert(_epoch, value, 0);
} else {
totalLQTYAllocationByEpoch.items[_epoch].value = _value;
totalLQTYAllocationByEpoch.items[_epoch].value = value;
}
emit ModifyTotalLQTYAllocation(_epoch, _value);
emit ModifyTotalLQTYAllocation(_epoch, _lqty, _averageTimestamp);
}

function _setLQTYAllocationByUserAtEpoch(address _user, uint16 _epoch, uint88 _value, bool _insert) private {
function _setLQTYAllocationByUserAtEpoch(
address _user,
uint16 _epoch,
uint88 _lqty,
uint32 _averageTimestamp,
bool _insert
) private {
uint224 value = (uint224(_lqty) << 32) | _averageTimestamp;
if (_insert) {
lqtyAllocationByUserAtEpoch[_user].insert(_epoch, _value, 0);
lqtyAllocationByUserAtEpoch[_user].insert(_epoch, value, 0);
} else {
lqtyAllocationByUserAtEpoch[_user].items[_epoch].value = _value;
lqtyAllocationByUserAtEpoch[_user].items[_epoch].value = value;
}
emit ModifyLQTYAllocation(_user, _epoch, _value);
emit ModifyLQTYAllocation(_user, _epoch, _lqty, _averageTimestamp);
}

/// @inheritdoc IInitiative
function onAfterAllocateLQTY(uint16 _currentEpoch, address _user, uint88 _voteLQTY, uint88 _vetoLQTY)
external
virtual
onlyGovernance
{
uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead();
function _encodeLQTYAllocation(uint88 _lqty, uint32 _averageTimestamp) private pure returns (uint224) {
return EncodingDecodingLib.encodeLQTYAllocation(_lqty, _averageTimestamp);
}
function _decodeLQTYAllocation(uint224 _value) private pure returns (uint88, uint32) {
return EncodingDecodingLib.decodeLQTYAllocation(_value);
}

function _loadTotalLQTYAllocation(uint16 _epoch) private view returns (uint88, uint32) {
return _decodeLQTYAllocation(totalLQTYAllocationByEpoch.items[_epoch].value);
}

function _loadLQTYAllocation(address _user, uint16 _epoch) private view returns (uint88, uint32) {
return _decodeLQTYAllocation(lqtyAllocationByUserAtEpoch[_user].items[_epoch].value);
}

function onAfterAllocateLQTY(
uint16 _currentEpoch,
address _user,
IGovernance.UserState calldata _userState,
IGovernance.Allocation calldata _allocation,
IGovernance.InitiativeState calldata _initiativeState
) external virtual onlyGovernance {
if (_currentEpoch == 0) return;

// if this is the first user allocation in the epoch, then insert a new item into the user allocation DLL
if (mostRecentUserEpoch != _currentEpoch) {
uint88 prevVoteLQTY = lqtyAllocationByUserAtEpoch[_user].items[mostRecentUserEpoch].value;
uint88 newVoteLQTY = (_vetoLQTY == 0) ? _voteLQTY : 0;
uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead();
// if this is the first allocation in the epoch, then insert a new item into the total allocation DLL
if (mostRecentTotalEpoch != _currentEpoch) {
uint88 prevTotalLQTYAllocation = totalLQTYAllocationByEpoch.items[mostRecentTotalEpoch].value;
if (_vetoLQTY == 0) {
// no veto to no veto
_setTotalLQTYAllocationByEpoch(
_currentEpoch, prevTotalLQTYAllocation + newVoteLQTY - prevVoteLQTY, true
);
} else {
if (prevVoteLQTY != 0) {
// if the prev user allocation was counted in, then remove the prev user allocation from the
// total allocation (no veto to veto)
_setTotalLQTYAllocationByEpoch(_currentEpoch, prevTotalLQTYAllocation - prevVoteLQTY, true);
} else {
// veto to veto
_setTotalLQTYAllocationByEpoch(_currentEpoch, prevTotalLQTYAllocation, true);
}
}
} else {
if (_vetoLQTY == 0) {
// no veto to no veto
_setTotalLQTYAllocationByEpoch(
_currentEpoch,
totalLQTYAllocationByEpoch.items[_currentEpoch].value + newVoteLQTY - prevVoteLQTY,
false
);
} else if (prevVoteLQTY != 0) {
// no veto to veto
_setTotalLQTYAllocationByEpoch(
_currentEpoch, totalLQTYAllocationByEpoch.items[_currentEpoch].value - prevVoteLQTY, false
);
}
}
// insert a new item into the user allocation DLL
_setLQTYAllocationByUserAtEpoch(_user, _currentEpoch, newVoteLQTY, true);
} else {
uint88 prevVoteLQTY = lqtyAllocationByUserAtEpoch[_user].getItem(_currentEpoch).value;
if (_vetoLQTY == 0) {
// update the allocation for the current epoch by adding the new allocation and subtracting
// the previous one (no veto to no veto)
_setTotalLQTYAllocationByEpoch(
_currentEpoch,
totalLQTYAllocationByEpoch.items[_currentEpoch].value + _voteLQTY - prevVoteLQTY,
false
);
_setLQTYAllocationByUserAtEpoch(_user, _currentEpoch, _voteLQTY, false);
} else {
// if the user vetoed the initiative, subtract the allocation from the DLLs (no veto to veto)
_setTotalLQTYAllocationByEpoch(
_currentEpoch, totalLQTYAllocationByEpoch.items[_currentEpoch].value - prevVoteLQTY, false
);
_setLQTYAllocationByUserAtEpoch(_user, _currentEpoch, 0, false);
}
}
uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead();
uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead();

_setTotalLQTYAllocationByEpoch(
_currentEpoch,
_initiativeState.voteLQTY,
_initiativeState.averageStakingTimestampVoteLQTY,
mostRecentTotalEpoch != _currentEpoch // Insert if current > recent
);

_setLQTYAllocationByUserAtEpoch(
_user,
_currentEpoch,
_allocation.voteLQTY,
_userState.averageStakingTimestamp,
mostRecentUserEpoch != _currentEpoch // Insert if user current > recent
);
}

/// @inheritdoc IInitiative
Expand Down
6 changes: 3 additions & 3 deletions src/ForwardBribe.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ contract ForwardBribe is BribeInitiative {
uint boldAmount = bold.balanceOf(address(this));
uint bribeTokenAmount = bribeToken.balanceOf(address(this));

if (boldAmount != 0) bold.safeTransfer(receiver, boldAmount);
if (bribeTokenAmount != 0) bribeToken.safeTransfer(receiver, bribeTokenAmount);
if (boldAmount != 0) bold.transfer(receiver, boldAmount);
if (bribeTokenAmount != 0) bribeToken.transfer(receiver, bribeTokenAmount);
}
}
}
Loading

0 comments on commit 26cb261

Please sign in to comment.