-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathLibProvingPeriod.sol
More file actions
145 lines (128 loc) · 6.99 KB
/
Copy pathLibProvingPeriod.sol
File metadata and controls
145 lines (128 loc) · 6.99 KB
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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {LibPercentage} from "../libs/LibPercentage.sol";
import "@openzeppelin/contracts/utils/math/SafeCast.sol";
/// Each proving period is defined by
/// - the _prover_ address that must post proofs for any publications received during this period
/// - the standard proving _fee_ that the prover charges per publication in this period
/// - the delayed proving fee that the prover charges per delayed publication in this period
/// - this is defined as a percentage (_delayedFeePercentage_) of the standard proving fee
/// The prover must lock some _stake_ that can be slashed if they fail to post a proof in a timely manner.
/// Proving periods are open-ended, meaning that they can be Open for an indefinite amount of time.
/// The period is Closed when the prover is outbid, chooses to leave, or is evicted for failing to prove.
/// At this point, the _end_ timestamp is set but the period is still Active. The prover is still required to
/// prove any publications received until the end timestamp is reached, when the period is Complete.
/// All publications in the period must be proven by the _deadline_, which should be after the end timestamp.
/// The prover can then withdraw their remaining stake, and the period is Finalized.
/// If a prover misses the deadline, anyone can prove outstanding publications on their behalf. In this case, the
/// _pastDeadline_ flag is set and the address that completes the outstanding proofs receives a fraction of the stake.
library LibProvingPeriod {
using LibPercentage for uint96;
using SafeCast for uint256;
struct Period {
// SLOT 1
address prover;
uint96 stake;
// SLOT 2
// the fee that the prover is willing to charge for proving each publication
uint96 fee;
// the percentage (with two decimals precision) of the fee that is charged for delayed publications.
uint16 delayedFeePercentage;
// the timestamp of the end of the period. Default to zero while the period is open.
uint40 end;
// the time by which the prover needs to submit the final proof
uint40 deadline;
// whether the final proof came after the deadline
bool pastDeadline;
}
/// @dev Initializes the period with the given parameters.
/// @dev The _end_ and _deadline_ default to zero. The _pastDeadline_ flag defaults to false.
/// @dev This can be called multiple times to set the latest bid while the auction is ongoing.
function init(Period storage period, address prover, uint96 fee, uint16 delayedFeePercentage, uint96 stake)
internal
{
require(prover != address(0), "Prover cannot be zero address");
period.prover = prover;
period.fee = fee;
period.delayedFeePercentage = delayedFeePercentage;
period.stake = stake;
}
/// @dev Whether the period has been initialised
function isInitialized(Period storage period) internal view returns (bool) {
return period.prover != address(0);
}
/// @dev The period has an end timestamp in the past
function isComplete(Period storage period) internal view returns (bool) {
return isBefore(period, block.timestamp);
}
/// @dev The period fee, scaled by `delayedFeePercentage` if the publication is delayed
function publicationFee(Period storage period, bool isDelayed) internal view returns (uint96) {
return isDelayed ? period.fee.scaleByPercentage(period.delayedFeePercentage) : period.fee;
}
/// @dev The period has no end timestamp
function isOpen(Period storage period) internal view returns (bool) {
return period.end == 0;
}
/// @dev The timestamp is after the end of the period (which must be set)
function isBefore(Period storage period, uint256 timestamp) internal view returns (bool) {
return period.end != 0 && timestamp > period.end;
}
/// @dev The timestamp is not after the end of the period
function isNotBefore(Period storage period, uint256 timestamp) internal view returns (bool) {
return !isBefore(period, timestamp);
}
/// @dev The period has a deadline timestamp in the past
function isDeadlinePassed(Period storage period) internal view returns (bool) {
return block.timestamp > period.deadline && period.deadline != 0;
}
/// @dev Whether the period is vacant (i.e. not initialised and open)
function isVacant(Period storage period) internal view returns (bool) {
return !isInitialized(period) && isOpen(period);
}
/// @dev Returns total fee earned by the period
/// @param numPublications The number of publications in the period
/// @param numDelayedPublications The number of delayed publications in the period
function totalFeeEarned(Period storage period, uint256 numPublications, uint256 numDelayedPublications)
internal
view
returns (uint96)
{
uint256 standardFee = publicationFee(period, false) * (numPublications - numDelayedPublications);
uint256 delayedFee = publicationFee(period, true) * numDelayedPublications;
return (standardFee + delayedFee).toUint96();
}
/// @dev Sets the period's end and deadline timestamps
/// @param period The period to finalize
/// @param endDelay The duration (from now) when the period will end
/// @param provingWindow The duration that proofs can be submitted after the end of the period
/// @return end The period's end timestamp
/// @return deadline The period's deadline timestamp
function close(Period storage period, uint40 endDelay, uint40 provingWindow)
internal
returns (uint40 end, uint40 deadline)
{
end = block.timestamp.toUint40() + endDelay;
deadline = end + provingWindow;
period.end = end;
period.deadline = deadline;
}
/// @dev slash the penalty from the period's stake
function slash(Period storage period, uint96 penalty) internal {
period.stake -= penalty;
}
/// @dev Assign the newProver (and fraction of remaining stake) to the new prover
/// @dev The last prover for the period will be assigned the reward (claimed with `finalizePastPeriod`).
/// In practice, a single prover will likely close the whole period with one proof.
function assignReward(Period storage period, address newProver) internal {
period.prover = newProver;
period.pastDeadline = true;
}
/// @dev Reset the prover and stake to zero. This ensures it cannot be finalized again.
/// @return stakeToReturn The amount of stake to return to the prover. If the original prover missed a proving
/// deadline, this will be just the reward fraction. The rest of the funds are locked in the contract.
function finalize(Period storage period, uint16 rewardFraction) internal returns (uint96 stakeToReturn) {
stakeToReturn = period.pastDeadline ? period.stake.scaleByBPS(rewardFraction) : period.stake;
period.prover = address(0);
period.stake = 0;
}
}