@@ -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,20 +30,25 @@ contract UFragmentsPolicy is Ownable {
30
30
event LogRebase (
31
31
uint256 indexed epoch ,
32
32
uint256 exchangeRate ,
33
- uint256 volume24hrs ,
33
+ uint256 cpi ,
34
34
int256 requestedSupplyAdjustment
35
35
);
36
36
37
37
UFragments public uFrags;
38
- IMarketOracle public marketOracle;
39
38
40
- // If the current exchange rate is within this absolute distance from the target, no supply
39
+ // Cpi oracle provides the current CPI-U, seasonally adjusted data,
40
+ // as a 18 decimal fixed point number
41
+ IOracle public cpiOracle;
42
+
43
+ // Market oracle provides the token/USD exchange rate as a 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
+ // If the current exchange rate is within this fractional distance from the target, no supply
41
48
// update is performed. Fixed point number--same format as the rate.
49
+ // (ie) abs(rate - targetRate) / targetRate < deviationThreshold, then no supply change.
42
50
uint256 public deviationThreshold;
43
51
44
- // The 24hr market volume must be at least this value before any supply adjustments occur.
45
- uint256 public minimumVolume;
46
-
47
52
// The rebase lag parameter, used to dampen the applied supply adjustment by 1 / rebaseLag
48
53
// Check setRebaseLag comments for more details.
49
54
uint256 public rebaseLag;
@@ -57,38 +62,48 @@ contract UFragmentsPolicy is Ownable {
57
62
// The number of rebase cycles since inception
58
63
uint256 public epoch;
59
64
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);
65
+ uint256 private constant DECIMALS = 18 ;
65
66
66
67
// Due to the expression in computeSupplyDelta(), MAX_RATE * MAX_SUPPLY must fit into an int256.
67
68
// Both are 18 decimals fixed point numbers.
68
- uint256 private constant MAX_RATE = 10 ** 6 * 10 ** RATE_DECIMALS ;
69
+ uint256 private constant MAX_RATE = 10 ** 6 * 10 ** DECIMALS ;
69
70
// MAX_SUPPLY = MAX_INT256 / MAX_RATE
70
71
uint256 private constant MAX_SUPPLY = ~ (uint256 (1 ) << 255 ) / MAX_RATE;
71
72
73
+ // CPI-U value July 10th 1983 100, DECIMALS Fixed point number
74
+ uint256 private constant BASE_CPI = 100 * (10 ** DECIMALS);
75
+
72
76
/**
73
77
* @notice Anyone can call this function to initiate a new rebase operation, provided more than
74
78
* the minimum time period has elapsed.
75
79
* @dev The supply adjustment equals (_totalSupply * DeviationFromTargetRate) / rebaseLag
76
- * Where DeviationFromTargetRate is (MarketOracleRate - TARGET_RATE) / TARGET_RATE
80
+ * Where DeviationFromTargetRate is (MarketOracleRate - targetRate) / targetRate
81
+ * and targetRate is CpiOracleRate / BASE_CPI
77
82
*/
78
83
function rebase () external {
79
84
// This comparison also ensures there is no reentrancy.
80
85
require (lastRebaseTimestampSec.add (minRebaseTimeIntervalSec) < now );
81
86
lastRebaseTimestampSec = now ;
82
87
epoch = epoch.add (1 );
83
88
89
+ uint256 cpi;
90
+ bool cpiValid;
91
+ (cpi, cpiValid) = cpiOracle.getData ();
92
+ require (cpiValid);
93
+
94
+ uint256 targetRate = cpi.mul (10 ** DECIMALS).div (BASE_CPI);
95
+
84
96
uint256 exchangeRate;
85
- uint256 volume;
86
- (exchangeRate, volume) = marketOracle.getPriceAnd24HourVolume ();
97
+ bool rateValid;
98
+ (exchangeRate, rateValid) = marketOracle.getData ();
99
+ require (rateValid);
100
+
87
101
if (exchangeRate > MAX_RATE) {
88
102
exchangeRate = MAX_RATE;
89
103
}
90
104
91
- int256 supplyDelta = computeSupplyDelta (exchangeRate, volume);
105
+ int256 supplyDelta = computeSupplyDelta (exchangeRate, targetRate);
106
+
92
107
// Apply the Dampening factor.
93
108
supplyDelta = supplyDelta.div (rebaseLag.toInt256Safe ());
94
109
@@ -98,43 +113,42 @@ contract UFragmentsPolicy is Ownable {
98
113
99
114
uint256 supplyAfterRebase = uFrags.rebase (epoch, supplyDelta);
100
115
assert (supplyAfterRebase <= MAX_SUPPLY);
101
- emit LogRebase (epoch, exchangeRate, volume , supplyDelta);
116
+ emit LogRebase (epoch, exchangeRate, cpi , supplyDelta);
102
117
}
103
118
104
119
/**
105
- * @notice Sets the reference to the market oracle.
106
- * @param marketOracle_ The address of the market oracle contract.
120
+ * @notice Sets the reference to the CPI oracle.
121
+ * @param cpiOracle_ The address of the cpi oracle contract.
107
122
*/
108
- function setMarketOracle (IMarketOracle marketOracle_ )
123
+ function setCpiOracle (IOracle cpiOracle_ )
109
124
external
110
125
onlyOwner
111
126
{
112
- marketOracle = marketOracle_ ;
127
+ cpiOracle = cpiOracle_ ;
113
128
}
114
129
115
130
/**
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.
131
+ * @notice Sets the reference to the market oracle.
132
+ * @param marketOracle_ The address of the market oracle contract.
120
133
*/
121
- function setDeviationThreshold ( uint256 deviationThreshold_ )
134
+ function setMarketOracle (IOracle marketOracle_ )
122
135
external
123
136
onlyOwner
124
137
{
125
- deviationThreshold = deviationThreshold_ ;
138
+ marketOracle = marketOracle_ ;
126
139
}
127
140
128
141
/**
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.
142
+ * @notice Sets the deviation threshold fraction. If the exchange rate given by the market
143
+ * oracle is within this fractional distance from the targetRate, then no supply
144
+ * modifications are made. DECIMALS fixed point number.
145
+ * @param deviationThreshold_ The new exchange rate threshold fraction.
132
146
*/
133
- function setMinimumVolume (uint256 minimumVolume_ )
147
+ function setDeviationThreshold (uint256 deviationThreshold_ )
134
148
external
135
149
onlyOwner
136
150
{
137
- minimumVolume = minimumVolume_ ;
151
+ deviationThreshold = deviationThreshold_ ;
138
152
}
139
153
140
154
/**
@@ -177,8 +191,9 @@ contract UFragmentsPolicy is Ownable {
177
191
{
178
192
Ownable.initialize (owner);
179
193
180
- deviationThreshold = (5 * TARGET_RATE) / 100 ; // 5% of target
181
- minimumVolume = 1 ;
194
+ // deviationThreshold = 0.05e18 = 5e16
195
+ deviationThreshold = 5 * 10 ** (DECIMALS-2 );
196
+
182
197
rebaseLag = 30 ;
183
198
minRebaseTimeIntervalSec = 1 days ;
184
199
lastRebaseTimestampSec = 0 ;
@@ -188,46 +203,40 @@ contract UFragmentsPolicy is Ownable {
188
203
}
189
204
190
205
/**
191
- * @return Computes the total supply adjustment in response to the exchange rate.
206
+ * @return Computes the total supply adjustment in response to the exchange rate
207
+ * and the targetRate.
192
208
*/
193
- function computeSupplyDelta (uint256 rate , uint256 volume )
209
+ function computeSupplyDelta (uint256 rate , uint256 targetRate )
194
210
private
195
211
view
196
212
returns (int256 )
197
213
{
198
- if (withinDeviationThreshold (rate) || ! enoughVolume (volume )) {
214
+ if (withinDeviationThreshold (rate, targetRate )) {
199
215
return 0 ;
200
216
}
201
217
202
- // (totalSupply * (rate - target)) / target
203
- return uFrags.totalSupply ().toInt256Safe ().mul (
204
- rate.toInt256Safe ().sub (TARGET_RATE_SIGNED)
205
- ).div (TARGET_RATE_SIGNED);
218
+ // supplyDelta = totalSupply * (rate - targetRate) / targetRate
219
+ int256 targetRateSigned = targetRate.toInt256Safe ();
220
+ return uFrags.totalSupply ().toInt256Safe ()
221
+ .mul (rate.toInt256Safe ().sub (targetRateSigned))
222
+ .div (targetRateSigned);
206
223
}
207
224
208
225
/**
209
226
* @param rate The current exchange rate, an 18 decimal fixed point number.
227
+ * @param targetRate The target exchange rate, an 18 decimal fixed point number.
210
228
* @return If the rate is within the deviation threshold from the target rate, returns true.
211
229
* Otherwise, returns false.
212
230
*/
213
- function withinDeviationThreshold (uint256 rate )
231
+ function withinDeviationThreshold (uint256 rate , uint256 targetRate )
214
232
private
215
233
view
216
234
returns (bool )
217
235
{
218
- return (rate >= TARGET_RATE && rate.sub (TARGET_RATE) < deviationThreshold)
219
- || (rate < TARGET_RATE && TARGET_RATE.sub (rate) < deviationThreshold);
220
- }
236
+ uint256 absoluteDeviationThreshold = targetRate.mul (deviationThreshold)
237
+ .div (10 ** DECIMALS);
221
238
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;
239
+ return (rate >= targetRate && rate.sub (targetRate) < absoluteDeviationThreshold)
240
+ || (rate < targetRate && targetRate.sub (rate) < absoluteDeviationThreshold);
232
241
}
233
242
}
0 commit comments