Skip to content

Commit 2ecd816

Browse files
Sachinrichardliang
andauthored
Fix PerpV2 Strategy Extension price feed bug (#12)
* Fix price feed bug * Remove unnecessary file * Add suggested changes; Improve javadoc * Add basePriceDecimalAdjustment as a contract setting * Bump package version Co-authored-by: Richard Liang <[email protected]>
1 parent 75dbcf0 commit 2ecd816

File tree

9 files changed

+210
-128
lines changed

9 files changed

+210
-128
lines changed

contracts/extensions/PerpV2LeverageStrategyExtension.sol

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { PreciseUnitMath } from "@setprotocol/set-protocol-v2/contracts/lib/Prec
3333
import { BaseExtension } from "../lib/BaseExtension.sol";
3434
import { IAccountBalance } from "../interfaces/IAccountBalance.sol";
3535
import { IBaseManager } from "../interfaces/IBaseManager.sol";
36-
import { IChainlinkAggregatorV3 } from "../interfaces/IChainlinkAggregatorV3.sol";
36+
import { IPriceFeed } from "../interfaces/IPriceFeed.sol";
3737
import { IVault } from "../interfaces/IVault.sol";
3838

3939
import { StringArrayUtils } from "../lib/StringArrayUtils.sol";
@@ -70,12 +70,12 @@ contract PerpV2LeverageStrategyExtension is BaseExtension {
7070

7171
struct ActionInfo {
7272
int256 baseBalance; // Balance of virtual base asset from Perp in precise units (10e18). E.g. vWBTC = 10e18
73-
int256 quoteBalance; // Balance of virtual quote asset from Perp in precise units (10e18). E.g. vUSDC = 10e18
73+
int256 quoteBalance; // Balance of virtual quote asset from Perp in precise units (10e18). E.g. vUSD = 10e18
7474
IPerpV2LeverageModule.AccountInfo accountInfo; // Info on perpetual account including, collateral balance, owedRealizedPnl and pendingFunding
7575
int256 basePositionValue; // Valuation in USD adjusted for decimals in precise units (10e18)
7676
int256 quoteValue; // Valuation in USD adjusted for decimals in precise units (10e18)
77-
int256 basePrice; // Price of base asset in precise units (10e18) from Chainlink
78-
int256 quotePrice; // Price of quote asset in precise units (10e18) from Chainlink
77+
int256 basePrice; // Price of base asset in precise units (10e18) from PerpV2 Oracle
78+
int256 quotePrice; // Price of quote asset in precise units (10e18) from PerpV2 Oracle
7979
uint256 setTotalSupply; // Total supply of SetToken
8080
}
8181

@@ -90,8 +90,13 @@ contract PerpV2LeverageStrategyExtension is BaseExtension {
9090
ISetToken setToken; // Instance of leverage token
9191
IPerpV2LeverageModule perpV2LeverageModule; // Instance of Perp V2 leverage module
9292
IAccountBalance perpV2AccountBalance; // Instance of Perp V2 AccountBalance contract used to fetch position balances
93-
IChainlinkAggregatorV3 basePriceOracle; // Chainlink oracle feed that returns prices in 8 decimals for base asset
94-
IChainlinkAggregatorV3 quotePriceOracle; // Chainlink oracle feed that returns prices in 8 decimals for quote asset
93+
IPriceFeed baseUSDPriceOracle; // PerpV2 oracle that returns TWAP price for base asset in USD. IPriceFeed is a PerpV2 specific interface
94+
// to interact with differnt oracle providers, e.g. Band Protocol and Chainlink, for different assets
95+
// listed on PerpV2
96+
uint256 twapInterval; // TWAP interval to be used to fetch base asset price in seconds
97+
// PerpV2 uses a 15 min TWAP interval, i.e. twapInterval = 900
98+
uint256 basePriceDecimalAdjustment; // Decimal adjustment for the price returned by the PerpV2 oracle for the base asset.
99+
// Equal to vBaseAsset.decimals() - baseUSDPriceOracle.decimals()
95100
address virtualBaseAddress; // Address of virtual base asset (e.g. vETH, vWBTC etc)
96101
address virtualQuoteAddress; // Address of virtual USDC quote asset. The Perp V2 system uses USDC for all markets
97102
}
@@ -747,23 +752,25 @@ contract PerpV2LeverageStrategyExtension is BaseExtension {
747752
function _createActionInfo() internal view returns(ActionInfo memory) {
748753
ActionInfo memory rebalanceInfo;
749754

750-
// Calculate prices from chainlink. Chainlink returns prices with 8 decimal places, so we need to adjust by 10 ** 10.
751-
// In Perp v2, virtual tokens all have 18 decimals, therefore we do not need to make further adjustments to determine
752-
// base and quote valuation
753-
int256 rawBasePrice = strategy.basePriceOracle.latestAnswer();
754-
int256 rawQuotePrice = strategy.quotePriceOracle.latestAnswer();
755-
rebalanceInfo.basePrice = rawBasePrice.mul(10 ** 10);
756-
rebalanceInfo.quotePrice = rawQuotePrice.mul(10 ** 10);
755+
// Fetch base token prices from PerpV2 oracles and adjust them to 18 decimal places.
756+
int256 rawBasePrice = strategy.baseUSDPriceOracle.getPrice(strategy.twapInterval).toInt256();
757+
uint256 decimals = strategy.baseUSDPriceOracle.decimals();
758+
rebalanceInfo.basePrice = rawBasePrice.mul((10 ** strategy.basePriceDecimalAdjustment).toInt256());
759+
760+
// vUSD price is fixed to 1$
761+
rebalanceInfo.quotePrice = PreciseUnitMath.preciseUnit().toInt256();
757762

758763
// Note: getTakerPositionSize returns zero if base balance is less than 10 wei
759764
rebalanceInfo.baseBalance = strategy.perpV2AccountBalance.getTakerPositionSize(address(strategy.setToken), strategy.virtualBaseAddress);
760765

761766
// Note: Fetching quote balance associated with a single position and not the net quote balance
762767
rebalanceInfo.quoteBalance = strategy.perpV2AccountBalance.getTakerOpenNotional(address(strategy.setToken), strategy.virtualBaseAddress);
768+
763769
rebalanceInfo.accountInfo = strategy.perpV2LeverageModule.getAccountInfo(strategy.setToken);
764770

771+
// In Perp v2, all virtual tokens have 18 decimals, therefore we do not need to make further adjustments to determine base valuation.
765772
rebalanceInfo.basePositionValue = rebalanceInfo.basePrice.preciseMul(rebalanceInfo.baseBalance);
766-
rebalanceInfo.quoteValue = rebalanceInfo.quotePrice.preciseMul(rebalanceInfo.quoteBalance);
773+
rebalanceInfo.quoteValue = rebalanceInfo.quoteBalance;
767774

768775
rebalanceInfo.setTotalSupply = strategy.setToken.totalSupply();
769776

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: MIT License
2+
pragma solidity 0.6.10;
3+
4+
interface IPriceFeed {
5+
function decimals() external view returns (uint8);
6+
7+
/// @dev Returns the index price of the token.
8+
/// @param interval The interval represents twap interval.
9+
function getPrice(uint256 interval) external view returns (uint256);
10+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
Copyright 2022 Set Labs Inc.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
16+
SPDX-License-Identifier: Apache License, Version 2.0
17+
*/
18+
19+
pragma solidity 0.6.10;
20+
21+
/**
22+
* Mock PerpV2 Price Feed.
23+
*/
24+
contract PerpV2PriceFeedMock {
25+
uint8 public decimals;
26+
uint256 internal price;
27+
28+
constructor(uint8 _decimals) public {
29+
decimals = _decimals;
30+
}
31+
32+
/**
33+
* Typical usage for setting the BaseToken oracle to 100 is:
34+
*
35+
* ```
36+
* await mockPriceFeed.setPrice(ethers.utils.parseUnits("100", decimals));
37+
* ```
38+
*/
39+
function setPrice(uint256 _price) public {
40+
price = _price;
41+
}
42+
43+
44+
/**
45+
* Returns the index price of the token.
46+
*/
47+
function getPrice(uint256 /*interval*/) external view returns (uint256) {
48+
return price;
49+
}
50+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@setprotocol/set-v2-strategies",
3-
"version": "0.0.2",
3+
"version": "0.0.3",
44
"description": "",
55
"main": "dist",
66
"types": "dist/types",

0 commit comments

Comments
 (0)