Skip to content

Commit c631d70

Browse files
authored
Add ReClamm oracle section (#325)
1 parent 1a3dfbb commit c631d70

1 file changed

Lines changed: 134 additions & 18 deletions

File tree

docs/concepts/core-concepts/bpt-oracles/bpt-oracles.md

Lines changed: 134 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,17 @@ Then the real magic happens - we can substitute those xⱼ expressions into the
5555

5656
With x̃ representing the vector of theoretical token balances, the pool constraint can be expressed mathematically as:
5757

58+
```
5859
F(x̃) = D; or F(x̃, D) = 0
60+
```
5961

6062
This means that the theoretical balances must reproduce the real invariant.
6163

6264
The price constraint can be expressed mathematically as:
6365

66+
```
6467
∇f(x̃) = k̃ · ρ
68+
```
6569

6670
This means that the internal prices must match (i.e., be proportional to) the oracle prices. ρ (rho) is a "critical boundary" constraint on k̃. We can derive a minimum valid value of k̃ from the oracle prices and degree of price curvature: at this value or below, the "T curve" (described below) goes to infinity and the equation is no longer soluble.
6771

@@ -73,73 +77,173 @@ To calculate ρ:
7377

7478
Given these constraints, the key is to find k̃. To understand how, we start with the invariant equation for the pool:
7579

80+
```
7681
f(x₁, x₂, ..., xₙ) = D
82+
```
7783

78-
This is some function which, operating on the real balances, produces a single invariant value D, representing the total value of the pool. The details vary, but the Balancer Vault requires this to be defined for every pool type. So far, we have implemented oracles for both Weighted and Stable Balancer pools. (ReCLAMM pools should also work, as they are fundamentally Weighted pools, just incorporating virtual balances.)
84+
This is some function which, operating on the real balances, produces a single invariant value D, representing the total value of the pool. The details vary, but the Balancer Vault requires this to be defined for every pool type. So far, we have implemented oracles for both Weighted and Stable Balancer pools. (ReCLAMM pools should also work, as they are fundamentally Weighted pools, just incorporating virtual balances. See the ReClamm Pools section below.)
7985

8086
The partial derivative ∂f/∂xⱼ represents how much the invariant changes per unit of token j, and the ratio of these partial derivatives represents the internal spot price of one token in terms of another. For instance, ∂f/∂x₂ / ∂f/∂x₁ would be the spot price of token 2 in terms of token 1.
8187

8288
The n gradient equations look like:
8389

90+
```
8491
∂F/∂x₁ = k̃ · p₁<br>
8592
∂F/∂x₂ = k̃ · p₂<br>
8693
...<br>
8794
∂F/∂xₙ = k̃ · p₂
95+
```
8896

8997
We now apply the second constraint, substituting the x expressions into the pool constraint F(x̃, D) = 0. Since all the x expressions are functions of k̃, we now have a single equation in terms of k̃: one equation, one unknown.
9098

9199
After a lot of algebra, the single equation can be written as:
92100

93-
T(k̃)^(n+1) · P(k̃) = α; where
101+
```
102+
T(k̃)^(n+1) · P(k̃) = α
103+
```
94104

95-
T(k̃) = Σ(1/(k̃rᵢ - 1)) - 1; from the gradient equations, where the r values are the scaled prices described above;
105+
where:
96106

97-
P(k̃) = ∏(k̃rᵢ - 1); also from the gradient equations; and
107+
```
108+
T(k̃) = Σ(1/(k̃rᵢ - 1)) - 1
109+
```
98110

99-
α = a·c^(n+1); a constant derived from the pool parameters, where:
111+
from the gradient equations, where the r values are the scaled prices described above;
100112

113+
```
114+
P(k̃) = ∏(k̃rᵢ - 1)
115+
```
116+
117+
also from the gradient equations; and
118+
119+
```
120+
α = a·c^(n+1)
121+
```
122+
123+
a constant derived from the pool parameters, where:
124+
125+
```
101126
a = A·n^(2n);<br>
102127
b = a - n^n; and<br>
103128
c = b/a
129+
```
104130

105-
Unfortunately this "T equation" is non-linear in , so it must be solved numerically. On-chain, we use Newton's method to find the root (= the value of k̃ that satisfies both constraints). In the mathematical paper referenced below, we prove that given the specified starting point, it will converge to the correct solution. There may be many roots, especially with higher numbers of tokens. The correct one is the smallest non-negative root, closest to the origin.
131+
Unfortunately this "T equation" is non-linear in ``, so it must be solved numerically. On-chain, we use Newton's method to find the root (= the value of k̃ that satisfies both constraints). In the mathematical paper referenced below, we prove that given the specified starting point, it will converge to the correct solution. There may be many roots, especially with higher numbers of tokens. The correct one is the smallest non-negative root, closest to the origin.
106132

107133
In summary:
108134

109135
* Oracle prices tell us what the "fair" relative prices should be
110136
* The gradient condition ensures that internal AMM prices correspond to these fair prices
111137
* The invariant condition ensures that the theoretical balances are valid for the pool, and correctly represent the value
112-
* is the common scaling parameter: the "knob" we adjust to make both conditions true simultaneously
113-
* Once we find the right k̃, we can calculate the fair balances x̃ⱼ, and price the LP token
138+
* `` is the common scaling parameter: the "knob" we adjust to make both conditions true simultaneously
139+
* Once we find the right k̃, we can calculate the fair balances `x̃ⱼ`, and price the LP token
114140

115141
See [this page](./bpt-oracles-example.md) for a numerical example.
116142

117143
### Weighted Pools
118144

119145
Weighted and Stable Pools use the same general algorithm. While the complex StableSwap invariant requires Newton's method to find the scaling parameter k̃, then calculate effective balances and total value, the power-law invariant of the Weighted Pool allows us to solve the gradient and invariant conditions simultaneously, giving us:
120146

121-
TVL = k × Π((Pᵢ/Wᵢ)^Wᵢ) in one step.
147+
```
148+
TVL = k × Π((Pᵢ/Wᵢ)^Wᵢ)
149+
```
150+
151+
in one step.
122152

123153
In particular, "mapping" the weighted pool solution onto the equivalent terms used above:
124154

125-
* The theoretical balances x̃ᵢ = (TVL × Wᵢ)/Pᵢ, where TVL is the total pool value (referred to as Bᵢ in the WeightedLPOracle code docs).
126-
* The Weighted invariant D = Π(Bᵢ^Wᵢ), computed directly using theoretical balances and weights (referred to as k in the WeightedLPOracle code docs).
127-
* The scaling parameter is in the Weighted case simply equal to the TVL (C in the code docs).
155+
* The theoretical balances `x̃ᵢ = (TVL × Wᵢ)/Pᵢ`, where TVL is the total pool value (referred to as `Bᵢ` in the WeightedLPOracle code docs).
156+
* The Weighted invariant `D = Π(Bᵢ^Wᵢ)`, computed directly using theoretical balances and weights (referred to as k in the WeightedLPOracle code docs).
157+
* The scaling parameter `` is in the Weighted case simply equal to the TVL (`C` in the code docs).
128158

129-
So, positing a normalization constant C such that C = (Pᵢ × Bᵢ / Wᵢ) for every token, the gradient "price constraint" is:
159+
So, positing a normalization constant `C` such that `C = (Pᵢ × Bᵢ / Wᵢ)` for every token, the gradient "price constraint" is:
130160

161+
```
131162
Bᵢ = (C × Wᵢ)/Pᵢ
163+
```
164+
165+
This set of balances align the pool's spot price with external prices provided by the feeds.
132166

133167
We can then substitute this directly into the invariant (no complex polynomials here):
134168

169+
```
135170
D = Π((C × Wᵢ/Pᵢ)^Wᵢ) = C × Π((Wᵢ/Pᵢ)^Wᵢ)
171+
```
136172

137173
And then solve for C directly:
138174

175+
```
139176
C = k × Π((Pᵢ/Wᵢ)^Wᵢ) = TVL = Total pool value
177+
```
140178

141179
The price is then simply TVL / totalSupply.
142180

181+
### ReCLAMM Pools
182+
183+
The same principle can be applied to a ReCLAMM pool, which is in practice a 50/50 weighted pool with virtual balances that concentrate the liquidity in a specified price range.
184+
185+
The ReCLAMM invariant is
186+
187+
```
188+
D = (Ra + Va)(Rb + Vb)
189+
```
190+
191+
where `Ri` represents real balances and `Vi` represents virtual balances.
192+
193+
On the other hand, the spot price of the pool is:
194+
195+
```
196+
P = Tb / Ta = (Rb + Vb) / (Ra + Va)
197+
```
198+
199+
So we can express the invariant in terms of price:
200+
201+
```
202+
D = P (Ra + Va)^2 = (Rb + Vb)^2 / P
203+
```
204+
205+
Isolating total balances:
206+
207+
```
208+
sqrt(D / P) = Ta
209+
sqrt(D * P) = Tb
210+
```
211+
212+
So
213+
214+
```
215+
Ra = Ta - Va = sqrt(D / P) - Va
216+
Rb = Tb - Vb = sqrt(D * P) - Vb
217+
```
218+
219+
With the given price feeds `Pᵢ`, we can find the theoretical real balances `x̃ᵢ = [Ra', Rb']`, and compute the TVL:
220+
221+
```
222+
TVL = Σ (x̃ᵢ × Pᵢ) = Ra' × Pa + Rb' × Pb
223+
```
224+
225+
#### Practical constraints
226+
227+
The calculated `Ra'` and `Rb'` in the step above can be negative, or above the maximum real balance. Therefore it needs to be capped on both ends:
228+
```
229+
Ra' = max(0, Ra');
230+
Ra' = min(Ra', Ra_max)
231+
```
232+
233+
To calculate maximum real balances, we can evaluate the invariant at the edges. In particular, `Ra` is `Ra_max` when `Rb = 0`, and vice versa:
234+
235+
```
236+
D = (Ra_max + Va)(Vb)
237+
D = (Va)(Rb_max + Vb)
238+
```
239+
240+
Isolating max real balances:
241+
242+
```
243+
Ra_max = D / Vb - Va
244+
Rb_max = D / Va - Vb
245+
```
246+
143247
### E-CLP Pools (Elliptic Concentrated Liquidity Pools)
144248

145249
E-CLP pools use a concentrated liquidity mechanism based on an elliptical curve constraint, allowing liquidity to be concentrated within a specified price range [α, β]. Unlike Weighted Pools which use simple power-law invariants or Stable Pools which use polynomial invariants, E-CLPs leverage geometric transformations to map between price space and balance space.
@@ -157,38 +261,50 @@ Given oracle prices P₁ and P₂ for the two tokens, the relative price is r =
157261

158262
When the market price is below the pool's concentrated range, the pool holds only token 1. The effective balance width in price space is:
159263

264+
```
160265
b_P = (A⁻¹·τ(β))_x - (A⁻¹·τ(α))_x
266+
```
161267

162268
And the total value locked is:
163269

270+
```
164271
TVL = b_P × P₁ × invariant
272+
```
165273

166274
**Case 2: r > β (Above the upper price bound)**
167275

168276
When the market price is above the pool's concentrated range, the pool holds only token 2. The effective balance width is:
169277

278+
```
170279
b_P = (A⁻¹·τ(α))_y - (A⁻¹·τ(β))_y
280+
```
171281

172282
And the total value locked is:
173283

284+
```
174285
TVL = b_P × P₂ × invariant
286+
```
175287

176288
**Case 3: α ≤ r ≤ β (Within the concentrated range)**
177289

178290
When the market price is within the pool's range, both tokens are present. We compute the point τ(r) on the ellipse corresponding to the current price ratio, then calculate the effective balance vector:
179291

292+
```
180293
v_x = (A⁻¹·τ(β))_x - (A⁻¹·τ(r))_x
181294
v_y = (A⁻¹·τ(α))_y - (A⁻¹·τ(r))_y
295+
```
182296

183297
The total value is then the scalar product of the price vector and the balance vector:
184298

299+
```
185300
TVL = (P₁ × v_x + P₂ × v_y) × invariant
301+
```
186302

187303
In summary:
188304

189-
* The τ function maps price ratios to points on the ellipse curve, establishing the "fair" position on the curve given market prices
190-
* The A⁻¹ transformation converts points from the ellipse to effective balance space
191-
* The three cases handle the geometric reality that outside the [α, β] range, the pool is single-sided
305+
* The `τ` function maps price ratios to points on the ellipse curve, establishing the "fair" position on the curve given market prices
306+
* The `A⁻¹` transformation converts points from the ellipse to effective balance space
307+
* The three cases handle the geometric reality that outside the `[α, β]` range, the pool is single-sided
192308
* Unlike Weighted Pools where TVL can be computed directly, or Stable Pools where Newton's method solves for a scaling parameter, E-CLP uses geometric projections to determine the effective balances
193309
* The invariant serves as a scaling factor, similar to its role in other pool types
194310

@@ -208,6 +324,6 @@ This paper goes much deeper into the mathematics, providing a rigorous theoretic
208324

209325
It reviews the mathematical properties of the StableSwap function, especially the upper/lower price bounds.
210326

211-
It analyzes Newton's method, proving that the function G(k) is convex (which ensures convergence), and justifies the choice of starting point k₀. Newton's method is iterative, converging on the final value of by refining subsequent guesses, so it is important for performance to start in the right place. The paper proves the existence, uniqueness, and guaranteed monotonic convergence on from k₀.
327+
It analyzes Newton's method, proving that the function `G(k)` is convex (which ensures convergence), and justifies the choice of starting point `k₀`. Newton's method is iterative, converging on the final value of `` by refining subsequent guesses, so it is important for performance to start in the right place. The paper proves the existence, uniqueness, and guaranteed monotonic convergence on `` from `k₀`.
212328

213-
Finally, it analyzes edge cases, and proves that the boundary condition k̃rᵢ - 1 > 0 always holds under all supported conditions (i.e., balances, invariant, and amplification parameter are all > 0, and there are at least two tokens).
329+
Finally, it analyzes edge cases, and proves that the boundary condition `k̃rᵢ - 1 > 0` always holds under all supported conditions (i.e., balances, invariant, and amplification parameter are all > 0, and there are at least two tokens).

0 commit comments

Comments
 (0)