@openzeppelin/confidential-contracts 0.2.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +24 -0
  2. package/build/contracts/Checkpoints.json +16 -0
  3. package/build/contracts/CheckpointsConfidential.json +16 -0
  4. package/build/contracts/ConfidentialFungibleToken.json +614 -0
  5. package/build/contracts/ConfidentialFungibleTokenERC20Wrapper.json +793 -0
  6. package/build/contracts/ConfidentialFungibleTokenUtils.json +10 -0
  7. package/build/contracts/ConfidentialFungibleTokenVotes.json +1002 -0
  8. package/build/contracts/ERC7821WithExecutor.json +145 -0
  9. package/build/contracts/IConfidentialFungibleToken.json +458 -0
  10. package/build/contracts/IConfidentialFungibleTokenReceiver.json +45 -0
  11. package/build/contracts/TFHESafeMath.json +10 -0
  12. package/build/contracts/VestingWalletCliffConfidential.json +275 -0
  13. package/build/contracts/VestingWalletCliffExecutorConfidential.json +424 -0
  14. package/build/contracts/VestingWalletCliffExecutorConfidentialFactory.json +290 -0
  15. package/build/contracts/VestingWalletConfidential.json +246 -0
  16. package/build/contracts/VotesConfidential.json +412 -0
  17. package/finance/ERC7821WithExecutor.sol +46 -0
  18. package/finance/VestingWalletCliffConfidential.sol +62 -0
  19. package/finance/VestingWalletCliffExecutorConfidentialFactory.sol +203 -0
  20. package/finance/VestingWalletConfidential.sol +130 -0
  21. package/governance/utils/VotesConfidential.sol +202 -0
  22. package/interfaces/IConfidentialFungibleToken.sol +135 -0
  23. package/interfaces/IConfidentialFungibleTokenReceiver.sol +19 -0
  24. package/package.json +39 -0
  25. package/token/ConfidentialFungibleToken.sol +314 -0
  26. package/token/extensions/ConfidentialFungibleTokenERC20Wrapper.sol +175 -0
  27. package/token/extensions/ConfidentialFungibleTokenVotes.sol +29 -0
  28. package/token/utils/ConfidentialFungibleTokenUtils.sol +46 -0
  29. package/utils/TFHESafeMath.sol +37 -0
  30. package/utils/structs/CheckpointsConfidential.sol +193 -0
  31. package/utils/structs/temporary-Checkpoints.sol +835 -0
@@ -0,0 +1,835 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // OpenZeppelin Confidential Contracts (last updated v0.2.0-rc.1) (utils/structs/temporary-Checkpoints.sol)
3
+ // OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/Checkpoints.sol)
4
+ // This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
5
+ // WARNING: This file is temporary and will be deleted once the latest version of the file is released in v5.5.0 of @openzeppelin/contracts.
6
+
7
+ pragma solidity ^0.8.20;
8
+
9
+ import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
10
+
11
+ /**
12
+ * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
13
+ * time, and later looking up past values by block number. See {Votes} as an example.
14
+ *
15
+ * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
16
+ * checkpoint for the current transaction block using the {push} function.
17
+ */
18
+ library Checkpoints {
19
+ /**
20
+ * @dev A value was attempted to be inserted on a past checkpoint.
21
+ */
22
+ error CheckpointUnorderedInsertion();
23
+
24
+ struct Trace256 {
25
+ Checkpoint256[] _checkpoints;
26
+ }
27
+
28
+ struct Checkpoint256 {
29
+ uint256 _key;
30
+ uint256 _value;
31
+ }
32
+
33
+ /**
34
+ * @dev Pushes a (`key`, `value`) pair into a Trace256 so that it is stored as the checkpoint.
35
+ *
36
+ * Returns previous value and new value.
37
+ *
38
+ * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint256).max` key set will disable the
39
+ * library.
40
+ */
41
+ function push(
42
+ Trace256 storage self,
43
+ uint256 key,
44
+ uint256 value
45
+ ) internal returns (uint256 oldValue, uint256 newValue) {
46
+ return _insert(self._checkpoints, key, value);
47
+ }
48
+
49
+ /**
50
+ * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
51
+ * there is none.
52
+ */
53
+ function lowerLookup(Trace256 storage self, uint256 key) internal view returns (uint256) {
54
+ uint256 len = self._checkpoints.length;
55
+ uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
56
+ return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
57
+ }
58
+
59
+ /**
60
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
61
+ * if there is none.
62
+ */
63
+ function upperLookup(Trace256 storage self, uint256 key) internal view returns (uint256) {
64
+ uint256 len = self._checkpoints.length;
65
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
66
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
67
+ }
68
+
69
+ /**
70
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
71
+ * if there is none.
72
+ *
73
+ * NOTE: This is a variant of {upperLookup} that is optimized to find "recent" checkpoint (checkpoints with high
74
+ * keys).
75
+ */
76
+ function upperLookupRecent(Trace256 storage self, uint256 key) internal view returns (uint256) {
77
+ uint256 len = self._checkpoints.length;
78
+
79
+ uint256 low = 0;
80
+ uint256 high = len;
81
+
82
+ if (len > 5) {
83
+ uint256 mid = len - Math.sqrt(len);
84
+ if (key < _unsafeAccess(self._checkpoints, mid)._key) {
85
+ high = mid;
86
+ } else {
87
+ low = mid + 1;
88
+ }
89
+ }
90
+
91
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
92
+
93
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
94
+ }
95
+
96
+ /**
97
+ * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
98
+ */
99
+ function latest(Trace256 storage self) internal view returns (uint256) {
100
+ uint256 pos = self._checkpoints.length;
101
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
102
+ }
103
+
104
+ /**
105
+ * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
106
+ * in the most recent checkpoint.
107
+ */
108
+ function latestCheckpoint(Trace256 storage self) internal view returns (bool exists, uint256 _key, uint256 _value) {
109
+ uint256 pos = self._checkpoints.length;
110
+ if (pos == 0) {
111
+ return (false, 0, 0);
112
+ } else {
113
+ Checkpoint256 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
114
+ return (true, ckpt._key, ckpt._value);
115
+ }
116
+ }
117
+
118
+ /**
119
+ * @dev Returns the number of checkpoints.
120
+ */
121
+ function length(Trace256 storage self) internal view returns (uint256) {
122
+ return self._checkpoints.length;
123
+ }
124
+
125
+ /**
126
+ * @dev Returns checkpoint at given position.
127
+ */
128
+ function at(Trace256 storage self, uint32 pos) internal view returns (Checkpoint256 memory) {
129
+ return self._checkpoints[pos];
130
+ }
131
+
132
+ /**
133
+ * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
134
+ * or by updating the last one.
135
+ */
136
+ function _insert(
137
+ Checkpoint256[] storage self,
138
+ uint256 key,
139
+ uint256 value
140
+ ) private returns (uint256 oldValue, uint256 newValue) {
141
+ uint256 pos = self.length;
142
+
143
+ if (pos > 0) {
144
+ Checkpoint256 storage last = _unsafeAccess(self, pos - 1);
145
+ uint256 lastKey = last._key;
146
+ uint256 lastValue = last._value;
147
+
148
+ // Checkpoint keys must be non-decreasing.
149
+ if (lastKey > key) {
150
+ revert CheckpointUnorderedInsertion();
151
+ }
152
+
153
+ // Update or push new checkpoint
154
+ if (lastKey == key) {
155
+ last._value = value;
156
+ } else {
157
+ self.push(Checkpoint256({_key: key, _value: value}));
158
+ }
159
+ return (lastValue, value);
160
+ } else {
161
+ self.push(Checkpoint256({_key: key, _value: value}));
162
+ return (0, value);
163
+ }
164
+ }
165
+
166
+ /**
167
+ * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high`
168
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
169
+ * `high`.
170
+ *
171
+ * WARNING: `high` should not be greater than the array's length.
172
+ */
173
+ function _upperBinaryLookup(
174
+ Checkpoint256[] storage self,
175
+ uint256 key,
176
+ uint256 low,
177
+ uint256 high
178
+ ) private view returns (uint256) {
179
+ while (low < high) {
180
+ uint256 mid = Math.average(low, high);
181
+ if (_unsafeAccess(self, mid)._key > key) {
182
+ high = mid;
183
+ } else {
184
+ low = mid + 1;
185
+ }
186
+ }
187
+ return high;
188
+ }
189
+
190
+ /**
191
+ * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high`
192
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
193
+ * `high`.
194
+ *
195
+ * WARNING: `high` should not be greater than the array's length.
196
+ */
197
+ function _lowerBinaryLookup(
198
+ Checkpoint256[] storage self,
199
+ uint256 key,
200
+ uint256 low,
201
+ uint256 high
202
+ ) private view returns (uint256) {
203
+ while (low < high) {
204
+ uint256 mid = Math.average(low, high);
205
+ if (_unsafeAccess(self, mid)._key < key) {
206
+ low = mid + 1;
207
+ } else {
208
+ high = mid;
209
+ }
210
+ }
211
+ return high;
212
+ }
213
+
214
+ /**
215
+ * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
216
+ */
217
+ function _unsafeAccess(
218
+ Checkpoint256[] storage self,
219
+ uint256 pos
220
+ ) private pure returns (Checkpoint256 storage result) {
221
+ assembly {
222
+ mstore(0, self.slot)
223
+ result.slot := add(keccak256(0, 0x20), mul(pos, 2))
224
+ }
225
+ }
226
+
227
+ struct Trace224 {
228
+ Checkpoint224[] _checkpoints;
229
+ }
230
+
231
+ struct Checkpoint224 {
232
+ uint32 _key;
233
+ uint224 _value;
234
+ }
235
+
236
+ /**
237
+ * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
238
+ *
239
+ * Returns previous value and new value.
240
+ *
241
+ * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the
242
+ * library.
243
+ */
244
+ function push(
245
+ Trace224 storage self,
246
+ uint32 key,
247
+ uint224 value
248
+ ) internal returns (uint224 oldValue, uint224 newValue) {
249
+ return _insert(self._checkpoints, key, value);
250
+ }
251
+
252
+ /**
253
+ * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
254
+ * there is none.
255
+ */
256
+ function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
257
+ uint256 len = self._checkpoints.length;
258
+ uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
259
+ return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
260
+ }
261
+
262
+ /**
263
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
264
+ * if there is none.
265
+ */
266
+ function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
267
+ uint256 len = self._checkpoints.length;
268
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
269
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
270
+ }
271
+
272
+ /**
273
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
274
+ * if there is none.
275
+ *
276
+ * NOTE: This is a variant of {upperLookup} that is optimized to find "recent" checkpoint (checkpoints with high
277
+ * keys).
278
+ */
279
+ function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) {
280
+ uint256 len = self._checkpoints.length;
281
+
282
+ uint256 low = 0;
283
+ uint256 high = len;
284
+
285
+ if (len > 5) {
286
+ uint256 mid = len - Math.sqrt(len);
287
+ if (key < _unsafeAccess(self._checkpoints, mid)._key) {
288
+ high = mid;
289
+ } else {
290
+ low = mid + 1;
291
+ }
292
+ }
293
+
294
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
295
+
296
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
297
+ }
298
+
299
+ /**
300
+ * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
301
+ */
302
+ function latest(Trace224 storage self) internal view returns (uint224) {
303
+ uint256 pos = self._checkpoints.length;
304
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
305
+ }
306
+
307
+ /**
308
+ * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
309
+ * in the most recent checkpoint.
310
+ */
311
+ function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
312
+ uint256 pos = self._checkpoints.length;
313
+ if (pos == 0) {
314
+ return (false, 0, 0);
315
+ } else {
316
+ Checkpoint224 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
317
+ return (true, ckpt._key, ckpt._value);
318
+ }
319
+ }
320
+
321
+ /**
322
+ * @dev Returns the number of checkpoints.
323
+ */
324
+ function length(Trace224 storage self) internal view returns (uint256) {
325
+ return self._checkpoints.length;
326
+ }
327
+
328
+ /**
329
+ * @dev Returns checkpoint at given position.
330
+ */
331
+ function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
332
+ return self._checkpoints[pos];
333
+ }
334
+
335
+ /**
336
+ * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
337
+ * or by updating the last one.
338
+ */
339
+ function _insert(
340
+ Checkpoint224[] storage self,
341
+ uint32 key,
342
+ uint224 value
343
+ ) private returns (uint224 oldValue, uint224 newValue) {
344
+ uint256 pos = self.length;
345
+
346
+ if (pos > 0) {
347
+ Checkpoint224 storage last = _unsafeAccess(self, pos - 1);
348
+ uint32 lastKey = last._key;
349
+ uint224 lastValue = last._value;
350
+
351
+ // Checkpoint keys must be non-decreasing.
352
+ if (lastKey > key) {
353
+ revert CheckpointUnorderedInsertion();
354
+ }
355
+
356
+ // Update or push new checkpoint
357
+ if (lastKey == key) {
358
+ last._value = value;
359
+ } else {
360
+ self.push(Checkpoint224({_key: key, _value: value}));
361
+ }
362
+ return (lastValue, value);
363
+ } else {
364
+ self.push(Checkpoint224({_key: key, _value: value}));
365
+ return (0, value);
366
+ }
367
+ }
368
+
369
+ /**
370
+ * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high`
371
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
372
+ * `high`.
373
+ *
374
+ * WARNING: `high` should not be greater than the array's length.
375
+ */
376
+ function _upperBinaryLookup(
377
+ Checkpoint224[] storage self,
378
+ uint32 key,
379
+ uint256 low,
380
+ uint256 high
381
+ ) private view returns (uint256) {
382
+ while (low < high) {
383
+ uint256 mid = Math.average(low, high);
384
+ if (_unsafeAccess(self, mid)._key > key) {
385
+ high = mid;
386
+ } else {
387
+ low = mid + 1;
388
+ }
389
+ }
390
+ return high;
391
+ }
392
+
393
+ /**
394
+ * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high`
395
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
396
+ * `high`.
397
+ *
398
+ * WARNING: `high` should not be greater than the array's length.
399
+ */
400
+ function _lowerBinaryLookup(
401
+ Checkpoint224[] storage self,
402
+ uint32 key,
403
+ uint256 low,
404
+ uint256 high
405
+ ) private view returns (uint256) {
406
+ while (low < high) {
407
+ uint256 mid = Math.average(low, high);
408
+ if (_unsafeAccess(self, mid)._key < key) {
409
+ low = mid + 1;
410
+ } else {
411
+ high = mid;
412
+ }
413
+ }
414
+ return high;
415
+ }
416
+
417
+ /**
418
+ * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
419
+ */
420
+ function _unsafeAccess(
421
+ Checkpoint224[] storage self,
422
+ uint256 pos
423
+ ) private pure returns (Checkpoint224 storage result) {
424
+ assembly {
425
+ mstore(0, self.slot)
426
+ result.slot := add(keccak256(0, 0x20), pos)
427
+ }
428
+ }
429
+
430
+ struct Trace208 {
431
+ Checkpoint208[] _checkpoints;
432
+ }
433
+
434
+ struct Checkpoint208 {
435
+ uint48 _key;
436
+ uint208 _value;
437
+ }
438
+
439
+ /**
440
+ * @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
441
+ *
442
+ * Returns previous value and new value.
443
+ *
444
+ * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the
445
+ * library.
446
+ */
447
+ function push(
448
+ Trace208 storage self,
449
+ uint48 key,
450
+ uint208 value
451
+ ) internal returns (uint208 oldValue, uint208 newValue) {
452
+ return _insert(self._checkpoints, key, value);
453
+ }
454
+
455
+ /**
456
+ * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
457
+ * there is none.
458
+ */
459
+ function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
460
+ uint256 len = self._checkpoints.length;
461
+ uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
462
+ return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
463
+ }
464
+
465
+ /**
466
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
467
+ * if there is none.
468
+ */
469
+ function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
470
+ uint256 len = self._checkpoints.length;
471
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
472
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
473
+ }
474
+
475
+ /**
476
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
477
+ * if there is none.
478
+ *
479
+ * NOTE: This is a variant of {upperLookup} that is optimized to find "recent" checkpoint (checkpoints with high
480
+ * keys).
481
+ */
482
+ function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) {
483
+ uint256 len = self._checkpoints.length;
484
+
485
+ uint256 low = 0;
486
+ uint256 high = len;
487
+
488
+ if (len > 5) {
489
+ uint256 mid = len - Math.sqrt(len);
490
+ if (key < _unsafeAccess(self._checkpoints, mid)._key) {
491
+ high = mid;
492
+ } else {
493
+ low = mid + 1;
494
+ }
495
+ }
496
+
497
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
498
+
499
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
500
+ }
501
+
502
+ /**
503
+ * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
504
+ */
505
+ function latest(Trace208 storage self) internal view returns (uint208) {
506
+ uint256 pos = self._checkpoints.length;
507
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
508
+ }
509
+
510
+ /**
511
+ * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
512
+ * in the most recent checkpoint.
513
+ */
514
+ function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) {
515
+ uint256 pos = self._checkpoints.length;
516
+ if (pos == 0) {
517
+ return (false, 0, 0);
518
+ } else {
519
+ Checkpoint208 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
520
+ return (true, ckpt._key, ckpt._value);
521
+ }
522
+ }
523
+
524
+ /**
525
+ * @dev Returns the number of checkpoints.
526
+ */
527
+ function length(Trace208 storage self) internal view returns (uint256) {
528
+ return self._checkpoints.length;
529
+ }
530
+
531
+ /**
532
+ * @dev Returns checkpoint at given position.
533
+ */
534
+ function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) {
535
+ return self._checkpoints[pos];
536
+ }
537
+
538
+ /**
539
+ * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
540
+ * or by updating the last one.
541
+ */
542
+ function _insert(
543
+ Checkpoint208[] storage self,
544
+ uint48 key,
545
+ uint208 value
546
+ ) private returns (uint208 oldValue, uint208 newValue) {
547
+ uint256 pos = self.length;
548
+
549
+ if (pos > 0) {
550
+ Checkpoint208 storage last = _unsafeAccess(self, pos - 1);
551
+ uint48 lastKey = last._key;
552
+ uint208 lastValue = last._value;
553
+
554
+ // Checkpoint keys must be non-decreasing.
555
+ if (lastKey > key) {
556
+ revert CheckpointUnorderedInsertion();
557
+ }
558
+
559
+ // Update or push new checkpoint
560
+ if (lastKey == key) {
561
+ last._value = value;
562
+ } else {
563
+ self.push(Checkpoint208({_key: key, _value: value}));
564
+ }
565
+ return (lastValue, value);
566
+ } else {
567
+ self.push(Checkpoint208({_key: key, _value: value}));
568
+ return (0, value);
569
+ }
570
+ }
571
+
572
+ /**
573
+ * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high`
574
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
575
+ * `high`.
576
+ *
577
+ * WARNING: `high` should not be greater than the array's length.
578
+ */
579
+ function _upperBinaryLookup(
580
+ Checkpoint208[] storage self,
581
+ uint48 key,
582
+ uint256 low,
583
+ uint256 high
584
+ ) private view returns (uint256) {
585
+ while (low < high) {
586
+ uint256 mid = Math.average(low, high);
587
+ if (_unsafeAccess(self, mid)._key > key) {
588
+ high = mid;
589
+ } else {
590
+ low = mid + 1;
591
+ }
592
+ }
593
+ return high;
594
+ }
595
+
596
+ /**
597
+ * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high`
598
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
599
+ * `high`.
600
+ *
601
+ * WARNING: `high` should not be greater than the array's length.
602
+ */
603
+ function _lowerBinaryLookup(
604
+ Checkpoint208[] storage self,
605
+ uint48 key,
606
+ uint256 low,
607
+ uint256 high
608
+ ) private view returns (uint256) {
609
+ while (low < high) {
610
+ uint256 mid = Math.average(low, high);
611
+ if (_unsafeAccess(self, mid)._key < key) {
612
+ low = mid + 1;
613
+ } else {
614
+ high = mid;
615
+ }
616
+ }
617
+ return high;
618
+ }
619
+
620
+ /**
621
+ * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
622
+ */
623
+ function _unsafeAccess(
624
+ Checkpoint208[] storage self,
625
+ uint256 pos
626
+ ) private pure returns (Checkpoint208 storage result) {
627
+ assembly {
628
+ mstore(0, self.slot)
629
+ result.slot := add(keccak256(0, 0x20), pos)
630
+ }
631
+ }
632
+
633
+ struct Trace160 {
634
+ Checkpoint160[] _checkpoints;
635
+ }
636
+
637
+ struct Checkpoint160 {
638
+ uint96 _key;
639
+ uint160 _value;
640
+ }
641
+
642
+ /**
643
+ * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
644
+ *
645
+ * Returns previous value and new value.
646
+ *
647
+ * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the
648
+ * library.
649
+ */
650
+ function push(
651
+ Trace160 storage self,
652
+ uint96 key,
653
+ uint160 value
654
+ ) internal returns (uint160 oldValue, uint160 newValue) {
655
+ return _insert(self._checkpoints, key, value);
656
+ }
657
+
658
+ /**
659
+ * @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
660
+ * there is none.
661
+ */
662
+ function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
663
+ uint256 len = self._checkpoints.length;
664
+ uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
665
+ return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
666
+ }
667
+
668
+ /**
669
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
670
+ * if there is none.
671
+ */
672
+ function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
673
+ uint256 len = self._checkpoints.length;
674
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
675
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
676
+ }
677
+
678
+ /**
679
+ * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
680
+ * if there is none.
681
+ *
682
+ * NOTE: This is a variant of {upperLookup} that is optimized to find "recent" checkpoint (checkpoints with high
683
+ * keys).
684
+ */
685
+ function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) {
686
+ uint256 len = self._checkpoints.length;
687
+
688
+ uint256 low = 0;
689
+ uint256 high = len;
690
+
691
+ if (len > 5) {
692
+ uint256 mid = len - Math.sqrt(len);
693
+ if (key < _unsafeAccess(self._checkpoints, mid)._key) {
694
+ high = mid;
695
+ } else {
696
+ low = mid + 1;
697
+ }
698
+ }
699
+
700
+ uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
701
+
702
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
703
+ }
704
+
705
+ /**
706
+ * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
707
+ */
708
+ function latest(Trace160 storage self) internal view returns (uint160) {
709
+ uint256 pos = self._checkpoints.length;
710
+ return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
711
+ }
712
+
713
+ /**
714
+ * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
715
+ * in the most recent checkpoint.
716
+ */
717
+ function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
718
+ uint256 pos = self._checkpoints.length;
719
+ if (pos == 0) {
720
+ return (false, 0, 0);
721
+ } else {
722
+ Checkpoint160 storage ckpt = _unsafeAccess(self._checkpoints, pos - 1);
723
+ return (true, ckpt._key, ckpt._value);
724
+ }
725
+ }
726
+
727
+ /**
728
+ * @dev Returns the number of checkpoints.
729
+ */
730
+ function length(Trace160 storage self) internal view returns (uint256) {
731
+ return self._checkpoints.length;
732
+ }
733
+
734
+ /**
735
+ * @dev Returns checkpoint at given position.
736
+ */
737
+ function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) {
738
+ return self._checkpoints[pos];
739
+ }
740
+
741
+ /**
742
+ * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
743
+ * or by updating the last one.
744
+ */
745
+ function _insert(
746
+ Checkpoint160[] storage self,
747
+ uint96 key,
748
+ uint160 value
749
+ ) private returns (uint160 oldValue, uint160 newValue) {
750
+ uint256 pos = self.length;
751
+
752
+ if (pos > 0) {
753
+ Checkpoint160 storage last = _unsafeAccess(self, pos - 1);
754
+ uint96 lastKey = last._key;
755
+ uint160 lastValue = last._value;
756
+
757
+ // Checkpoint keys must be non-decreasing.
758
+ if (lastKey > key) {
759
+ revert CheckpointUnorderedInsertion();
760
+ }
761
+
762
+ // Update or push new checkpoint
763
+ if (lastKey == key) {
764
+ last._value = value;
765
+ } else {
766
+ self.push(Checkpoint160({_key: key, _value: value}));
767
+ }
768
+ return (lastValue, value);
769
+ } else {
770
+ self.push(Checkpoint160({_key: key, _value: value}));
771
+ return (0, value);
772
+ }
773
+ }
774
+
775
+ /**
776
+ * @dev Return the index of the first (oldest) checkpoint with key strictly bigger than the search key, or `high`
777
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
778
+ * `high`.
779
+ *
780
+ * WARNING: `high` should not be greater than the array's length.
781
+ */
782
+ function _upperBinaryLookup(
783
+ Checkpoint160[] storage self,
784
+ uint96 key,
785
+ uint256 low,
786
+ uint256 high
787
+ ) private view returns (uint256) {
788
+ while (low < high) {
789
+ uint256 mid = Math.average(low, high);
790
+ if (_unsafeAccess(self, mid)._key > key) {
791
+ high = mid;
792
+ } else {
793
+ low = mid + 1;
794
+ }
795
+ }
796
+ return high;
797
+ }
798
+
799
+ /**
800
+ * @dev Return the index of the first (oldest) checkpoint with key greater or equal than the search key, or `high`
801
+ * if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
802
+ * `high`.
803
+ *
804
+ * WARNING: `high` should not be greater than the array's length.
805
+ */
806
+ function _lowerBinaryLookup(
807
+ Checkpoint160[] storage self,
808
+ uint96 key,
809
+ uint256 low,
810
+ uint256 high
811
+ ) private view returns (uint256) {
812
+ while (low < high) {
813
+ uint256 mid = Math.average(low, high);
814
+ if (_unsafeAccess(self, mid)._key < key) {
815
+ low = mid + 1;
816
+ } else {
817
+ high = mid;
818
+ }
819
+ }
820
+ return high;
821
+ }
822
+
823
+ /**
824
+ * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
825
+ */
826
+ function _unsafeAccess(
827
+ Checkpoint160[] storage self,
828
+ uint256 pos
829
+ ) private pure returns (Checkpoint160 storage result) {
830
+ assembly {
831
+ mstore(0, self.slot)
832
+ result.slot := add(keccak256(0, 0x20), pos)
833
+ }
834
+ }
835
+ }