@@ -8,8 +8,8 @@ import "./lib/UInt256Lib.sol";
8
8
import "./UFragments.sol " ;
9
9
10
10
11
- interface IMarketOracle {
12
- function getPriceAnd24HourVolume () external returns (uint256 , uint256 );
11
+ interface IOracle {
12
+ function getData () external returns (uint256 , bool );
13
13
}
14
14
15
15
@@ -30,22 +30,32 @@ contract UFragmentsPolicy is Ownable {
30
30
event LogRebase (
31
31
uint256 indexed epoch ,
32
32
uint256 exchangeRate ,
33
- uint256 volume24hrs ,
34
- int256 requestedSupplyAdjustment
33
+ uint256 cpi ,
34
+ int256 requestedSupplyAdjustment ,
35
+ uint256 timestampSec
35
36
);
36
37
37
38
UFragments public uFrags;
38
- IMarketOracle public marketOracle;
39
39
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
41
51
// 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.
42
54
uint256 public deviationThreshold;
43
55
44
- // The 24hr market volume must be at least this value before any supply adjustments occur.
45
- uint256 public minimumVolume;
46
-
47
56
// The rebase lag parameter, used to dampen the applied supply adjustment by 1 / rebaseLag
48
57
// Check setRebaseLag comments for more details.
58
+ // Natural number, no decimal places.
49
59
uint256 public rebaseLag;
50
60
51
61
// More than this much time must pass between rebase operations.
@@ -57,38 +67,45 @@ contract UFragmentsPolicy is Ownable {
57
67
// The number of rebase cycles since inception
58
68
uint256 public epoch;
59
69
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 ;
65
71
66
72
// Due to the expression in computeSupplyDelta(), MAX_RATE * MAX_SUPPLY must fit into an int256.
67
73
// 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 ;
69
75
// MAX_SUPPLY = MAX_INT256 / MAX_RATE
70
76
uint256 private constant MAX_SUPPLY = ~ (uint256 (1 ) << 255 ) / MAX_RATE;
71
77
72
78
/**
73
79
* @notice Anyone can call this function to initiate a new rebase operation, provided more than
74
80
* the minimum time period has elapsed.
75
81
* @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
77
84
*/
78
85
function rebase () external {
79
86
// This comparison also ensures there is no reentrancy.
80
87
require (lastRebaseTimestampSec.add (minRebaseTimeIntervalSec) < now );
81
88
lastRebaseTimestampSec = now ;
82
89
epoch = epoch.add (1 );
83
90
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
+
84
98
uint256 exchangeRate;
85
- uint256 volume;
86
- (exchangeRate, volume) = marketOracle.getPriceAnd24HourVolume ();
99
+ bool rateValid;
100
+ (exchangeRate, rateValid) = marketOracle.getData ();
101
+ require (rateValid);
102
+
87
103
if (exchangeRate > MAX_RATE) {
88
104
exchangeRate = MAX_RATE;
89
105
}
90
106
91
- int256 supplyDelta = computeSupplyDelta (exchangeRate, volume);
107
+ int256 supplyDelta = computeSupplyDelta (exchangeRate, targetRate);
108
+
92
109
// Apply the Dampening factor.
93
110
supplyDelta = supplyDelta.div (rebaseLag.toInt256Safe ());
94
111
@@ -98,43 +115,42 @@ contract UFragmentsPolicy is Ownable {
98
115
99
116
uint256 supplyAfterRebase = uFrags.rebase (epoch, supplyDelta);
100
117
assert (supplyAfterRebase <= MAX_SUPPLY);
101
- emit LogRebase (epoch, exchangeRate, volume , supplyDelta);
118
+ emit LogRebase (epoch, exchangeRate, cpi , supplyDelta, lastRebaseTimestampSec );
102
119
}
103
120
104
121
/**
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.
107
124
*/
108
- function setMarketOracle (IMarketOracle marketOracle_ )
125
+ function setCpiOracle (IOracle cpiOracle_ )
109
126
external
110
127
onlyOwner
111
128
{
112
- marketOracle = marketOracle_ ;
129
+ cpiOracle = cpiOracle_ ;
113
130
}
114
131
115
132
/**
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.
120
135
*/
121
- function setDeviationThreshold ( uint256 deviationThreshold_ )
136
+ function setMarketOracle (IOracle marketOracle_ )
122
137
external
123
138
onlyOwner
124
139
{
125
- deviationThreshold = deviationThreshold_ ;
140
+ marketOracle = marketOracle_ ;
126
141
}
127
142
128
143
/**
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.
132
148
*/
133
- function setMinimumVolume (uint256 minimumVolume_ )
149
+ function setDeviationThreshold (uint256 deviationThreshold_ )
134
150
external
135
151
onlyOwner
136
152
{
137
- minimumVolume = minimumVolume_ ;
153
+ deviationThreshold = deviationThreshold_ ;
138
154
}
139
155
140
156
/**
@@ -171,63 +187,59 @@ contract UFragmentsPolicy is Ownable {
171
187
* It is called at the time of contract creation to invoke parent class initializers and
172
188
* initialize the contract's state variables.
173
189
*/
174
- function initialize (address owner , UFragments uFrags_ )
190
+ function initialize (address owner , UFragments uFrags_ , uint256 baseCpi_ )
175
191
public
176
192
initializer
177
193
{
178
194
Ownable.initialize (owner);
179
195
180
- deviationThreshold = (5 * TARGET_RATE) / 100 ; // 5% of target
181
- minimumVolume = 1 ;
196
+ // deviationThreshold = 0.05e18 = 5e16
197
+ deviationThreshold = 5 * 10 ** (DECIMALS-2 );
198
+
182
199
rebaseLag = 30 ;
183
200
minRebaseTimeIntervalSec = 1 days ;
184
201
lastRebaseTimestampSec = 0 ;
185
202
epoch = 0 ;
186
203
187
204
uFrags = uFrags_;
205
+ baseCpi = baseCpi_;
188
206
}
189
207
190
208
/**
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.
192
211
*/
193
- function computeSupplyDelta (uint256 rate , uint256 volume )
212
+ function computeSupplyDelta (uint256 rate , uint256 targetRate )
194
213
private
195
214
view
196
215
returns (int256 )
197
216
{
198
- if (withinDeviationThreshold (rate) || ! enoughVolume (volume )) {
217
+ if (withinDeviationThreshold (rate, targetRate )) {
199
218
return 0 ;
200
219
}
201
220
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);
206
226
}
207
227
208
228
/**
209
229
* @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.
210
231
* @return If the rate is within the deviation threshold from the target rate, returns true.
211
232
* Otherwise, returns false.
212
233
*/
213
- function withinDeviationThreshold (uint256 rate )
234
+ function withinDeviationThreshold (uint256 rate , uint256 targetRate )
214
235
private
215
236
view
216
237
returns (bool )
217
238
{
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);
221
241
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);
232
244
}
233
245
}
0 commit comments