@@ -64,6 +64,13 @@ contract UFragmentsPolicy is Ownable {
6464 // Block timestamp of last rebase operation
6565 uint256 public lastRebaseTimestampSec;
6666
67+ // The rebase window begins this many seconds into the minRebaseTimeInterval period.
68+ // For example if minRebaseTimeInterval is 24hrs, it represents the time of day in seconds.
69+ uint256 public rebaseWindowOffsetSec;
70+
71+ // The length of the time window where a rebase operation is allowed to execute, in seconds.
72+ uint256 public rebaseWindowLengthSec;
73+
6774 // The number of rebase cycles since inception
6875 uint256 public epoch;
6976
@@ -83,37 +90,41 @@ contract UFragmentsPolicy is Ownable {
8390 * and targetRate is CpiOracleRate / baseCpi
8491 */
8592 function rebase () external {
93+ require (inRebaseWindow ());
94+
8695 // This comparison also ensures there is no reentrancy.
8796 require (lastRebaseTimestampSec.add (minRebaseTimeIntervalSec) < now );
88- lastRebaseTimestampSec = now ;
97+
98+ // Snap the rebase time to the start of this window.
99+ lastRebaseTimestampSec = now .sub (now .mod (minRebaseTimeIntervalSec));
100+
89101 epoch = epoch.add (1 );
90102
91103 uint256 cpi;
92104 bool cpiValid;
93105 (cpi, cpiValid) = cpiOracle.getData ();
106+ require (cpiValid);
94107
95108 uint256 targetRate = cpi.mul (10 ** DECIMALS).div (baseCpi);
96109
97110 uint256 exchangeRate;
98111 bool rateValid;
99112 (exchangeRate, rateValid) = marketOracle.getData ();
113+ require (rateValid);
100114
101115 if (exchangeRate > MAX_RATE) {
102116 exchangeRate = MAX_RATE;
103117 }
104118
105- int256 supplyDelta = 0 ;
119+ int256 supplyDelta = computeSupplyDelta (exchangeRate, targetRate) ;
106120
107- if (cpiValid && rateValid) {
108- supplyDelta = computeSupplyDelta (exchangeRate, targetRate );
121+ // Apply the Dampening factor.
122+ supplyDelta = supplyDelta. div (rebaseLag. toInt256Safe () );
109123
110- // Apply the Dampening factor.
111- supplyDelta = supplyDelta.div (rebaseLag.toInt256Safe ());
112-
113- if (supplyDelta > 0 && uFrags.totalSupply ().add (uint256 (supplyDelta)) > MAX_SUPPLY) {
114- supplyDelta = (MAX_SUPPLY.sub (uFrags.totalSupply ())).toInt256Safe ();
115- }
124+ if (supplyDelta > 0 && uFrags.totalSupply ().add (uint256 (supplyDelta)) > MAX_SUPPLY) {
125+ supplyDelta = (MAX_SUPPLY.sub (uFrags.totalSupply ())).toInt256Safe ();
116126 }
127+
117128 uint256 supplyAfterRebase = uFrags.rebase (epoch, supplyDelta);
118129 assert (supplyAfterRebase <= MAX_SUPPLY);
119130 emit LogRebase (epoch, exchangeRate, cpi, supplyDelta, lastRebaseTimestampSec);
@@ -154,19 +165,6 @@ contract UFragmentsPolicy is Ownable {
154165 deviationThreshold = deviationThreshold_;
155166 }
156167
157- /**
158- * @notice Sets the minimum time period that must elapse between rebase cycles.
159- * @param minRebaseTimeIntervalSec_ More than this much time must pass between rebase
160- * operations, in seconds.
161- */
162- function setMinRebaseTimeIntervalSec (uint256 minRebaseTimeIntervalSec_ )
163- external
164- onlyOwner
165- {
166- require (minRebaseTimeIntervalSec_ > 0 );
167- minRebaseTimeIntervalSec = minRebaseTimeIntervalSec_;
168- }
169-
170168 /**
171169 * @notice Sets the rebase lag parameter.
172170 It is used to dampen the applied supply adjustment by 1 / rebaseLag
@@ -183,6 +181,33 @@ contract UFragmentsPolicy is Ownable {
183181 rebaseLag = rebaseLag_;
184182 }
185183
184+ /**
185+ * @notice Sets the parameters which control the timing and frequency of
186+ * rebase operations.
187+ * a) the minimum time period that must elapse between rebase cycles.
188+ * b) the rebase window offset parameter.
189+ * c) the rebase window length parameter.
190+ * @param minRebaseTimeIntervalSec_ More than this much time must pass between rebase
191+ * operations, in seconds.
192+ * @param rebaseWindowOffsetSec_ The number of seconds from the beginning of
193+ the rebase interval, where the rebase window begins.
194+ * @param rebaseWindowLengthSec_ The length of the rebase window in seconds.
195+ */
196+ function setRebaseTimingParameters (
197+ uint256 minRebaseTimeIntervalSec_ ,
198+ uint256 rebaseWindowOffsetSec_ ,
199+ uint256 rebaseWindowLengthSec_ )
200+ external
201+ onlyOwner
202+ {
203+ require (minRebaseTimeIntervalSec_ > 0 );
204+ require (rebaseWindowOffsetSec_ < minRebaseTimeIntervalSec_);
205+
206+ minRebaseTimeIntervalSec = minRebaseTimeIntervalSec_;
207+ rebaseWindowOffsetSec = rebaseWindowOffsetSec_;
208+ rebaseWindowLengthSec = rebaseWindowLengthSec_;
209+ }
210+
186211 /**
187212 * @dev ZOS upgradable contract initialization method.
188213 * It is called at the time of contract creation to invoke parent class initializers and
@@ -199,13 +224,26 @@ contract UFragmentsPolicy is Ownable {
199224
200225 rebaseLag = 30 ;
201226 minRebaseTimeIntervalSec = 1 days ;
227+ rebaseWindowOffsetSec = 72000 ; // 8PM UTC
228+ rebaseWindowLengthSec = 15 minutes ;
202229 lastRebaseTimestampSec = 0 ;
203230 epoch = 0 ;
204231
205232 uFrags = uFrags_;
206233 baseCpi = baseCpi_;
207234 }
208235
236+ /**
237+ * @return If the latest block timestamp is within the rebase time window it, returns true.
238+ * Otherwise, returns false.
239+ */
240+ function inRebaseWindow () public view returns (bool ) {
241+ return (
242+ now .mod (minRebaseTimeIntervalSec) >= rebaseWindowOffsetSec &&
243+ now .mod (minRebaseTimeIntervalSec) < (rebaseWindowOffsetSec.add (rebaseWindowLengthSec))
244+ );
245+ }
246+
209247 /**
210248 * @return Computes the total supply adjustment in response to the exchange rate
211249 * and the targetRate.
0 commit comments