Skip to content

Commit 3b8e8af

Browse files
authored
Add Chainlink oracles to FlexibleLeverageStrategyAdapter (#47)
* use chainlink in fli * switch completely to chainlink * fix tests * refactor * improve comments * improve decimal adjustment comment * fix decimal comment * bump package version
1 parent a43400c commit 3b8e8af

File tree

13 files changed

+159
-1014
lines changed

13 files changed

+159
-1014
lines changed

contracts/adapters/FlexibleLeverageStrategyAdapter.sol

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { Address } from "@openzeppelin/contracts/utils/Address.sol";
2121
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
2222
import { Math } from "@openzeppelin/contracts/math/Math.sol";
2323
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol";
24+
import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol";
2425

2526
import { BaseAdapter } from "../lib/BaseAdapter.sol";
2627
import { ICErc20 } from "../interfaces/ICErc20.sol";
@@ -30,6 +31,8 @@ import { ICompoundLeverageModule } from "../interfaces/ICompoundLeverageModule.s
3031
import { ICompoundPriceOracle } from "../interfaces/ICompoundPriceOracle.sol";
3132
import { ISetToken } from "../interfaces/ISetToken.sol";
3233
import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";
34+
import { IChainlinkAggregatorV3 } from "../interfaces/IChainlinkAggregatorV3.sol";
35+
3336

3437
/**
3538
* @title FlexibleLeverageStrategyAdapter
@@ -44,11 +47,16 @@ import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";
4447
* - Update ExecutionSettings struct to split exchangeData into leverExchangeData and deleverExchangeData
4548
* - Update _lever and _delever internal functions with struct changes
4649
* - Update setExecutionSettings to account for leverExchangeData and deleverExchangeData
50+
*
51+
* CHANGELOG 5/24/2021:
52+
* - Update _calculateActionInfo to add chainlink prices
53+
* - Update _calculateBorrowUnits and _calculateMinRepayUnits to use chainlink as an oracle in
4754
*/
4855
contract FlexibleLeverageStrategyAdapter is BaseAdapter {
4956
using Address for address;
5057
using PreciseUnitMath for uint256;
5158
using SafeMath for uint256;
59+
using SafeCast for int256;
5260

5361
/* ============ Enums ============ */
5462

@@ -62,12 +70,12 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
6270
/* ============ Structs ============ */
6371

6472
struct ActionInfo {
65-
uint256 collateralPrice; // Price of underlying in precise units (10e18)
66-
uint256 borrowPrice; // Price of underlying in precise units (10e18)
6773
uint256 collateralBalance; // Balance of underlying held in Compound in base units (e.g. USDC 10e6)
6874
uint256 borrowBalance; // Balance of underlying borrowed from Compound in base units
6975
uint256 collateralValue; // Valuation in USD adjusted for decimals in precise units (10e18)
7076
uint256 borrowValue; // Valuation in USD adjusted for decimals in precise units (10e18)
77+
uint256 collateralPrice; // Price of collateral in precise units (10e18) from Chainlink
78+
uint256 borrowPrice; // Price of borrow asset in precise units (10e18) from Chainlink
7179
uint256 setTotalSupply; // Total supply of SetToken
7280
}
7381

@@ -79,14 +87,17 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
7987
}
8088

8189
struct ContractSettings {
82-
ISetToken setToken; // Instance of leverage token
83-
ICompoundLeverageModule leverageModule; // Instance of Compound leverage module
84-
IComptroller comptroller; // Instance of Compound Comptroller
85-
ICompoundPriceOracle priceOracle; // Compound open oracle feed that returns prices accounting for decimals. e.g. USDC 6 decimals = 10^18 * 10^18 / 10^6
86-
ICErc20 targetCollateralCToken; // Instance of target collateral cToken asset
87-
ICErc20 targetBorrowCToken; // Instance of target borrow cToken asset
88-
address collateralAsset; // Address of underlying collateral
89-
address borrowAsset; // Address of underlying borrow asset
90+
ISetToken setToken; // Instance of leverage token
91+
ICompoundLeverageModule leverageModule; // Instance of Compound leverage module
92+
IComptroller comptroller; // Instance of Compound Comptroller
93+
IChainlinkAggregatorV3 collateralPriceOracle; // Chainlink oracle feed that returns prices in 8 decimals for collateral asset
94+
IChainlinkAggregatorV3 borrowPriceOracle; // Chainlink oracle feed that returns prices in 8 decimals for borrow asset
95+
ICErc20 targetCollateralCToken; // Instance of target collateral cToken asset
96+
ICErc20 targetBorrowCToken; // Instance of target borrow cToken asset
97+
address collateralAsset; // Address of underlying collateral
98+
address borrowAsset; // Address of underlying borrow asset
99+
uint256 collateralDecimalAdjustment; // Decimal adjustment for chainlink oracle of the collateral asset. Equal to 28-collateralDecimals (10^18 * 10^18 / 10^decimals / 10^8)
100+
uint256 borrowDecimalAdjustment; // Decimal adjustment for chainlink oracle of the borrowing asset. Equal to 28-borrowDecimals (10^18 * 10^18 / 10^decimals / 10^8)
90101
}
91102

92103
struct MethodologySettings {
@@ -671,9 +682,13 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
671682
function _createActionInfo() internal view returns(ActionInfo memory) {
672683
ActionInfo memory rebalanceInfo;
673684

674-
// IMPORTANT: Compound oracle returns prices adjusted for decimals. USDC is 6 decimals so $1 * 10^18 * 10^18 / 10^6 = 10^30
675-
rebalanceInfo.collateralPrice = strategy.priceOracle.getUnderlyingPrice(address(strategy.targetCollateralCToken));
676-
rebalanceInfo.borrowPrice = strategy.priceOracle.getUnderlyingPrice(address(strategy.targetBorrowCToken));
685+
// Calculate prices from chainlink. Adjusts decimals to be in line with Compound's oracles. Chainlink returns prices with 8 decimal places, but
686+
// compound expects 36 - underlyingDecimals decimal places from their oracles. This is so that when the underlying amount is multiplied by the
687+
// received price, the collateral valuation is normalized to 36 decimals. To perform this adjustment, we multiply by 10^(36 - 8 - underlyingDeciamls)
688+
int256 rawCollateralPrice = strategy.collateralPriceOracle.latestAnswer();
689+
rebalanceInfo.collateralPrice = rawCollateralPrice.toUint256().mul(10 ** strategy.collateralDecimalAdjustment);
690+
int256 rawBorrowPrice = strategy.borrowPriceOracle.latestAnswer();
691+
rebalanceInfo.borrowPrice = rawBorrowPrice.toUint256().mul(10 ** strategy.borrowDecimalAdjustment);
677692

678693
// Calculate stored exchange rate which does not trigger a state update
679694
uint256 cTokenBalance = strategy.targetCollateralCToken.balanceOf(address(strategy.setToken));
@@ -885,8 +900,8 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
885900
}
886901

887902
/**
888-
* Derive the borrow units for lever. The units are calculated by the collateral units multiplied by collateral / borrow asset price. Compound oracle prices
889-
* already adjust for decimals in the token.
903+
* Derive the borrow units for lever. The units are calculated by the collateral units multiplied by collateral / borrow asset price. Oracle prices
904+
* have already been adjusted for the decimals in the token.
890905
*
891906
* return uint256 Position units to borrow
892907
*/
@@ -905,7 +920,7 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
905920

906921
/**
907922
* Derive the min repay units from collateral units for delever. Units are calculated as target collateral rebalance units multiplied by slippage tolerance
908-
* and pair price (collateral oracle price / borrow oracle price). Compound oracle prices already adjust for decimals in the token.
923+
* and pair price (collateral oracle price / borrow oracle price). Oracle prices have already been adjusted for the decimals in the token.
909924
*
910925
* return uint256 Min position units to repay in borrow asset
911926
*/
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pragma solidity 0.6.10;
2+
3+
interface IChainlinkAggregatorV3 {
4+
function latestAnswer() external view returns (int256);
5+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
pragma solidity 0.6.10;
2+
3+
4+
contract ChainlinkAggregatorV3Mock {
5+
6+
int256 private latestPrice;
7+
8+
constructor() public {
9+
latestPrice = 0;
10+
}
11+
12+
function setPrice(int256 _price) external {
13+
latestPrice = _price;
14+
}
15+
16+
function latestAnswer() external view returns (int256) {
17+
return latestPrice;
18+
}
19+
}

contracts/viewers/FLIRebalanceViewer.sol

Lines changed: 0 additions & 221 deletions
This file was deleted.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@setprotocol/index-coop-contracts",
3-
"version": "0.0.15",
3+
"version": "0.0.17",
44
"description": "",
55
"main": "dist",
66
"types": "dist/types",

0 commit comments

Comments
 (0)