@@ -21,6 +21,7 @@ import { Address } from "@openzeppelin/contracts/utils/Address.sol";
21
21
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol " ;
22
22
import { Math } from "@openzeppelin/contracts/math/Math.sol " ;
23
23
import { SafeMath } from "@openzeppelin/contracts/math/SafeMath.sol " ;
24
+ import { SafeCast } from "@openzeppelin/contracts/utils/SafeCast.sol " ;
24
25
25
26
import { BaseAdapter } from "../lib/BaseAdapter.sol " ;
26
27
import { ICErc20 } from "../interfaces/ICErc20.sol " ;
@@ -30,6 +31,8 @@ import { ICompoundLeverageModule } from "../interfaces/ICompoundLeverageModule.s
30
31
import { ICompoundPriceOracle } from "../interfaces/ICompoundPriceOracle.sol " ;
31
32
import { ISetToken } from "../interfaces/ISetToken.sol " ;
32
33
import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol " ;
34
+ import { IChainlinkAggregatorV3 } from "../interfaces/IChainlinkAggregatorV3.sol " ;
35
+
33
36
34
37
/**
35
38
* @title FlexibleLeverageStrategyAdapter
@@ -44,11 +47,16 @@ import { PreciseUnitMath } from "../lib/PreciseUnitMath.sol";
44
47
* - Update ExecutionSettings struct to split exchangeData into leverExchangeData and deleverExchangeData
45
48
* - Update _lever and _delever internal functions with struct changes
46
49
* - 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
47
54
*/
48
55
contract FlexibleLeverageStrategyAdapter is BaseAdapter {
49
56
using Address for address ;
50
57
using PreciseUnitMath for uint256 ;
51
58
using SafeMath for uint256 ;
59
+ using SafeCast for int256 ;
52
60
53
61
/* ============ Enums ============ */
54
62
@@ -62,12 +70,12 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
62
70
/* ============ Structs ============ */
63
71
64
72
struct ActionInfo {
65
- uint256 collateralPrice; // Price of underlying in precise units (10e18)
66
- uint256 borrowPrice; // Price of underlying in precise units (10e18)
67
73
uint256 collateralBalance; // Balance of underlying held in Compound in base units (e.g. USDC 10e6)
68
74
uint256 borrowBalance; // Balance of underlying borrowed from Compound in base units
69
75
uint256 collateralValue; // Valuation in USD adjusted for decimals in precise units (10e18)
70
76
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
71
79
uint256 setTotalSupply; // Total supply of SetToken
72
80
}
73
81
@@ -79,14 +87,17 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
79
87
}
80
88
81
89
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)
90
101
}
91
102
92
103
struct MethodologySettings {
@@ -671,9 +682,13 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
671
682
function _createActionInfo () internal view returns (ActionInfo memory ) {
672
683
ActionInfo memory rebalanceInfo;
673
684
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);
677
692
678
693
// Calculate stored exchange rate which does not trigger a state update
679
694
uint256 cTokenBalance = strategy.targetCollateralCToken.balanceOf (address (strategy.setToken));
@@ -885,8 +900,8 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
885
900
}
886
901
887
902
/**
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.
890
905
*
891
906
* return uint256 Position units to borrow
892
907
*/
@@ -905,7 +920,7 @@ contract FlexibleLeverageStrategyAdapter is BaseAdapter {
905
920
906
921
/**
907
922
* 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.
909
924
*
910
925
* return uint256 Min position units to repay in borrow asset
911
926
*/
0 commit comments