Skip to content

Commit 1ca2ae2

Browse files
authored
Implemented rebase time window (#131)
* Revert "If oracle data is invalid apply 0 supply change instead of reverting transaction." * Implemented rebase window (#132) * implemented rebase window * code review fixes: * changes round #2 * fixed incorrect test spec message * added minRebaseTimeIntervalSec_>0 check back
1 parent d1ff1f6 commit 1ca2ae2

File tree

3 files changed

+220
-67
lines changed

3 files changed

+220
-67
lines changed

contracts/UFragmentsPolicy.sol

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)