Skip to content

Commit 642408a

Browse files
committed
feat: add fInverse() function to periphery
1 parent d3ffcf6 commit 642408a

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

src/EulerSwapPeriphery.sol

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {IEVC} from "evc/interfaces/IEthereumVaultConnector.sol";
55
import {IEVault} from "evk/EVault/IEVault.sol";
66
import {IEulerSwapPeriphery} from "./interfaces/IEulerSwapPeriphery.sol";
77
import {IERC20, IEulerSwap, SafeERC20} from "./EulerSwap.sol";
8+
import {Math} from "openzeppelin-contracts/utils/math/Math.sol";
89
import "@uniswap/v4-core/libraries/FullMath.sol";
910

1011
contract EulerSwapPeriphery is IEulerSwapPeriphery {
@@ -189,4 +190,58 @@ contract EulerSwapPeriphery is IEulerSwapPeriphery {
189190
else output = uint256(dy);
190191
}
191192
}
193+
194+
/**
195+
* @notice Computes the inverse of the `f()` function for the EulerSwap liquidity curve.
196+
* @dev Solves for `x` given `y` using the quadratic formula derived from the liquidity curve:
197+
* x = (-b + sqrt(b^2 + 4ac)) / 2a
198+
* Utilises Uniswap's FullMath to avoid overflow and ensures precision with upward rounding.
199+
*
200+
* @param y The y-coordinate input value (must be greater than `y0`).
201+
* @param px Price factor for the x-axis (scaled by 1e18, between 1e18 and 1e36).
202+
* @param py Price factor for the y-axis (scaled by 1e18, between 1e18 and 1e36).
203+
* @param x0 Reference x-value on the liquidity curve (≤ 2^112 - 1).
204+
* @param y0 Reference y-value on the liquidity curve (≤ 2^112 - 1).
205+
* @param c Curve parameter shaping liquidity concentration (scaled by 1e18, between 0 and 1e18).
206+
*
207+
* @return x The computed x-coordinate on the liquidity curve.
208+
*
209+
* @custom:precision Uses rounding up to maintain precision in all calculations.
210+
* @custom:safety FullMath handles potential overflow in the b^2 computation.
211+
* @custom:requirement Input `y` must be strictly greater than `y0`; otherwise, the function will revert.
212+
*/
213+
function fInverse(uint256 y, uint256 px, uint256 py, uint256 x0, uint256 y0, uint256 c)
214+
public
215+
pure
216+
returns (uint256)
217+
{
218+
// A component of the quadratic formula: a = 2 * c
219+
uint256 A = 2 * c;
220+
221+
// B component of the quadratic formula
222+
int256 B = int256((px * (y - y0) + py - 1) / py) - int256((x0 * (2 * c - 1e18) + 1e18 - 1) / 1e18);
223+
224+
// B^2 component, using FullMath for overflow safety
225+
uint256 absB = B < 0 ? uint256(-B) : uint256(B);
226+
uint256 squaredB = FullMath.mulDiv(absB, absB, 1e18) + (absB * absB % 1e18 == 0 ? 0 : 1);
227+
228+
// 4 * A * C component of the quadratic formula
229+
uint256 AC4 = Math.mulDiv(
230+
Math.mulDiv(4 * c, (1e18 - c), 1e18, Math.Rounding.Ceil),
231+
Math.mulDiv(x0, x0, 1e18, Math.Rounding.Ceil),
232+
1e18,
233+
Math.Rounding.Ceil
234+
);
235+
236+
// Discriminant: b^2 + 4ac, scaled up to maintain precision
237+
uint256 discriminant = (squaredB + AC4) * 1e18;
238+
239+
// Square root of the discriminant (rounded up)
240+
uint256 sqrt = Math.sqrt(discriminant);
241+
sqrt = (sqrt * sqrt < discriminant) ? sqrt + 1 : sqrt;
242+
243+
// Compute and return x = fInverse(y) using the quadratic formula
244+
return Math.mulDiv(uint256(int256(sqrt) - B), 1e18, A, Math.Rounding.Ceil);
245+
}
246+
192247
}

0 commit comments

Comments
 (0)