@@ -8,8 +8,8 @@ import "./lib/UInt256Lib.sol";
88import "./UFragments.sol " ;
99
1010
11- interface IMarketOracle {
12- function getPriceAnd24HourVolume () external returns (uint256 , uint256 );
11+ interface IOracle {
12+ function getData () external returns (uint256 , bool );
1313}
1414
1515
@@ -30,22 +30,32 @@ contract UFragmentsPolicy is Ownable {
3030 event LogRebase (
3131 uint256 indexed epoch ,
3232 uint256 exchangeRate ,
33- uint256 volume24hrs ,
34- int256 requestedSupplyAdjustment
33+ uint256 cpi ,
34+ int256 requestedSupplyAdjustment ,
35+ uint256 timestampSec
3536 );
3637
3738 UFragments public uFrags;
38- IMarketOracle public marketOracle;
3939
40- // If the current exchange rate is within this absolute distance from the target, no supply
40+ // Provides the current CPI, as an 18 decimal fixed point number.
41+ IOracle public cpiOracle;
42+
43+ // Market oracle provides the token/USD exchange rate as an 18 decimal fixed point number.
44+ // (eg) An oracle value of 1.5e18 it would mean 1 Ample is trading for $1.50.
45+ IOracle public marketOracle;
46+
47+ // CPI value at the time of launch, as an 18 decimal fixed point number.
48+ uint256 private baseCpi;
49+
50+ // If the current exchange rate is within this fractional distance from the target, no supply
4151 // update is performed. Fixed point number--same format as the rate.
52+ // (ie) abs(rate - targetRate) / targetRate < deviationThreshold, then no supply change.
53+ // DECIMALS Fixed point number.
4254 uint256 public deviationThreshold;
4355
44- // The 24hr market volume must be at least this value before any supply adjustments occur.
45- uint256 public minimumVolume;
46-
4756 // The rebase lag parameter, used to dampen the applied supply adjustment by 1 / rebaseLag
4857 // Check setRebaseLag comments for more details.
58+ // Natural number, no decimal places.
4959 uint256 public rebaseLag;
5060
5161 // More than this much time must pass between rebase operations.
@@ -57,38 +67,45 @@ contract UFragmentsPolicy is Ownable {
5767 // The number of rebase cycles since inception
5868 uint256 public epoch;
5969
60- uint256 private constant RATE_DECIMALS = 18 ;
61-
62- uint256 private constant TARGET_RATE = 1 * 10 ** RATE_DECIMALS;
63-
64- int256 private constant TARGET_RATE_SIGNED = int256 (TARGET_RATE);
70+ uint256 private constant DECIMALS = 18 ;
6571
6672 // Due to the expression in computeSupplyDelta(), MAX_RATE * MAX_SUPPLY must fit into an int256.
6773 // Both are 18 decimals fixed point numbers.
68- uint256 private constant MAX_RATE = 10 ** 6 * 10 ** RATE_DECIMALS ;
74+ uint256 private constant MAX_RATE = 10 ** 6 * 10 ** DECIMALS ;
6975 // MAX_SUPPLY = MAX_INT256 / MAX_RATE
7076 uint256 private constant MAX_SUPPLY = ~ (uint256 (1 ) << 255 ) / MAX_RATE;
7177
7278 /**
7379 * @notice Anyone can call this function to initiate a new rebase operation, provided more than
7480 * the minimum time period has elapsed.
7581 * @dev The supply adjustment equals (_totalSupply * DeviationFromTargetRate) / rebaseLag
76- * Where DeviationFromTargetRate is (MarketOracleRate - TARGET_RATE) / TARGET_RATE
82+ * Where DeviationFromTargetRate is (MarketOracleRate - targetRate) / targetRate
83+ * and targetRate is CpiOracleRate / baseCpi
7784 */
7885 function rebase () external {
7986 // This comparison also ensures there is no reentrancy.
8087 require (lastRebaseTimestampSec.add (minRebaseTimeIntervalSec) < now );
8188 lastRebaseTimestampSec = now ;
8289 epoch = epoch.add (1 );
8390
91+ uint256 cpi;
92+ bool cpiValid;
93+ (cpi, cpiValid) = cpiOracle.getData ();
94+ require (cpiValid);
95+
96+ uint256 targetRate = cpi.mul (10 ** DECIMALS).div (baseCpi);
97+
8498 uint256 exchangeRate;
85- uint256 volume;
86- (exchangeRate, volume) = marketOracle.getPriceAnd24HourVolume ();
99+ bool rateValid;
100+ (exchangeRate, rateValid) = marketOracle.getData ();
101+ require (rateValid);
102+
87103 if (exchangeRate > MAX_RATE) {
88104 exchangeRate = MAX_RATE;
89105 }
90106
91- int256 supplyDelta = computeSupplyDelta (exchangeRate, volume);
107+ int256 supplyDelta = computeSupplyDelta (exchangeRate, targetRate);
108+
92109 // Apply the Dampening factor.
93110 supplyDelta = supplyDelta.div (rebaseLag.toInt256Safe ());
94111
@@ -98,43 +115,42 @@ contract UFragmentsPolicy is Ownable {
98115
99116 uint256 supplyAfterRebase = uFrags.rebase (epoch, supplyDelta);
100117 assert (supplyAfterRebase <= MAX_SUPPLY);
101- emit LogRebase (epoch, exchangeRate, volume , supplyDelta);
118+ emit LogRebase (epoch, exchangeRate, cpi , supplyDelta, lastRebaseTimestampSec );
102119 }
103120
104121 /**
105- * @notice Sets the reference to the market oracle.
106- * @param marketOracle_ The address of the market oracle contract.
122+ * @notice Sets the reference to the CPI oracle.
123+ * @param cpiOracle_ The address of the cpi oracle contract.
107124 */
108- function setMarketOracle (IMarketOracle marketOracle_ )
125+ function setCpiOracle (IOracle cpiOracle_ )
109126 external
110127 onlyOwner
111128 {
112- marketOracle = marketOracle_ ;
129+ cpiOracle = cpiOracle_ ;
113130 }
114131
115132 /**
116- * @notice Sets the deviation threshold. If the exchange rate given by the market
117- * oracle is within this absolute distance from the target, then no supply
118- * modifications are made. RATE_DECIMALS fixed point number.
119- * @param deviationThreshold_ The new exchange rate threshold.
133+ * @notice Sets the reference to the market oracle.
134+ * @param marketOracle_ The address of the market oracle contract.
120135 */
121- function setDeviationThreshold ( uint256 deviationThreshold_ )
136+ function setMarketOracle (IOracle marketOracle_ )
122137 external
123138 onlyOwner
124139 {
125- deviationThreshold = deviationThreshold_ ;
140+ marketOracle = marketOracle_ ;
126141 }
127142
128143 /**
129- * @notice Sets the minimum volume. During rebase, the volume must be at least this value before
130- * any supply adjustment is made.
131- * @param minimumVolume_ The new minimum volume, measured in 24hr market Token Volume.
144+ * @notice Sets the deviation threshold fraction. If the exchange rate given by the market
145+ * oracle is within this fractional distance from the targetRate, then no supply
146+ * modifications are made. DECIMALS fixed point number.
147+ * @param deviationThreshold_ The new exchange rate threshold fraction.
132148 */
133- function setMinimumVolume (uint256 minimumVolume_ )
149+ function setDeviationThreshold (uint256 deviationThreshold_ )
134150 external
135151 onlyOwner
136152 {
137- minimumVolume = minimumVolume_ ;
153+ deviationThreshold = deviationThreshold_ ;
138154 }
139155
140156 /**
@@ -171,63 +187,59 @@ contract UFragmentsPolicy is Ownable {
171187 * It is called at the time of contract creation to invoke parent class initializers and
172188 * initialize the contract's state variables.
173189 */
174- function initialize (address owner , UFragments uFrags_ )
190+ function initialize (address owner , UFragments uFrags_ , uint256 baseCpi_ )
175191 public
176192 initializer
177193 {
178194 Ownable.initialize (owner);
179195
180- deviationThreshold = (5 * TARGET_RATE) / 100 ; // 5% of target
181- minimumVolume = 1 ;
196+ // deviationThreshold = 0.05e18 = 5e16
197+ deviationThreshold = 5 * 10 ** (DECIMALS-2 );
198+
182199 rebaseLag = 30 ;
183200 minRebaseTimeIntervalSec = 1 days ;
184201 lastRebaseTimestampSec = 0 ;
185202 epoch = 0 ;
186203
187204 uFrags = uFrags_;
205+ baseCpi = baseCpi_;
188206 }
189207
190208 /**
191- * @return Computes the total supply adjustment in response to the exchange rate.
209+ * @return Computes the total supply adjustment in response to the exchange rate
210+ * and the targetRate.
192211 */
193- function computeSupplyDelta (uint256 rate , uint256 volume )
212+ function computeSupplyDelta (uint256 rate , uint256 targetRate )
194213 private
195214 view
196215 returns (int256 )
197216 {
198- if (withinDeviationThreshold (rate) || ! enoughVolume (volume )) {
217+ if (withinDeviationThreshold (rate, targetRate )) {
199218 return 0 ;
200219 }
201220
202- // (totalSupply * (rate - target)) / target
203- return uFrags.totalSupply ().toInt256Safe ().mul (
204- rate.toInt256Safe ().sub (TARGET_RATE_SIGNED)
205- ).div (TARGET_RATE_SIGNED);
221+ // supplyDelta = totalSupply * (rate - targetRate) / targetRate
222+ int256 targetRateSigned = targetRate.toInt256Safe ();
223+ return uFrags.totalSupply ().toInt256Safe ()
224+ .mul (rate.toInt256Safe ().sub (targetRateSigned))
225+ .div (targetRateSigned);
206226 }
207227
208228 /**
209229 * @param rate The current exchange rate, an 18 decimal fixed point number.
230+ * @param targetRate The target exchange rate, an 18 decimal fixed point number.
210231 * @return If the rate is within the deviation threshold from the target rate, returns true.
211232 * Otherwise, returns false.
212233 */
213- function withinDeviationThreshold (uint256 rate )
234+ function withinDeviationThreshold (uint256 rate , uint256 targetRate )
214235 private
215236 view
216237 returns (bool )
217238 {
218- return (rate >= TARGET_RATE && rate.sub (TARGET_RATE) < deviationThreshold)
219- || (rate < TARGET_RATE && TARGET_RATE.sub (rate) < deviationThreshold);
220- }
239+ uint256 absoluteDeviationThreshold = targetRate.mul (deviationThreshold)
240+ .div (10 ** DECIMALS);
221241
222- /**
223- * @param volume Total trade volume of the last reported 24 hours in Token volume.
224- * return True, if the volume meets requirements for a supply adjustment. False otherwise.
225- */
226- function enoughVolume (uint256 volume )
227- private
228- view
229- returns (bool )
230- {
231- return volume >= minimumVolume;
242+ return (rate >= targetRate && rate.sub (targetRate) < absoluteDeviationThreshold)
243+ || (rate < targetRate && targetRate.sub (rate) < absoluteDeviationThreshold);
232244 }
233245}
0 commit comments