Skip to content

Commit

Permalink
use frx/weth dual oracle for frxETH price
Browse files Browse the repository at this point in the history
  • Loading branch information
danoctavian committed Jul 31, 2024
1 parent 6d4d6c7 commit 508e830
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 6 deletions.
10 changes: 10 additions & 0 deletions src/external/frax/IFrxEthWethDualOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: BSD 3-Clause License
pragma solidity ^0.8.24;

interface IFrxEthWethDualOracle {

/// @notice The ```getCurveEmaEthPerFrxEth``` function gets the EMA price of frxEth in eth units
/// @dev normalized to match precision of oracle
/// @return _ethPerFrxEth
function getCurveEmaEthPerFrxEth() external view returns (uint256 _ethPerFrxEth);
}
8 changes: 8 additions & 0 deletions src/external/frax/IsfrxETH.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: BSD 3-Clause License
pragma solidity ^0.8.24;

import {IERC4626} from "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";

interface IsfrxETH is IERC4626 {
function pricePerShare() external view returns (uint256);
}
18 changes: 13 additions & 5 deletions src/ynEIGEN/LSDRateProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {IstETH} from "src/external/lido/IstETH.sol";
import {IrETH} from "src/external/rocketpool/IrETH.sol";
import {IswETH} from "src/external/swell/IswETH.sol";
import {ImETHStaking} from "src/external/mantle/ImETHStaking.sol";
import {IFrxEthWethDualOracle} from "src/external/frax/IFrxEthWethDualOracle.sol";
import {IsfrxETH} from "src/external/frax/IsfrxETH.sol";

contract LSDRateProvider {

Expand All @@ -22,6 +24,7 @@ contract LSDRateProvider {

uint256 constant UNIT = 1e18;
address constant FRAX_ASSET = 0xac3E018457B222d93114458476f3E3416Abbe38F; // sfrxETH
address constant FRX_ETH_WETH_DUAL_ORACLE = 0x350a9841956D8B0212EAdF5E14a449CA85FAE1C0; // FrxEthWethDualOracle
address constant LIDO_ASSET = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; // wstETH
address constant RETH_ASSET = 0xae78736Cd615f374D3085123A210448E74Fc6393; // RETH
address constant WOETH_ASSET = 0xDcEe70654261AF21C44c093C300eD3Bb97b78192;
Expand All @@ -47,10 +50,9 @@ contract LSDRateProvider {

/*
This contract uses the rate as provided the protocol that controls the asset.
This approach avoids issues with sourcing market prices that would cause asset value
fluctuation that depends on market price fluctuation
Known risks that require mitigation:
In case one of the LSDs depegs from its ETH price, users can still deposit to ynEigen,
Known current risks:
In case one of the LSDs depegs from its ETH price and the oracles still report the undepegged price,
users can still deposit to ynEigen,
and receive the same amount of shares as though the underlying asset has not depegged yet,
as the protocols below will report the same LSD/ETH price.
*/
Expand All @@ -59,7 +61,13 @@ contract LSDRateProvider {
return IstETH(LIDO_UDERLYING).getPooledEthByShares(UNIT);
}
if (_asset == FRAX_ASSET) {
return IERC4626(FRAX_ASSET).totalAssets() * UNIT / IERC20(FRAX_ASSET).totalSupply();
/* Calculate the price per share of sfrxETH in terms of ETH using the Frax Oracle.
The Frax Oracle provides a time-weighted average price (TWAP) using a curve exponential moving average (EMA)
to smooth out the price fluctuations of ETH per sfrxETH. This helps in obtaining a stable conversion rate.
*/

uint256 frxETHPriceInETH = IFrxEthWethDualOracle(FRX_ETH_WETH_DUAL_ORACLE).getCurveEmaEthPerFrxEth();
return IsfrxETH(FRAX_ASSET).pricePerShare() * frxETHPriceInETH / UNIT;
}
if (_asset == WOETH_ASSET) {
return IERC4626(WOETH_ASSET).previewRedeem(UNIT);
Expand Down
5 changes: 4 additions & 1 deletion test/integration/ynEIGEN/AssetRegistry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {IERC4626} from "lib/openzeppelin-contracts/contracts/interfaces/IERC4626
import {IrETH} from "src/external/rocketpool/IrETH.sol";
import { IwstETH } from "src/external/lido/IwstETH.sol";
import {IstETH} from "src/external/lido/IstETH.sol";
import {IFrxEthWethDualOracle} from "src/external/frax/IFrxEthWethDualOracle.sol";
import {IsfrxETH} from "src/external/frax/IsfrxETH.sol";
import {IAccessControl} from "lib/openzeppelin-contracts/contracts/access/IAccessControl.sol";

import "forge-std/console.sol";
Expand Down Expand Up @@ -145,7 +147,8 @@ contract AssetRegistryTest is ynEigenIntegrationBaseTest {
// End of the Selection
IERC20 asset = IERC20(chainAddresses.lsd.SFRXETH_ADDRESS); // Using wstETH as the asset
address FRAX_ASSET = chainAddresses.lsd.SFRXETH_ADDRESS;
uint256 realRate = IERC4626(FRAX_ASSET).totalAssets() * 1e18 / IERC20(FRAX_ASSET).totalSupply();
IFrxEthWethDualOracle FRX_ETH_WETH_DUAL_ORACLE = IFrxEthWethDualOracle(testAssetUtils.FRX_ETH_WETH_DUAL_ORACLE());
uint256 realRate = IsfrxETH(FRAX_ASSET).pricePerShare() * FRX_ETH_WETH_DUAL_ORACLE.getCurveEmaEthPerFrxEth() / 1e18;
uint256 expectedConvertedAmount = amount * realRate / 1e18; // Calculating the expected converted amount based on the real rate
uint256 convertedAmount = assetRegistry.convertToUnitOfAccount(asset, amount);
assertEq(convertedAmount, expectedConvertedAmount, "Converted amount should match expected value based on real rate");
Expand Down
10 changes: 10 additions & 0 deletions test/utils/TestAssetUtils.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,19 @@ contract TestAssetUtils is Test {
ContractAddresses.ChainAddresses chainAddresses;
ContractAddresses contractAddresses;

address public FRX_ETH_WETH_DUAL_ORACLE;


constructor() {
contractAddresses = new ContractAddresses();
chainAddresses = contractAddresses.getChainAddresses(block.chainid);

if (block.chainid == 1) {
FRX_ETH_WETH_DUAL_ORACLE = 0x350a9841956D8B0212EAdF5E14a449CA85FAE1C0;
} else if (block.chainid == 17000) {
// UNAVAILABLE
FRX_ETH_WETH_DUAL_ORACLE = address(0x0);
}
}

function get_Asset(address asset, address receiver, uint256 amount) public returns (uint256 balance) {
Expand Down

0 comments on commit 508e830

Please sign in to comment.