@@ -17,7 +17,7 @@ import "./L1ReservoirStorage.sol";
17
17
* It provides a function to periodically drip rewards, and functions to compute accumulated and new
18
18
* total rewards at a particular block number.
19
19
*/
20
- contract L1Reservoir is L1ReservoirV1Storage , Reservoir {
20
+ contract L1Reservoir is L1ReservoirV2Storage , Reservoir {
21
21
using SafeMath for uint256 ;
22
22
23
23
// Emitted when the initial supply snapshot is taken after contract deployment
@@ -38,6 +38,10 @@ contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
38
38
event RewardsDripped (uint256 _totalMinted , uint256 _sentToL2 , uint256 _nextDeadline );
39
39
// Emitted when the address for the L2Reservoir is updated
40
40
event L2ReservoirAddressUpdated (address _l2ReservoirAddress );
41
+ // Emitted when drip reward per block is updated
42
+ event DripRewardPerBlockUpdated (uint256 _dripRewardPerBlock );
43
+ // Emitted when minDripInterval is updated
44
+ event MinDripIntervalUpdated (uint256 _minDripInterval );
41
45
42
46
/**
43
47
* @dev Initialize this contract.
@@ -90,6 +94,26 @@ contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
90
94
emit L2RewardsFractionStaged (_l2RewardsFraction);
91
95
}
92
96
97
+ /**
98
+ * @dev Sets the drip reward per block
99
+ * This is the reward in GRT provided to the keeper that calls drip()
100
+ * @param _dripRewardPerBlock GRT accrued for each block after the threshold
101
+ */
102
+ function setDripRewardPerBlock (uint256 _dripRewardPerBlock ) external onlyGovernor {
103
+ dripRewardPerBlock = _dripRewardPerBlock;
104
+ emit DripRewardPerBlockUpdated (_dripRewardPerBlock);
105
+ }
106
+
107
+ /**
108
+ * @dev Sets the minimum drip interval
109
+ * This is the minimum number of blocks between two successful drips
110
+ * @param _minDripInterval Minimum number of blocks since last drip for drip to be allowed
111
+ */
112
+ function setMinDripInterval (uint256 _minDripInterval ) external onlyGovernor {
113
+ minDripInterval = _minDripInterval;
114
+ emit MinDripIntervalUpdated (_minDripInterval);
115
+ }
116
+
93
117
/**
94
118
* @dev Sets the L2 Reservoir address
95
119
* This is the address on L2 to which we send tokens for rewards.
@@ -128,16 +152,23 @@ contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
128
152
* @param l2MaxGas Max gas for the L2 retryable ticket, only needed if L2RewardsFraction is > 0
129
153
* @param l2GasPriceBid Gas price for the L2 retryable ticket, only needed if L2RewardsFraction is > 0
130
154
* @param l2MaxSubmissionCost Max submission price for the L2 retryable ticket, only needed if L2RewardsFraction is > 0
155
+ * @param keeperRewardBeneficiary Address to which to credit keeper reward (will be redeemed in L2 if l2RewardsFraction is nonzero)
131
156
*/
132
157
function drip (
133
158
uint256 l2MaxGas ,
134
159
uint256 l2GasPriceBid ,
135
- uint256 l2MaxSubmissionCost
160
+ uint256 l2MaxSubmissionCost ,
161
+ address keeperRewardBeneficiary
136
162
) external payable notPaused {
163
+ require (block .number > lastRewardsUpdateBlock + minDripInterval, "WAIT_FOR_MIN_INTERVAL " );
164
+
137
165
uint256 mintedRewardsTotal = getNewGlobalRewards (rewardsMintedUntilBlock);
138
166
uint256 mintedRewardsActual = getNewGlobalRewards (block .number );
139
167
// eps = (signed int) mintedRewardsTotal - mintedRewardsActual
140
168
169
+ uint256 keeperReward = dripRewardPerBlock.mul (
170
+ block .number .sub (lastRewardsUpdateBlock).sub (minDripInterval)
171
+ );
141
172
if (nextIssuanceRate != issuanceRate) {
142
173
rewardsManager ().updateAccRewardsPerSignal ();
143
174
snapshotAccumulatedRewards (mintedRewardsActual); // This updates lastRewardsUpdateBlock
@@ -150,13 +181,15 @@ contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
150
181
rewardsMintedUntilBlock = block .number .add (dripInterval);
151
182
// n = deltaR(t1, t0)
152
183
uint256 newRewardsToDistribute = getNewGlobalRewards (rewardsMintedUntilBlock);
153
- // N = n - eps
154
- uint256 tokensToMint = newRewardsToDistribute.add (mintedRewardsActual).sub (
155
- mintedRewardsTotal
156
- );
184
+ // N = n - eps ( + reward)
185
+ uint256 tokensToMint = newRewardsToDistribute
186
+ .add (mintedRewardsActual)
187
+ .add (keeperReward)
188
+ .sub (mintedRewardsTotal);
157
189
190
+ IGraphToken grt = graphToken ();
158
191
if (tokensToMint > 0 ) {
159
- graphToken () .mint (address (this ), tokensToMint);
192
+ grt .mint (address (this ), tokensToMint);
160
193
}
161
194
162
195
uint256 tokensToSendToL2 = 0 ;
@@ -187,20 +220,26 @@ contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
187
220
tokensToSendToL2,
188
221
l2MaxGas,
189
222
l2GasPriceBid,
190
- l2MaxSubmissionCost
223
+ l2MaxSubmissionCost,
224
+ keeperReward,
225
+ keeperRewardBeneficiary
191
226
);
192
227
} else if (l2RewardsFraction > 0 ) {
193
228
tokensToSendToL2 = tokensToMint.mul (l2RewardsFraction).div (TOKEN_DECIMALS);
194
229
_sendNewTokensAndStateToL2 (
195
230
tokensToSendToL2,
196
231
l2MaxGas,
197
232
l2GasPriceBid,
198
- l2MaxSubmissionCost
233
+ l2MaxSubmissionCost,
234
+ keeperReward,
235
+ keeperRewardBeneficiary
199
236
);
200
237
} else {
201
238
// Avoid locking funds in this contract if we don't need to
202
239
// send a message to L2.
203
240
require (msg .value == 0 , "No eth value needed " );
241
+ // If we don't send rewards to L2, pay the keeper reward in L1
242
+ grt.transfer (keeperRewardBeneficiary, keeperReward);
204
243
}
205
244
emit RewardsDripped (tokensToMint, tokensToSendToL2, rewardsMintedUntilBlock);
206
245
}
@@ -234,14 +273,18 @@ contract L1Reservoir is L1ReservoirV1Storage, Reservoir {
234
273
uint256 nTokens ,
235
274
uint256 maxGas ,
236
275
uint256 gasPriceBid ,
237
- uint256 maxSubmissionCost
276
+ uint256 maxSubmissionCost ,
277
+ uint256 keeperReward ,
278
+ address keeper
238
279
) internal {
239
280
uint256 normalizedSupply = l2RewardsFraction.mul (tokenSupplyCache).div (TOKEN_DECIMALS);
240
281
bytes memory extraData = abi.encodeWithSelector (
241
282
IL2Reservoir.receiveDrip.selector ,
242
283
normalizedSupply,
243
284
issuanceRate,
244
- nextDripNonce
285
+ nextDripNonce,
286
+ keeperReward,
287
+ keeper
245
288
);
246
289
nextDripNonce = nextDripNonce.add (1 );
247
290
bytes memory data = abi.encode (maxSubmissionCost, extraData);
0 commit comments