Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 61 additions & 23 deletions contracts/UFragmentsPolicy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ contract UFragmentsPolicy is Ownable {
// Block timestamp of last rebase operation
uint256 public lastRebaseTimestampSec;

// The rebase window begins this many seconds into the minRebaseTimeInterval period.
// For example if minRebaseTimeInterval is 24hrs, it represents the time of day in seconds.
uint256 public rebaseWindowOffsetSec;

// The length of the time window where a rebase operation is allowed to execute, in seconds.
uint256 public rebaseWindowLengthSec;

// The number of rebase cycles since inception
uint256 public epoch;

Expand All @@ -83,37 +90,41 @@ contract UFragmentsPolicy is Ownable {
* and targetRate is CpiOracleRate / baseCpi
*/
function rebase() external {
require(inRebaseWindow());

// This comparison also ensures there is no reentrancy.
require(lastRebaseTimestampSec.add(minRebaseTimeIntervalSec) < now);
lastRebaseTimestampSec = now;

// Snap the rebase time to the start of this window.
lastRebaseTimestampSec = now.sub(now.mod(minRebaseTimeIntervalSec));

epoch = epoch.add(1);

uint256 cpi;
bool cpiValid;
(cpi, cpiValid) = cpiOracle.getData();
require(cpiValid);

uint256 targetRate = cpi.mul(10 ** DECIMALS).div(baseCpi);

uint256 exchangeRate;
bool rateValid;
(exchangeRate, rateValid) = marketOracle.getData();
require(rateValid);

if (exchangeRate > MAX_RATE) {
exchangeRate = MAX_RATE;
}

int256 supplyDelta = 0;
int256 supplyDelta = computeSupplyDelta(exchangeRate, targetRate);

if (cpiValid && rateValid) {
supplyDelta = computeSupplyDelta(exchangeRate, targetRate);
// Apply the Dampening factor.
supplyDelta = supplyDelta.div(rebaseLag.toInt256Safe());

// Apply the Dampening factor.
supplyDelta = supplyDelta.div(rebaseLag.toInt256Safe());

if (supplyDelta > 0 && uFrags.totalSupply().add(uint256(supplyDelta)) > MAX_SUPPLY) {
supplyDelta = (MAX_SUPPLY.sub(uFrags.totalSupply())).toInt256Safe();
}
if (supplyDelta > 0 && uFrags.totalSupply().add(uint256(supplyDelta)) > MAX_SUPPLY) {
supplyDelta = (MAX_SUPPLY.sub(uFrags.totalSupply())).toInt256Safe();
}

uint256 supplyAfterRebase = uFrags.rebase(epoch, supplyDelta);
assert(supplyAfterRebase <= MAX_SUPPLY);
emit LogRebase(epoch, exchangeRate, cpi, supplyDelta, lastRebaseTimestampSec);
Expand Down Expand Up @@ -154,19 +165,6 @@ contract UFragmentsPolicy is Ownable {
deviationThreshold = deviationThreshold_;
}

/**
* @notice Sets the minimum time period that must elapse between rebase cycles.
* @param minRebaseTimeIntervalSec_ More than this much time must pass between rebase
* operations, in seconds.
*/
function setMinRebaseTimeIntervalSec(uint256 minRebaseTimeIntervalSec_)
external
onlyOwner
{
require(minRebaseTimeIntervalSec_ > 0);
minRebaseTimeIntervalSec = minRebaseTimeIntervalSec_;
}

/**
* @notice Sets the rebase lag parameter.
It is used to dampen the applied supply adjustment by 1 / rebaseLag
Expand All @@ -183,6 +181,33 @@ contract UFragmentsPolicy is Ownable {
rebaseLag = rebaseLag_;
}

/**
* @notice Sets the parameters which control the timing and frequency of
* rebase operations.
* a) the minimum time period that must elapse between rebase cycles.
* b) the rebase window offset parameter.
* c) the rebase window length parameter.
* @param minRebaseTimeIntervalSec_ More than this much time must pass between rebase
* operations, in seconds.
* @param rebaseWindowOffsetSec_ The number of seconds from the beginning of
the rebase interval, where the rebase window begins.
* @param rebaseWindowLengthSec_ The length of the rebase window in seconds.
*/
function setRebaseTimingParameters(
uint256 minRebaseTimeIntervalSec_,
uint256 rebaseWindowOffsetSec_,
uint256 rebaseWindowLengthSec_)
external
onlyOwner
{
require(minRebaseTimeIntervalSec_ > 0);
require(rebaseWindowOffsetSec_ < minRebaseTimeIntervalSec_);

minRebaseTimeIntervalSec = minRebaseTimeIntervalSec_;
rebaseWindowOffsetSec = rebaseWindowOffsetSec_;
rebaseWindowLengthSec = rebaseWindowLengthSec_;
}

/**
* @dev ZOS upgradable contract initialization method.
* It is called at the time of contract creation to invoke parent class initializers and
Expand All @@ -199,13 +224,26 @@ contract UFragmentsPolicy is Ownable {

rebaseLag = 30;
minRebaseTimeIntervalSec = 1 days;
rebaseWindowOffsetSec = 72000; // 8PM UTC
rebaseWindowLengthSec = 15 minutes;
lastRebaseTimestampSec = 0;
epoch = 0;

uFrags = uFrags_;
baseCpi = baseCpi_;
}

/**
* @return If the latest block timestamp is within the rebase time window it, returns true.
* Otherwise, returns false.
*/
function inRebaseWindow() public view returns (bool) {
return (
now.mod(minRebaseTimeIntervalSec) >= rebaseWindowOffsetSec &&
now.mod(minRebaseTimeIntervalSec) < (rebaseWindowOffsetSec.add(rebaseWindowLengthSec))
);
}

/**
* @return Computes the total supply adjustment in response to the exchange rate
* and the targetRate.
Expand Down
Loading