|
1 | 1 | // SPDX-License-Identifier: MIT
|
2 | 2 | pragma solidity ^0.8.24;
|
3 | 3 |
|
| 4 | +import {console} from "forge-std/console.sol"; |
| 5 | + |
4 | 6 | import {IERC20} from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
|
5 | 7 | import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
|
6 | 8 |
|
@@ -43,13 +45,13 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
|
43 | 45 | }
|
44 | 46 |
|
45 | 47 | /// @inheritdoc IBribeInitiative
|
46 |
| - function totalLQTYAllocatedByEpoch(uint16 _epoch) external view returns (uint88) { |
47 |
| - return totalLQTYAllocationByEpoch.getValue(_epoch); |
| 48 | + function totalLQTYAllocatedByEpoch(uint16 _epoch) external view returns (uint88, uint32) { |
| 49 | + return _loadTotalLQTYAllocation(_epoch); |
48 | 50 | }
|
49 | 51 |
|
50 | 52 | /// @inheritdoc IBribeInitiative
|
51 |
| - function lqtyAllocatedByUserAtEpoch(address _user, uint16 _epoch) external view returns (uint88) { |
52 |
| - return lqtyAllocationByUserAtEpoch[_user].getValue(_epoch); |
| 53 | + function lqtyAllocatedByUserAtEpoch(address _user, uint16 _epoch) external view returns (uint88, uint32) { |
| 54 | + return _loadLQTYAllocation(_user, _epoch); |
53 | 55 | }
|
54 | 56 |
|
55 | 57 | /// @inheritdoc IBribeInitiative
|
@@ -96,9 +98,14 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
|
96 | 98 | "BribeInitiative: invalid-prev-total-lqty-allocation-epoch"
|
97 | 99 | );
|
98 | 100 |
|
99 |
| - boldAmount = uint256(bribe.boldAmount) * uint256(lqtyAllocation.value) / uint256(totalLQTYAllocation.value); |
100 |
| - bribeTokenAmount = |
101 |
| - uint256(bribe.bribeTokenAmount) * uint256(lqtyAllocation.value) / uint256(totalLQTYAllocation.value); |
| 101 | + (uint88 totalLQTY, uint32 totalAverageTimestamp) = _decodeLQTYAllocation(totalLQTYAllocation.value); |
| 102 | + uint240 totalVotes = governance.lqtyToVotes(totalLQTY, block.timestamp, totalAverageTimestamp); |
| 103 | + if (totalVotes != 0) { |
| 104 | + (uint88 lqty, uint32 averageTimestamp) = _decodeLQTYAllocation(lqtyAllocation.value); |
| 105 | + uint240 votes = governance.lqtyToVotes(lqty, block.timestamp, averageTimestamp); |
| 106 | + boldAmount = uint256(bribe.boldAmount) * uint256(votes) / uint256(totalVotes); |
| 107 | + bribeTokenAmount = uint256(bribe.bribeTokenAmount) * uint256(votes) / uint256(totalVotes); |
| 108 | + } |
102 | 109 |
|
103 | 110 | claimedBribeAtEpoch[_user][_epoch] = true;
|
104 | 111 |
|
@@ -129,93 +136,72 @@ contract BribeInitiative is IInitiative, IBribeInitiative {
|
129 | 136 | /// @inheritdoc IInitiative
|
130 | 137 | function onUnregisterInitiative(uint16) external virtual override onlyGovernance {}
|
131 | 138 |
|
132 |
| - function _setTotalLQTYAllocationByEpoch(uint16 _epoch, uint88 _value, bool _insert) private { |
| 139 | + function _setTotalLQTYAllocationByEpoch(uint16 _epoch, uint88 _lqty, uint32 _averageTimestamp, bool _insert) |
| 140 | + private |
| 141 | + { |
| 142 | + uint224 value = (uint224(_lqty) << 32) | _averageTimestamp; |
133 | 143 | if (_insert) {
|
134 |
| - totalLQTYAllocationByEpoch.insert(_epoch, _value, 0); |
| 144 | + totalLQTYAllocationByEpoch.insert(_epoch, value, 0); |
135 | 145 | } else {
|
136 |
| - totalLQTYAllocationByEpoch.items[_epoch].value = _value; |
| 146 | + totalLQTYAllocationByEpoch.items[_epoch].value = value; |
137 | 147 | }
|
138 |
| - emit ModifyTotalLQTYAllocation(_epoch, _value); |
| 148 | + emit ModifyTotalLQTYAllocation(_epoch, _lqty, _averageTimestamp); |
139 | 149 | }
|
140 | 150 |
|
141 |
| - function _setLQTYAllocationByUserAtEpoch(address _user, uint16 _epoch, uint88 _value, bool _insert) private { |
| 151 | + function _setLQTYAllocationByUserAtEpoch( |
| 152 | + address _user, |
| 153 | + uint16 _epoch, |
| 154 | + uint88 _lqty, |
| 155 | + uint32 _averageTimestamp, |
| 156 | + bool _insert |
| 157 | + ) private { |
| 158 | + uint224 value = (uint224(_lqty) << 32) | _averageTimestamp; |
142 | 159 | if (_insert) {
|
143 |
| - lqtyAllocationByUserAtEpoch[_user].insert(_epoch, _value, 0); |
| 160 | + lqtyAllocationByUserAtEpoch[_user].insert(_epoch, value, 0); |
144 | 161 | } else {
|
145 |
| - lqtyAllocationByUserAtEpoch[_user].items[_epoch].value = _value; |
| 162 | + lqtyAllocationByUserAtEpoch[_user].items[_epoch].value = value; |
146 | 163 | }
|
147 |
| - emit ModifyLQTYAllocation(_user, _epoch, _value); |
| 164 | + emit ModifyLQTYAllocation(_user, _epoch, _lqty, _averageTimestamp); |
148 | 165 | }
|
149 | 166 |
|
150 |
| - /// @inheritdoc IInitiative |
151 |
| - function onAfterAllocateLQTY(uint16 _currentEpoch, address _user, uint88 _voteLQTY, uint88 _vetoLQTY) |
152 |
| - external |
153 |
| - virtual |
154 |
| - onlyGovernance |
155 |
| - { |
156 |
| - uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); |
| 167 | + function _decodeLQTYAllocation(uint224 _value) private pure returns (uint88, uint32) { |
| 168 | + return (uint88(_value >> 32), uint32(_value)); |
| 169 | + } |
| 170 | + |
| 171 | + function _loadTotalLQTYAllocation(uint16 _epoch) private view returns (uint88, uint32) { |
| 172 | + return _decodeLQTYAllocation(totalLQTYAllocationByEpoch.items[_epoch].value); |
| 173 | + } |
| 174 | + |
| 175 | + function _loadLQTYAllocation(address _user, uint16 _epoch) private view returns (uint88, uint32) { |
| 176 | + return _decodeLQTYAllocation(lqtyAllocationByUserAtEpoch[_user].items[_epoch].value); |
| 177 | + } |
157 | 178 |
|
| 179 | + function onAfterAllocateLQTY( |
| 180 | + uint16 _currentEpoch, |
| 181 | + address _user, |
| 182 | + IGovernance.UserState calldata _userState, |
| 183 | + IGovernance.Allocation calldata _allocation, |
| 184 | + IGovernance.InitiativeState calldata _initiativeState |
| 185 | + ) external virtual onlyGovernance { |
158 | 186 | if (_currentEpoch == 0) return;
|
159 | 187 |
|
160 |
| - // if this is the first user allocation in the epoch, then insert a new item into the user allocation DLL |
161 |
| - if (mostRecentUserEpoch != _currentEpoch) { |
162 |
| - uint88 prevVoteLQTY = lqtyAllocationByUserAtEpoch[_user].items[mostRecentUserEpoch].value; |
163 |
| - uint88 newVoteLQTY = (_vetoLQTY == 0) ? _voteLQTY : 0; |
164 |
| - uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead(); |
165 |
| - // if this is the first allocation in the epoch, then insert a new item into the total allocation DLL |
166 |
| - if (mostRecentTotalEpoch != _currentEpoch) { |
167 |
| - uint88 prevTotalLQTYAllocation = totalLQTYAllocationByEpoch.items[mostRecentTotalEpoch].value; |
168 |
| - if (_vetoLQTY == 0) { |
169 |
| - // no veto to no veto |
170 |
| - _setTotalLQTYAllocationByEpoch( |
171 |
| - _currentEpoch, prevTotalLQTYAllocation + newVoteLQTY - prevVoteLQTY, true |
172 |
| - ); |
173 |
| - } else { |
174 |
| - if (prevVoteLQTY != 0) { |
175 |
| - // if the prev user allocation was counted in, then remove the prev user allocation from the |
176 |
| - // total allocation (no veto to veto) |
177 |
| - _setTotalLQTYAllocationByEpoch(_currentEpoch, prevTotalLQTYAllocation - prevVoteLQTY, true); |
178 |
| - } else { |
179 |
| - // veto to veto |
180 |
| - _setTotalLQTYAllocationByEpoch(_currentEpoch, prevTotalLQTYAllocation, true); |
181 |
| - } |
182 |
| - } |
183 |
| - } else { |
184 |
| - if (_vetoLQTY == 0) { |
185 |
| - // no veto to no veto |
186 |
| - _setTotalLQTYAllocationByEpoch( |
187 |
| - _currentEpoch, |
188 |
| - totalLQTYAllocationByEpoch.items[_currentEpoch].value + newVoteLQTY - prevVoteLQTY, |
189 |
| - false |
190 |
| - ); |
191 |
| - } else if (prevVoteLQTY != 0) { |
192 |
| - // no veto to veto |
193 |
| - _setTotalLQTYAllocationByEpoch( |
194 |
| - _currentEpoch, totalLQTYAllocationByEpoch.items[_currentEpoch].value - prevVoteLQTY, false |
195 |
| - ); |
196 |
| - } |
197 |
| - } |
198 |
| - // insert a new item into the user allocation DLL |
199 |
| - _setLQTYAllocationByUserAtEpoch(_user, _currentEpoch, newVoteLQTY, true); |
200 |
| - } else { |
201 |
| - uint88 prevVoteLQTY = lqtyAllocationByUserAtEpoch[_user].getItem(_currentEpoch).value; |
202 |
| - if (_vetoLQTY == 0) { |
203 |
| - // update the allocation for the current epoch by adding the new allocation and subtracting |
204 |
| - // the previous one (no veto to no veto) |
205 |
| - _setTotalLQTYAllocationByEpoch( |
206 |
| - _currentEpoch, |
207 |
| - totalLQTYAllocationByEpoch.items[_currentEpoch].value + _voteLQTY - prevVoteLQTY, |
208 |
| - false |
209 |
| - ); |
210 |
| - _setLQTYAllocationByUserAtEpoch(_user, _currentEpoch, _voteLQTY, false); |
211 |
| - } else { |
212 |
| - // if the user vetoed the initiative, subtract the allocation from the DLLs (no veto to veto) |
213 |
| - _setTotalLQTYAllocationByEpoch( |
214 |
| - _currentEpoch, totalLQTYAllocationByEpoch.items[_currentEpoch].value - prevVoteLQTY, false |
215 |
| - ); |
216 |
| - _setLQTYAllocationByUserAtEpoch(_user, _currentEpoch, 0, false); |
217 |
| - } |
218 |
| - } |
| 188 | + uint16 mostRecentUserEpoch = lqtyAllocationByUserAtEpoch[_user].getHead(); |
| 189 | + uint16 mostRecentTotalEpoch = totalLQTYAllocationByEpoch.getHead(); |
| 190 | + |
| 191 | + _setTotalLQTYAllocationByEpoch( |
| 192 | + _currentEpoch, |
| 193 | + _initiativeState.voteLQTY, |
| 194 | + _initiativeState.averageStakingTimestampVoteLQTY, |
| 195 | + mostRecentTotalEpoch != _currentEpoch // Insert if current > recent |
| 196 | + ); |
| 197 | + |
| 198 | + _setLQTYAllocationByUserAtEpoch( |
| 199 | + _user, |
| 200 | + _currentEpoch, |
| 201 | + _allocation.voteLQTY, |
| 202 | + _userState.averageStakingTimestamp, |
| 203 | + mostRecentUserEpoch != _currentEpoch // Insert if user current > recent |
| 204 | + ); |
219 | 205 | }
|
220 | 206 |
|
221 | 207 | /// @inheritdoc IInitiative
|
|
0 commit comments