You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+12-12
Original file line number
Diff line number
Diff line change
@@ -14,11 +14,11 @@ Updating the oracle is divided into 3 phases:
14
14
15
15
LibOracle.OracleUpdateSet memory us = oracleGetUpdateSet(oc);
16
16
17
-
// Phase 3: Write the updates out to storage:
17
+
// Phase 3: Write the updates out to storage along with a new tick:
18
18
19
19
oracleUpdate(oc, us, newTick);
20
20
21
-
The `OracleUpdateSet` contains up-to-date moving averages, variances, and `tickAtStartOfBlock` so these can be used to influence an AMM, if desired.
21
+
The `OracleUpdateSet` contains up-to-date moving averages, variances, and `tickAtStartOfBlock` so these can be used to parameterise an AMM, if desired.
22
22
23
23
Finally, once a new tick has been determined by the implementing contract, the updated values are written out to storage, as well as to the ring buffer (if applicable).
24
24
@@ -30,7 +30,7 @@ In uniswap3 terminology, a "tick" refers to a log-space, quantised price-ratio b
30
30
31
31
**Price ratio*: Given two assets, a price can be considered as a ratio (or fraction). For example, consider ETH and USD. If 1500 USD will get you 1 ETH, then the price ratio would be `1500/1` or `1/1500`, depending on which asset you select as your base/quote. Because usually it's inconvenient to work with fractions, we represent this instead as a number, for example `1500`, or `0.0006666...`
32
32
**Log-space*: The price ratio numbers can get very large/small, especially considering some tokens have different decimal values. In order to keep them within a reasonable range, we use the logarithms of the price ratios. For example, `ln(1500/1) = 7.313...` and `ln(1/1500) = -7.313...`. A very appealing property of logarithms is that inverting a price ratio is equivalent to negating its logarithm. There are several other benefits to using log-space that we will describe below.
33
-
**Quantised*: Because we can't store our prices to an unlimited precision, we need to round their values to the nearest representable value. Using the previous example, we might round `7.313...` to `7.3`. Although this loses some precision, this loss can be quantified and maintained to an acceptable level. Note that this rounding operation is the source of the name "tick": Imagine the ticks on a chart as being discrete values that data-points must conform to.
33
+
**Quantised*: Because we can't store our prices to an unlimited precision, we need to round their values to the nearest representable value. Using the previous example, we might round `7.313...` to `7.3`. Although this loses some precision, this loss can be quantified and maintained at an acceptable level. Note that this rounding operation is the source of the name "tick": Imagine the ticks on a chart as being evenly-spaced discrete values that data-points must conform to.
34
34
35
35
### Uniswap3 Ticks
36
36
@@ -46,22 +46,22 @@ From these we can derive `MAX_TICK`:
46
46
MAX_TICK = ln(2**128) / ln(1.0001)
47
47
MAX_TICK = 887272.7517...
48
48
49
-
Uniswap3 stores ticks in `int24`variables, which have plenty of room since these tick values only contain about 20.8 bits of information:
49
+
Uniswap3 stores each tick as an `int24`type, which is more than large enough since Uniswap3 tick values contain about 20.8 bits of information:
50
50
51
51
ln(887272 * 2 + 1)/ln(2) = 20.759...
52
52
53
53
### LibOracle Ticks
54
54
55
-
Since LibOracle is attempting to get the maximum benefit out of a limited storage space, our ticks begin with slightly different requirements:
55
+
Since LibOracle is attempting to squeeze the maximum benefit out of a limited storage space, our ticks begin with slightly different requirements:
56
56
57
57
* Price ratios between `1/2**128` and `2**128` should be supported.
58
58
* It should maximise information density while fitting into an `int24`
59
59
60
60
So our `MAX_TICK` value is chosen to be `2**23 - 256` and `MIN_TICK` is the negation: `-8388352` and `8388352`.
61
61
62
-
The subtracting of 256 is done to allow round-tripping through "small" ticks (see below).
62
+
(Subtracting 256 is done to allow round-tripping through "small" ticks, described below)
63
63
64
-
These ticks have a higher information density within `int24`s:
64
+
LibOracle ticks have a higher information density within `int24`s:
65
65
66
66
ln((2**23 - 256) * 2 + 1)/ln(2) = 23.99995605...
67
67
@@ -77,7 +77,7 @@ It is approximately `0.001%`.
77
77
78
78
### Small Ticks
79
79
80
-
Internally, LibOracle quantises these ticks down further into `int16`s for storage in its ring buffer. Essentially it divides the tick values by `256` and then truncates (actually it adds or subtracts `128`first, to implement rounding -- this is a mid-step quantisation).
80
+
Internally, LibOracle quantises these ticks down further into `int16`s for storage in its ring buffer. Essentially it divides the tick values by `256` and then rounds (it adds or subtracts `128`and then truncates -- this is a mid-step quantisation).
81
81
82
82
Small ticks have minimum and maximum vaues of `-32767` and `32767`, providing the following density:
83
83
@@ -100,14 +100,14 @@ One useful property of logarithms is that it is very easy to convert bases. For
100
100
101
101
Javascript is unable to represent the `B` value to enough precision, so this conversion is approximate (but good enough for plotting).
102
102
103
-
For on-chain implementations, note that this is equivalent to simply multiplying by `9.454084984590639502`.
103
+
For on-chain implementations, note that this is approximately equivalent to simply multiplying by `9.454084984590639502`.
104
104
105
105
106
106
107
107
108
108
## Moving Average and Variance
109
109
110
-
Although the ring buffer oracle can provide a geometric time-weighted average, for some applications querying this data structure can be too expensive. In particular, an AMM that implements LibOracle might like to use a moving average of a price to influence the behaviour of swaps, and the AMM might not be competitive if swapping could consume a large and/or unpredictable amount of gas.
110
+
Although the ring buffer oracle can provide a geometric time-weighted average, for some applications querying this data structure can be too expensive. In particular, an AMM that implements LibOracle might want to use a moving average of a price to influence the behaviour of swaps (as in Curve2 for example), and the AMM might not be competitive if swapping could consume a large and/or unpredictable amount of gas.
111
111
112
112
Additionally, for some AMM designs it may be useful to know the variance (or standard deviation) of a price over a time period.
113
113
@@ -123,11 +123,11 @@ An EMA works by maintaining an accumulator value that "decays" over time as it i
123
123
124
124
alpha = e**(-elapsed / window)
125
125
126
-
LibOracle uses `e` as the base of the exponent, but other bases will also work. The nice feature of the `e` is that if the initial decay rate remained constant, then the decay would be exactly complete after 1 window's duration. Of course, this doesn't happen because the rate of decay reduces with the magnitude.
126
+
LibOracle uses `e` as the base of the exponent, but other bases will also work. The nice feature of `e` is that if the initial decay rate remained constant, then the decay would be exactly complete after 1 window's duration. Of course, this doesn't happen because the rate of decay reduces with the magnitude and after 1 window the magnitude is reduced to `1/e = 0.367879...`.
127
127
128
128
An important feature of exponential decay is that the decay is unaffected by the frequency of updates to the accumulator. This means that the reported moving averages will be unaffected by the amount of activity tracked by the oracle. Additionally, in cases where the tick doesn't change in an update, there is no need to spend the gas to update the accumulator -- it can be put off until needed.
129
129
130
-
Variance is also tracked through a slight modification the above process.
130
+
Variance is also tracked through a slight modification of the above process.
0 commit comments