@defi-wonderland/keep3r-v2
Version:
The Keep3r Network is a decentralized network for projects that need external devops, and for external teams to find keeper jobs
1,143 lines (1,142 loc) • 47.6 kB
HTML
<html lang="en">
<head>
<title>Code coverage report for contracts/peripherals/jobs/Keep3rJobFundableLiquidity.sol</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../../prettify.css" />
<link rel="stylesheet" href="../../../base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="../../../index.html">all files</a> / <a href="index.html">contracts/peripherals/jobs/</a> Keep3rJobFundableLiquidity.sol
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Statements</span>
<span class='fraction'>0/131</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Branches</span>
<span class='fraction'>0/72</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Functions</span>
<span class='fraction'>0/23</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">0% </span>
<span class="quiet">Lines</span>
<span class='fraction'>0/127</span>
</div>
</div>
</div>
<div class='status-line low'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360</td><td class="line-coverage quiet"><span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">// SPDX-License-Identifier: MIT
pragma solidity >=0.8.4 <0.9.0;
import './Keep3rJobOwnership.sol';
import '../Keep3rAccountance.sol';
import '../Keep3rParameters.sol';
import '../../../interfaces/IPairManager.sol';
import '../../../interfaces/peripherals/IKeep3rJobs.sol';
import '../../libraries/FullMath.sol';
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '@openzeppelin/contracts/utils/math/Math.sol';
abstract contract Keep3rJobFundableLiquidity is IKeep3rJobFundableLiquidity, ReentrancyGuard, Keep3rJobOwnership, Keep3rParameters {
using EnumerableSet for EnumerableSet.AddressSet;
using SafeERC20 for IERC20;
/// @notice List of liquidities that are accepted in the system
EnumerableSet.AddressSet internal _approvedLiquidities;
/// @inheritdoc IKeep3rJobFundableLiquidity
mapping(address => mapping(address => uint256)) public override liquidityAmount;
/// @inheritdoc IKeep3rJobFundableLiquidity
mapping(address => uint256) public override rewardedAt;
/// @inheritdoc IKeep3rJobFundableLiquidity
mapping(address => uint256) public override workedAt;
/// @notice Tracks an address and returns its TickCache
mapping(address => TickCache) internal _tick;
// Views
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function approvedLiquidities() external view override returns (address[] memory _list) {</span>
<span class="cstat-no" title="statement not covered" > _list = _approvedLiquidities.values()</span>;
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function jobPeriodCredits(address _job) public view virtual override returns (uint256 _periodCredits) {</span>
<span class="cstat-no" title="statement not covered" > for (uint256 i; i < _jobLiquidities[_job].length(); i++) {</span>
<span class="cstat-no" title="statement not covered" > address _liquidity = _jobLiquidities[_job].at(i);</span>
<span class="cstat-no" title="statement not covered" > if (_approvedLiquidities.contains(_liquidity)) {</span>
<span class="cstat-no" title="statement not covered" > TickCache memory _tickCache = observeLiquidity(_liquidity);</span>
<span class="cstat-no" title="statement not covered" > if (_tickCache.period != 0) {</span>
<span class="cstat-no" title="statement not covered" > int56 _tickDifference = _isKP3RToken0[_liquidity] ? _tickCache.difference : -_tickCache.difference;</span>
<span class="cstat-no" title="statement not covered" > _periodCredits += _getReward(</span>
IKeep3rHelper(keep3rHelper).getKP3RsAtTick(liquidityAmount[_job][_liquidity], _tickDifference, rewardPeriodTime)
);
}
}
}
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function jobLiquidityCredits(address _job) public view override returns (uint256 _liquidityCredits) {</span>
<span class="cstat-no" title="statement not covered" > uint256 _periodCredits = jobPeriodCredits(_job);</span>
// A job can have liquidityCredits without periodCredits (forced by Governance)
<span class="cstat-no" title="statement not covered" > if (rewardedAt[_job] > _period(block.timestamp - rewardPeriodTime)) {</span>
// Will calculate job credits only if it was rewarded later than last period
<span class="cstat-no" title="statement not covered" > if ((block.timestamp - rewardedAt[_job]) >= rewardPeriodTime) {</span>
// Will return a full period if job was rewarded more than a period ago
<span class="cstat-no" title="statement not covered" > _liquidityCredits = _periodCredits</span>;
} else {
// Will update minted job credits (not forced) to new twaps if credits are outdated
<span class="cstat-no" title="statement not covered" > _liquidityCredits = _periodCredits > 0</span>
? (_jobLiquidityCredits[_job] * _periodCredits) / _jobPeriodCredits[_job]
: _jobLiquidityCredits[_job];
}
} else {
// Will return a full period if job credits are expired
<span class="cstat-no" title="statement not covered" > _liquidityCredits = _periodCredits</span>;
}
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function totalJobCredits(address _job) external view override returns (uint256 _credits) {</span>
<span class="cstat-no" title="statement not covered" > uint256 _periodCredits = jobPeriodCredits(_job);</span>
<span class="cstat-no" title="statement not covered" > uint256 _cooldown;</span>
<span class="cstat-no" title="statement not covered" > if ((rewardedAt[_job] > _period(block.timestamp - rewardPeriodTime))) {</span>
// Will calculate cooldown if it outdated
<span class="cstat-no" title="statement not covered" > if ((block.timestamp - rewardedAt[_job]) >= rewardPeriodTime) {</span>
// Will calculate cooldown from last reward reference in this period
<span class="cstat-no" title="statement not covered" > _cooldown = block.timestamp - (rewardedAt[_job] + rewardPeriodTime)</span>;
} else {
// Will calculate cooldown from last reward timestamp
<span class="cstat-no" title="statement not covered" > _cooldown = block.timestamp - rewardedAt[_job]</span>;
}
} else {
// Will calculate cooldown from period start if expired
<span class="cstat-no" title="statement not covered" > _cooldown = block.timestamp - _period(block.timestamp)</span>;
}
<span class="cstat-no" title="statement not covered" > _credits = jobLiquidityCredits(_job) + _phase(_cooldown, _periodCredits)</span>;
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function quoteLiquidity(address _liquidity, uint256 _amount) external view virtual override returns (uint256 _periodCredits) {</span>
<span class="cstat-no" title="statement not covered" > if (_approvedLiquidities.contains(_liquidity)) {</span>
<span class="cstat-no" title="statement not covered" > TickCache memory _tickCache = observeLiquidity(_liquidity);</span>
<span class="cstat-no" title="statement not covered" > if (_tickCache.period != 0) {</span>
<span class="cstat-no" title="statement not covered" > int56 _tickDifference = _isKP3RToken0[_liquidity] ? _tickCache.difference : -_tickCache.difference;</span>
<span class="cstat-no" title="statement not covered" > return _getReward(IKeep3rHelper(keep3rHelper).getKP3RsAtTick(_amount, _tickDifference, rewardPeriodTime));</span>
}
}
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function observeLiquidity(address _liquidity) public view virtual override returns (TickCache memory _tickCache) {</span>
<span class="cstat-no" title="statement not covered" > if (_tick[_liquidity].period == _period(block.timestamp)) {</span>
// Will return cached twaps if liquidity is updated
<span class="cstat-no" title="statement not covered" > _tickCache = _tick[_liquidity]</span>;
} else {
<span class="cstat-no" title="statement not covered" > bool success;</span>
<span class="cstat-no" title="statement not covered" > uint256 lastPeriod = _period(block.timestamp - rewardPeriodTime);</span>
<span class="cstat-no" title="statement not covered" > if (_tick[_liquidity].period == lastPeriod) {</span>
// Will only ask for current period accumulator if liquidity is outdated
<span class="cstat-no" title="statement not covered" > uint32[] memory _secondsAgo = new uint32[](1);</span>
<span class="cstat-no" title="statement not covered" > int56 previousTick = _tick[_liquidity].current;</span>
<span class="cstat-no" title="statement not covered" > _secondsAgo[0] = uint32(block.timestamp - _period(block.timestamp))</span>;
<span class="cstat-no" title="statement not covered" > (_tickCache.current, , success) = IKeep3rHelper(keep3rHelper).observe(_liquidityPool[_liquidity], _secondsAgo)</span>;
<span class="cstat-no" title="statement not covered" > _tickCache.difference = _tickCache.current - previousTick</span>;
} else <span class="cstat-no" title="statement not covered" >if (_tick[_liquidity].period < lastPeriod) {</span>
// Will ask for 2 accumulators if liquidity is expired
<span class="cstat-no" title="statement not covered" > uint32[] memory _secondsAgo = new uint32[](2);</span>
<span class="cstat-no" title="statement not covered" > _secondsAgo[0] = uint32(block.timestamp - _period(block.timestamp))</span>;
<span class="cstat-no" title="statement not covered" > _secondsAgo[1] = uint32(block.timestamp - _period(block.timestamp) + rewardPeriodTime)</span>;
<span class="cstat-no" title="statement not covered" > int56 _tickCumulative2;</span>
<span class="cstat-no" title="statement not covered" > (_tickCache.current, _tickCumulative2, success) = IKeep3rHelper(keep3rHelper).observe(_liquidityPool[_liquidity], _secondsAgo)</span>;
<span class="cstat-no" title="statement not covered" > _tickCache.difference = _tickCache.current - _tickCumulative2</span>;
}
<span class="cstat-no" title="statement not covered" > if (success) {</span>
<span class="cstat-no" title="statement not covered" > _tickCache.period = _period(block.timestamp)</span>;
} else {
<span class="cstat-no" title="statement not covered" > _tickCache.period = 0</span>;
}
}
}
// Methods
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function forceLiquidityCreditsToJob(address _job, uint256 _amount) external override onlyGovernance {</span>
<span class="cstat-no" title="statement not covered" > if (!_jobs.contains(_job)) revert JobUnavailable();</span>
<span class="cstat-no" title="statement not covered" > _settleJobAccountance(_job)</span>;
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] += _amount</span>;
<span class="cstat-no" title="statement not covered" > emit LiquidityCreditsForced(_job, rewardedAt[_job], _jobLiquidityCredits[_job]);</span>
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function approveLiquidity(address _liquidity) external virtual override onlyGovernance {</span>
<span class="cstat-no" title="statement not covered" > if (!_approvedLiquidities.add(_liquidity)) revert LiquidityPairApproved();</span>
<span class="cstat-no" title="statement not covered" > _liquidityPool[_liquidity] = IPairManager(_liquidity).pool()</span>;
<span class="cstat-no" title="statement not covered" > _isKP3RToken0[_liquidity] = IKeep3rHelper(keep3rHelper).isKP3RToken0(_liquidityPool[_liquidity])</span>;
<span class="cstat-no" title="statement not covered" > _tick[_liquidity] = observeLiquidity(_liquidity)</span>;
<span class="cstat-no" title="statement not covered" > emit LiquidityApproval(_liquidity);</span>
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function revokeLiquidity(address _liquidity) external override onlyGovernance {</span>
<span class="cstat-no" title="statement not covered" > if (!_approvedLiquidities.remove(_liquidity)) revert LiquidityPairUnexistent();</span>
<span class="cstat-no" title="statement not covered" > emit LiquidityRevocation(_liquidity);</span>
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function addLiquidityToJob(</span>
address _job,
address _liquidity,
uint256 _amount
) external override nonReentrant {
<span class="cstat-no" title="statement not covered" > if (!_approvedLiquidities.contains(_liquidity)) revert LiquidityPairUnapproved();</span>
<span class="cstat-no" title="statement not covered" > if (!_jobs.contains(_job)) revert JobUnavailable();</span>
<span class="cstat-no" title="statement not covered" > _jobLiquidities[_job].add(_liquidity)</span>;
<span class="cstat-no" title="statement not covered" > _settleJobAccountance(_job)</span>;
<span class="cstat-no" title="statement not covered" > if (_quoteLiquidity(liquidityAmount[_job][_liquidity] + _amount, _liquidity) < liquidityMinimum) revert JobLiquidityLessThanMin();</span>
<span class="cstat-no" title="statement not covered" > emit LiquidityCreditsReward(_job, rewardedAt[_job], _jobLiquidityCredits[_job], _jobPeriodCredits[_job]);</span>
<span class="cstat-no" title="statement not covered" > IERC20(_liquidity).safeTransferFrom(msg.sender, address(this), _amount)</span>;
<span class="cstat-no" title="statement not covered" > liquidityAmount[_job][_liquidity] += _amount</span>;
<span class="cstat-no" title="statement not covered" > _jobPeriodCredits[_job] += _getReward(_quoteLiquidity(_amount, _liquidity))</span>;
<span class="cstat-no" title="statement not covered" > emit LiquidityAddition(_job, _liquidity, msg.sender, _amount);</span>
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function unbondLiquidityFromJob(</span>
address _job,
address _liquidity,
uint256 _amount
) external override onlyJobOwner(_job) {
<span class="cstat-no" title="statement not covered" > canWithdrawAfter[_job][_liquidity] = block.timestamp + unbondTime</span>;
<span class="cstat-no" title="statement not covered" > pendingUnbonds[_job][_liquidity] += _amount</span>;
<span class="cstat-no" title="statement not covered" > _unbondLiquidityFromJob(_job, _liquidity, _amount)</span>;
<span class="cstat-no" title="statement not covered" > uint256 _remainingLiquidity = liquidityAmount[_job][_liquidity];</span>
<span class="cstat-no" title="statement not covered" > if (_remainingLiquidity > 0 && _quoteLiquidity(_remainingLiquidity, _liquidity) < liquidityMinimum) revert JobLiquidityLessThanMin();</span>
<span class="cstat-no" title="statement not covered" > emit Unbonding(_job, _liquidity, _amount);</span>
}
/// @inheritdoc IKeep3rJobFundableLiquidity
<span class="fstat-no" title="function not covered" > function withdrawLiquidityFromJob(</span>
address _job,
address _liquidity,
address _receiver
) external override onlyJobOwner(_job) {
<span class="cstat-no" title="statement not covered" > if (_receiver == address(0)) revert ZeroAddress();</span>
<span class="cstat-no" title="statement not covered" > if (canWithdrawAfter[_job][_liquidity] == 0) revert UnbondsUnexistent();</span>
<span class="cstat-no" title="statement not covered" > if (canWithdrawAfter[_job][_liquidity] >= block.timestamp) revert UnbondsLocked();</span>
<span class="cstat-no" title="statement not covered" > if (disputes[_job]) revert Disputed();</span>
<span class="cstat-no" title="statement not covered" > uint256 _amount = pendingUnbonds[_job][_liquidity];</span>
<span class="cstat-no" title="statement not covered" > IERC20(_liquidity).safeTransfer(_receiver, _amount)</span>;
<span class="cstat-no" title="statement not covered" > emit LiquidityWithdrawal(_job, _liquidity, _receiver, _amount);</span>
<span class="cstat-no" title="statement not covered" > pendingUnbonds[_job][_liquidity] = 0</span>;
}
// Internal functions
/// @notice Updates or rewards job liquidity credits depending on time since last job reward
<span class="fstat-no" title="function not covered" > function _updateJobCreditsIfNeeded(address _job) internal returns (bool _rewarded) {</span>
<span class="cstat-no" title="statement not covered" > if (rewardedAt[_job] < _period(block.timestamp)) {</span>
// Will exit function if job has been rewarded in current period
<span class="cstat-no" title="statement not covered" > if (rewardedAt[_job] <= _period(block.timestamp - rewardPeriodTime)) {</span>
// Will reset job to period syncronicity if a full period passed without rewards
<span class="cstat-no" title="statement not covered" > _updateJobPeriod(_job)</span>;
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] = _jobPeriodCredits[_job]</span>;
<span class="cstat-no" title="statement not covered" > rewardedAt[_job] = _period(block.timestamp)</span>;
<span class="cstat-no" title="statement not covered" > _rewarded = true</span>;
} else <span class="cstat-no" title="statement not covered" >if ((block.timestamp - rewardedAt[_job]) >= rewardPeriodTime) {</span>
// Will reset job's syncronicity if last reward was more than epoch ago
<span class="cstat-no" title="statement not covered" > _updateJobPeriod(_job)</span>;
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] = _jobPeriodCredits[_job]</span>;
<span class="cstat-no" title="statement not covered" > rewardedAt[_job] += rewardPeriodTime</span>;
<span class="cstat-no" title="statement not covered" > _rewarded = true</span>;
} else <span class="cstat-no" title="statement not covered" >if (workedAt[_job] < _period(block.timestamp)) {</span>
// First keeper on period has to update job accountance to current twaps
<span class="cstat-no" title="statement not covered" > uint256 previousPeriodCredits = _jobPeriodCredits[_job];</span>
<span class="cstat-no" title="statement not covered" > _updateJobPeriod(_job)</span>;
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] = (_jobLiquidityCredits[_job] * _jobPeriodCredits[_job]) / previousPeriodCredits</span>;
// Updating job accountance does not reward job
}
}
}
/// @notice Only called if _jobLiquidityCredits < payment
<span class="fstat-no" title="function not covered" > function _rewardJobCredits(address _job) internal {</span>
/// @notice Only way to += jobLiquidityCredits is when keeper rewarding (cannot pay work)
/* WARNING: this allows to top up _jobLiquidityCredits to a max of 1.99 but have to spend at least 1 */
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] += _phase(block.timestamp - rewardedAt[_job], _jobPeriodCredits[_job])</span>;
<span class="cstat-no" title="statement not covered" > rewardedAt[_job] = block.timestamp</span>;
}
/// @notice Updates accountance for _jobPeriodCredits
<span class="fstat-no" title="function not covered" > function _updateJobPeriod(address _job) internal {</span>
<span class="cstat-no" title="statement not covered" > _jobPeriodCredits[_job] = _calculateJobPeriodCredits(_job)</span>;
}
/// @notice Quotes the outdated job liquidities and calculates _periodCredits
/// @dev This function is also responsible for keeping the KP3R/WETH quote updated
<span class="fstat-no" title="function not covered" > function _calculateJobPeriodCredits(address _job) internal virtual returns (uint256 _periodCredits) {</span>
<span class="cstat-no" title="statement not covered" > if (_tick[kp3rWethPool].period != _period(block.timestamp)) {</span>
// Updates KP3R/WETH quote if needed
<span class="cstat-no" title="statement not covered" > _tick[kp3rWethPool] = observeLiquidity(kp3rWethPool)</span>;
}
<span class="cstat-no" title="statement not covered" > for (uint256 i; i < _jobLiquidities[_job].length(); i++) {</span>
<span class="cstat-no" title="statement not covered" > address _liquidity = _jobLiquidities[_job].at(i);</span>
<span class="cstat-no" title="statement not covered" > if (_approvedLiquidities.contains(_liquidity)) {</span>
<span class="cstat-no" title="statement not covered" > if (_tick[_liquidity].period != _period(block.timestamp)) {</span>
// Updates liquidity cache only if needed
<span class="cstat-no" title="statement not covered" > _tick[_liquidity] = observeLiquidity(_liquidity)</span>;
}
<span class="cstat-no" title="statement not covered" > _periodCredits += _getReward(_quoteLiquidity(liquidityAmount[_job][_liquidity], _liquidity))</span>;
}
}
}
/// @notice Updates job accountance calculating the impact of the unbonded liquidity amount
<span class="fstat-no" title="function not covered" > function _unbondLiquidityFromJob(</span>
address _job,
address _liquidity,
uint256 _amount
) internal nonReentrant {
<span class="cstat-no" title="statement not covered" > if (!_jobLiquidities[_job].contains(_liquidity)) revert JobLiquidityUnexistent();</span>
<span class="cstat-no" title="statement not covered" > if (liquidityAmount[_job][_liquidity] < _amount) revert JobLiquidityInsufficient();</span>
// Ensures current twaps in job liquidities
<span class="cstat-no" title="statement not covered" > _updateJobPeriod(_job)</span>;
<span class="cstat-no" title="statement not covered" > uint256 _periodCreditsToRemove = _getReward(_quoteLiquidity(_amount, _liquidity));</span>
// A liquidity can be revoked causing a job to have 0 periodCredits
<span class="cstat-no" title="statement not covered" > if (_jobPeriodCredits[_job] > 0) {</span>
// Removes a % correspondant to a full rewardPeriodTime for the liquidity withdrawn vs all of the liquidities
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] -= (_jobLiquidityCredits[_job] * _periodCreditsToRemove) / _jobPeriodCredits[_job]</span>;
<span class="cstat-no" title="statement not covered" > _jobPeriodCredits[_job] -= _periodCreditsToRemove</span>;
}
<span class="cstat-no" title="statement not covered" > liquidityAmount[_job][_liquidity] -= _amount</span>;
<span class="cstat-no" title="statement not covered" > if (liquidityAmount[_job][_liquidity] == 0) {</span>
<span class="cstat-no" title="statement not covered" > _jobLiquidities[_job].remove(_liquidity)</span>;
}
}
/// @notice Returns a fraction of the multiplier or the whole multiplier if equal or more than a rewardPeriodTime has passed
<span class="fstat-no" title="function not covered" > function _phase(uint256 _timePassed, uint256 _multiplier) internal view returns (uint256 _result) {</span>
<span class="cstat-no" title="statement not covered" > if (_timePassed < rewardPeriodTime) {</span>
<span class="cstat-no" title="statement not covered" > _result = (_timePassed * _multiplier) / rewardPeriodTime</span>;
} else <span class="cstat-no" title="statement not covered" >_result = _multiplier</span>;
}
/// @notice Returns the start of the period of the provided timestamp
<span class="fstat-no" title="function not covered" > function _period(uint256 _timestamp) internal view returns (uint256 _periodTimestamp) {</span>
<span class="cstat-no" title="statement not covered" > return _timestamp - (_timestamp % rewardPeriodTime);</span>
}
/// @notice Calculates relation between rewardPeriod and inflationPeriod
<span class="fstat-no" title="function not covered" > function _getReward(uint256 _baseAmount) internal view returns (uint256 _credits) {</span>
<span class="cstat-no" title="statement not covered" > return FullMath.mulDiv(_baseAmount, rewardPeriodTime, inflationPeriod);</span>
}
/// @notice Returns underlying KP3R amount for a given liquidity amount
<span class="fstat-no" title="function not covered" > function _quoteLiquidity(uint256 _amount, address _liquidity) internal view virtual returns (uint256 _quote) {</span>
<span class="cstat-no" title="statement not covered" > if (_tick[_liquidity].period != 0) {</span>
<span class="cstat-no" title="statement not covered" > int56 _tickDifference = _isKP3RToken0[_liquidity] ? _tick[_liquidity].difference : -_tick[_liquidity].difference;</span>
<span class="cstat-no" title="statement not covered" > _quote = IKeep3rHelper(keep3rHelper).getKP3RsAtTick(_amount, _tickDifference, rewardPeriodTime)</span>;
}
}
/// @notice Returns KP3R amount for a given ETH amount
<span class="fstat-no" title="function not covered" > function _quoteKp3rs(uint256 _eth) internal view virtual returns (uint256 _amountOut) {</span>
<span class="cstat-no" title="statement not covered" > int56 _tickDifference = _isKP3RToken0[kp3rWethPool] ? _tick[kp3rWethPool].difference : -_tick[kp3rWethPool].difference;</span>
<span class="cstat-no" title="statement not covered" > _amountOut = IKeep3rHelper(keep3rHelper).getQuoteAtTick(uint128(_eth), _tickDifference, rewardPeriodTime)</span>;
}
/// @notice Updates job credits to current quotes and rewards job's pending minted credits
/// @dev Ensures a maximum of 1 period of credits
<span class="fstat-no" title="function not covered" > function _settleJobAccountance(address _job) internal virtual {</span>
<span class="cstat-no" title="statement not covered" > _updateJobCreditsIfNeeded(_job)</span>;
<span class="cstat-no" title="statement not covered" > _rewardJobCredits(_job)</span>;
<span class="cstat-no" title="statement not covered" > _jobLiquidityCredits[_job] = Math.min(_jobLiquidityCredits[_job], _jobPeriodCredits[_job])</span>;
}
}
</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Fri May 20 2022 12:16:04 GMT+0200 (Central European Summer Time)
</div>
</div>
<script src="../../../prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="../../../sorter.js"></script>
</body>
</html>