-
Notifications
You must be signed in to change notification settings - Fork 32
ZenBull strategy oracle #517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
iamsahu
wants to merge
9
commits into
master
Choose a base branch
from
feat/zenBullStrategy-oracle
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
cc0ceae
feat: zen bull oracle
iamsahu 6d5100c
feat: working oracle
iamsahu bab416d
fix: corrected the calculation
iamsahu 6e66951
chore: comments
iamsahu 7e0c864
fix: working oracle
iamsahu 3476d88
fix: removed intermediate conversions
iamsahu 846acbc
fix: simplified calculation
iamsahu 0deb155
feat: removed stack too deep issue
iamsahu 180928e
Merge branch 'master' into feat/zenBullStrategy-oracle
iamsahu File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
176 changes: 176 additions & 0 deletions
176
packages/foundry/contracts/oracles/opyn/ZenBullOracle.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity >=0.8.13; | ||
|
|
||
| import "@yield-protocol/utils-v2/contracts/cast/CastBytes32Bytes6.sol"; | ||
| import {wadPow, wadDiv, wadMul} from "solmate/utils/SignedWadMath.sol"; | ||
| import "@yield-protocol/utils-v2/contracts/token/IERC20.sol"; | ||
| import "../../interfaces/IOracle.sol"; | ||
| import {ICrabStrategy} from "./CrabOracle.sol"; | ||
| import {IUniswapV3PoolState} from "../uniswap/uniswapv0.8/pool/IUniswapV3PoolState.sol"; | ||
| import "forge-std/src/console.sol"; | ||
|
|
||
| error ZenBullOracleUnsupportedAsset(); | ||
|
|
||
| interface IZenBullStrategy { | ||
| /** | ||
| * @notice return the internal accounting of the bull strategy's crab balance | ||
| * @return crab token amount hold by the bull strategy | ||
| */ | ||
| function getCrabBalance() external view returns (uint256); | ||
|
|
||
| /** | ||
| * @notice get crab vault debt and collateral details | ||
| * @return vault eth collateral, vault wPowerPerp debt | ||
| */ | ||
| function getCrabVaultDetails() external view returns (uint256, uint256); | ||
|
|
||
| function totalSupply() external view returns (uint256); | ||
| } | ||
|
|
||
| /// @notice Returns price of zen bull token in USDC & vice versa | ||
| /// @dev Based on calculations provided by Opyn team https://gist.github.com/iamsahu/91428eb2029f4a78eabbe26ed7490087 | ||
| contract ZenBullOracle is IOracle { | ||
| using CastBytes32Bytes6 for bytes32; | ||
|
|
||
| ICrabStrategy public immutable crabStrategy; | ||
| IZenBullStrategy public immutable zenBullStrategy; | ||
| IUniswapV3PoolState public immutable osqthWethPool; | ||
| IUniswapV3PoolState public immutable wethUsdcPool; | ||
| IERC20 public immutable eulerDToken; | ||
| IERC20 public immutable eulerEToken; | ||
| bytes6 public immutable usdcId; | ||
| bytes6 public immutable zenBullId; | ||
|
|
||
| event SourceSet( | ||
| ICrabStrategy crabStrategy, | ||
| IZenBullStrategy zenBullStrategy, | ||
| IUniswapV3PoolState osqthWethPool, | ||
| IUniswapV3PoolState wethUsdcPool, | ||
| IERC20 eulerDToken, | ||
| IERC20 eulerEToken | ||
| ); | ||
|
|
||
| constructor( | ||
| ICrabStrategy crabStrategy_, | ||
| IZenBullStrategy zenBullStrategy_, | ||
| IUniswapV3PoolState osqthWethPool_, | ||
| IUniswapV3PoolState wethUsdcPool_, | ||
| IERC20 eulerDToken_, | ||
| IERC20 eulerEToken_, | ||
| bytes6 usdcId_, | ||
| bytes6 zenBullId_ | ||
| ) { | ||
| crabStrategy = crabStrategy_; | ||
| zenBullStrategy = zenBullStrategy_; | ||
| osqthWethPool = osqthWethPool_; | ||
| wethUsdcPool = wethUsdcPool_; | ||
| eulerDToken = eulerDToken_; | ||
| eulerEToken = eulerEToken_; | ||
| usdcId = usdcId_; | ||
| zenBullId = zenBullId_; | ||
| emit SourceSet( | ||
| crabStrategy_, | ||
| zenBullStrategy_, | ||
| osqthWethPool_, | ||
| wethUsdcPool_, | ||
| eulerDToken_, | ||
| eulerEToken_ | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Retrieve the value of the amount at the latest oracle price. | ||
| * Only `zenBullId` and `usdcId` are accepted as asset identifiers. | ||
| */ | ||
| function peek( | ||
| bytes32 base, | ||
| bytes32 quote, | ||
| uint256 baseAmount | ||
| ) | ||
| external | ||
| view | ||
| virtual | ||
| override | ||
| returns (uint256 quoteAmount, uint256 updateTime) | ||
| { | ||
| return _peek(base.b6(), quote.b6(), baseAmount); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Retrieve the value of the amount at the latest oracle price. Same as `peek` for this oracle. | ||
| * Only `zenBullId` and `usdcId` are accepted as asset identifiers. | ||
| */ | ||
| function get( | ||
| bytes32 base, | ||
| bytes32 quote, | ||
| uint256 baseAmount | ||
| ) | ||
| external | ||
| virtual | ||
| override | ||
| returns (uint256 quoteAmount, uint256 updateTime) | ||
| { | ||
| return _peek(base.b6(), quote.b6(), baseAmount); | ||
| } | ||
|
|
||
| /** | ||
| * @notice Retrieve the value of the amount at the latest oracle price. | ||
| */ | ||
| function _peek( | ||
| bytes6 base, | ||
| bytes6 quote, | ||
| uint256 baseAmount | ||
| ) private view returns (uint256 quoteAmount, uint256 updateTime) { | ||
| if (base == zenBullId && quote == usdcId) { | ||
| quoteAmount = (_getZenBullPrice() * baseAmount) / 1e18; | ||
| } else if (base == usdcId && quote == zenBullId) { | ||
| quoteAmount = (baseAmount * 1e18) / _getZenBullPrice(); | ||
| } else { | ||
| revert ZenBullOracleUnsupportedAsset(); | ||
| } | ||
| updateTime = block.timestamp; | ||
| } | ||
|
|
||
| /** | ||
| * @notice Calculates the price of one zen bull token in USDC | ||
| */ | ||
| function _getZenBullPrice() private view returns (uint256) { | ||
| uint256 bullUSDCDebtBalance = eulerDToken.balanceOf( | ||
| address(zenBullStrategy) | ||
| ); | ||
| uint256 bullWethCollateralBalance = eulerEToken.balanceOf( | ||
| address(zenBullStrategy) | ||
| ); | ||
| uint256 bullCrabBalance = zenBullStrategy.getCrabBalance(); | ||
| (uint256 crabEthBalance, uint256 craboSqthBalance) = zenBullStrategy | ||
| .getCrabVaultDetails(); | ||
| uint256 crabTotalSupply = crabStrategy.totalSupply(); | ||
| uint256 bullTotalSupply = zenBullStrategy.totalSupply(); | ||
| (, int24 tick, , , , , ) = osqthWethPool.slot0(); | ||
| int256 osqthWethPrice = wadDiv( | ||
| 1e18, | ||
| wadPow(10001e14, int256(tick) * 1e18) | ||
| ); | ||
|
iamsahu marked this conversation as resolved.
Outdated
|
||
| (, tick, , , , , ) = wethUsdcPool.slot0(); | ||
| int256 wethUsdcPrice = wadDiv( | ||
| 1e18, | ||
| wadPow(10001e14, int256(tick) * 1e18) | ||
| ); | ||
|
|
||
| int256 crabUsdcValue = wadMul(int256(crabEthBalance), wethUsdcPrice) - | ||
|
iamsahu marked this conversation as resolved.
Outdated
|
||
| wadMul( | ||
| int256(craboSqthBalance), | ||
| wadMul(osqthWethPrice, wethUsdcPrice) | ||
| ); | ||
|
|
||
| int256 crabUsdcPrice = wadDiv(crabUsdcValue, int256(crabTotalSupply)); | ||
| int256 bullUsdcValue = wadMul(int256(bullCrabBalance), crabUsdcPrice) + | ||
| wadMul(int256(bullWethCollateralBalance), wethUsdcPrice) - | ||
| int256(bullUSDCDebtBalance); | ||
|
|
||
| uint256 bullUsdcPrice = uint256( | ||
| wadDiv(bullUsdcValue, int256(bullTotalSupply)) | ||
| ); | ||
| return bullUsdcPrice; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
59 changes: 59 additions & 0 deletions
59
packages/foundry/contracts/test/oracles/ZenBullOracleTest.t.sol
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please deploy on a fork, and use that to code a test harness that verifies that the ZenBullPrice obtained is within an order of magnitude of something. If ZenBull is expected to stay within 0.1 ETH and 10 ETH most of the time, that would be a good range to test against. |
||
| pragma solidity >=0.8.13; | ||
|
|
||
| import "forge-std/src/Test.sol"; | ||
| import "@yield-protocol/utils-v2/contracts/access/AccessControl.sol"; | ||
| import "../../oracles/opyn/ZenBullOracle.sol"; | ||
| import {IZenBullStrategy} from "../../oracles/opyn/ZenBullOracle.sol"; | ||
| import "../../oracles/uniswap/UniswapV3Oracle.sol"; | ||
| import "../utils/TestConstants.sol"; | ||
| import {wadPow, wadDiv} from "solmate/utils/SignedWadMath.sol"; | ||
|
|
||
| contract ZenBullOracleTest is Test, TestConstants { | ||
| ZenBullOracle public zenBullOracle; | ||
|
|
||
| ICrabStrategy crabStrategy_ = | ||
| ICrabStrategy(0x3B960E47784150F5a63777201ee2B15253D713e8); | ||
| IZenBullStrategy zenBullStrategy_ = | ||
| IZenBullStrategy(0xb46Fb07b0c80DBC3F97cae3BFe168AcaD46dF507); | ||
| IUniswapV3PoolState osqthWethPool_ = | ||
| IUniswapV3PoolState(0x82c427AdFDf2d245Ec51D8046b41c4ee87F0d29C); | ||
| IUniswapV3PoolState wethUsdcPool_ = | ||
| IUniswapV3PoolState(0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8); | ||
| IERC20 eulerDToken_ = IERC20(0x84721A3dB22EB852233AEAE74f9bC8477F8bcc42); | ||
| IERC20 eulerEToken_ = IERC20(0x1b808F49ADD4b8C6b5117d9681cF7312Fcf0dC1D); | ||
|
|
||
| function setUp() public { | ||
| vm.createSelectFork(MAINNET, 16468440); | ||
| zenBullOracle = new ZenBullOracle( | ||
| crabStrategy_, | ||
| zenBullStrategy_, | ||
| osqthWethPool_, | ||
| wethUsdcPool_, | ||
| eulerDToken_, | ||
| eulerEToken_, | ||
| USDC, | ||
| ZENBULL | ||
| ); | ||
| } | ||
|
|
||
| function testPeek() public { | ||
| (uint256 amount, ) = zenBullOracle.peek( | ||
| bytes32(ZENBULL), | ||
| bytes32(USDC), | ||
| 1e18 | ||
| ); | ||
| emit log_named_uint("Zenbull in USDC Value", amount); | ||
| assertEq(amount, 3475041114); | ||
| } | ||
|
|
||
| function testPeekReversed() public { | ||
| (uint256 amount, ) = zenBullOracle.peek( | ||
| bytes32(USDC), | ||
| bytes32(ZENBULL), | ||
| 1e6 | ||
| ); | ||
| emit log_named_uint("USDC in Zenbull Value", amount); | ||
| assertEq(amount, 287766379503042); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.