Line data Source code
1 : // SPDX-License-Identifier: MIT
2 :
3 : pragma solidity ^0.6.12;
4 : pragma experimental ABIEncoderV2;
5 :
6 : // OZ Imports
7 :
8 : import { AdminUpgradeableProxy } from "../common/AdminUpgradeableProxy.sol";
9 :
10 : // Tornado imports
11 :
12 : import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/ITornadoInstance.sol";
13 :
14 : // Local V2 imports
15 :
16 : import { FeeOracleManager } from "../v2/FeeOracleManager.sol";
17 :
18 : import { InstanceRegistry } from "../v2/InstanceRegistry.sol";
19 :
20 : import { CurveFeeOracle, ICurvePriceOracle, CurveChainedOracles } from "../v2/CurveFeeOracle.sol";
21 :
22 : import { UniswapFeeOracle } from "../v2/UniswapFeeOracle.sol";
23 :
24 : import { TornadoRouter } from "../v2/TornadoRouter.sol";
25 :
26 : /**
27 : * @title CRVUSDInstancesProposal
28 : * @author AlienTornadosaurusHex
29 : * @notice Proposal to add crvUSD instances in 100, 1000, 10000, 100000, 1000000 denominations.
30 : */
31 : contract CRVUSDInstancesProposal {
32 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
33 :
34 : /* @dev The first Curve pool which is capable of being used as a safe oracle due to analytical EMA price */
35 : address public constant crvUSDUSDCStableswap2Pool = 0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E;
36 :
37 : /* @dev The second Curve pool which is capable of being used as a safe oracle due to analytical EMA price */
38 : address public constant tricryptoUSDCPool = 0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B;
39 :
40 : /* @dev The InstanceRegistry contract, for registering instances, proxy must be upgraded */
41 : InstanceRegistry public constant instanceRegistry =
42 : InstanceRegistry(0xB20c66C4DE72433F3cE747b58B86830c459CA911);
43 :
44 : /* @dev The FeeOracleManager contract, proxy must be upgraded */
45 : FeeOracleManager public constant feeOracleManager =
46 : FeeOracleManager(0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7);
47 :
48 : /* @dev This is the Uniswap V3 Oracle which we will use for all of our traditional instances, but it will
49 : also help the Curve instances, the former must have been deployed with the address of this */
50 : UniswapFeeOracle public immutable uniswapFeeOracle;
51 :
52 : /* @dev This is the CurveFeeOracle contract which will be deployed beforehand and which will be able to
53 : use multiple Curve pools as oracles, at once. */
54 : CurveFeeOracle public immutable curveFeeOracle;
55 :
56 : /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LOGIC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
57 :
58 : constructor(address _deployedCurveFeeOracleAddress, address _deployedUniswapFeeOracleAddress) public {
59 : curveFeeOracle = CurveFeeOracle(_deployedCurveFeeOracleAddress);
60 : uniswapFeeOracle = UniswapFeeOracle(_deployedUniswapFeeOracleAddress);
61 : }
62 :
63 : /**
64 : * @dev This function also executes further internal functions inlined below.
65 : */
66 : function executeProposal() external {
67 : // Load the deployed crvUSD instances
68 :
69 2 : ITornadoInstance cu100 = ITornadoInstance(0x913a73486Dc4AA3832A56d461542836C1eeB93be);
70 2 : ITornadoInstance cu1_000 = ITornadoInstance(0x5A6b3C829dB3e938C885000c6E93CF35E74876a4);
71 2 : ITornadoInstance cu10_000 = ITornadoInstance(0x49f173CDAB99a2C3800F1255393DF9B7a17B82Bb);
72 2 : ITornadoInstance cu100_000 = ITornadoInstance(0x4640Dffc9fD0B113B983e3A350b070a119CA143C);
73 2 : ITornadoInstance cu1_000_000 = ITornadoInstance(0xc4eA8Bd3Fd76f3c255395793B47F7c55aD59d991);
74 :
75 : // Ok, first add the Uniswap V3 Oracle to the contract
76 :
77 2 : curveFeeOracle.setUniswapFeeOracle(uniswapFeeOracle);
78 :
79 : // Then, add necessary oracles for the CRVUSD price, to the CurveFeeOracle
80 :
81 2 : _setCurveFeeChainedOracleForInstance(curveFeeOracle, cu100);
82 2 : _setCurveFeeChainedOracleForInstance(curveFeeOracle, cu1_000);
83 2 : _setCurveFeeChainedOracleForInstance(curveFeeOracle, cu10_000);
84 2 : _setCurveFeeChainedOracleForInstance(curveFeeOracle, cu100_000);
85 2 : _setCurveFeeChainedOracleForInstance(curveFeeOracle, cu1_000_000);
86 :
87 : // Then, add the instances to the InstanceRegistry
88 :
89 2 : instanceRegistry.addInstance(cu100);
90 2 : instanceRegistry.addInstance(cu1_000);
91 2 : instanceRegistry.addInstance(cu10_000);
92 2 : instanceRegistry.addInstance(cu100_000);
93 2 : instanceRegistry.addInstance(cu1_000_000);
94 :
95 : // Finally, set all necessary data in the FeeOracleManager
96 :
97 2 : feeOracleManager.setFeeOracle(address(cu100), address(curveFeeOracle));
98 2 : feeOracleManager.setFeeOracle(address(cu1_000), address(curveFeeOracle));
99 2 : feeOracleManager.setFeeOracle(address(cu10_000), address(curveFeeOracle));
100 2 : feeOracleManager.setFeeOracle(address(cu100_000), address(curveFeeOracle));
101 2 : feeOracleManager.setFeeOracle(address(cu1_000_000), address(curveFeeOracle));
102 :
103 : // The fee will be 0.3 % for those pools for which it makes sense
104 :
105 2 : feeOracleManager.setFeePercentForInstance(cu100, 0);
106 2 : feeOracleManager.setFeePercentForInstance(cu1_000, 0);
107 2 : feeOracleManager.setFeePercentForInstance(cu10_000, 30);
108 2 : feeOracleManager.setFeePercentForInstance(cu100_000, 30);
109 2 : feeOracleManager.setFeePercentForInstance(cu1_000_000, 30);
110 :
111 : // Make the update interval 6 hours
112 :
113 2 : feeOracleManager.setFeeUpdateIntervalForInstance(cu100, 6 hours);
114 2 : feeOracleManager.setFeeUpdateIntervalForInstance(cu1_000, 6 hours);
115 2 : feeOracleManager.setFeeUpdateIntervalForInstance(cu10_000, 6 hours);
116 2 : feeOracleManager.setFeeUpdateIntervalForInstance(cu100_000, 6 hours);
117 2 : feeOracleManager.setFeeUpdateIntervalForInstance(cu1_000_000, 6 hours);
118 :
119 : // Update them all at the start
120 :
121 2 : address router = feeOracleManager.feeUpdaterAddress();
122 :
123 2 : feeOracleManager.setFeeUpdater(address(this));
124 :
125 2 : feeOracleManager.updateFee(cu100, false);
126 2 : feeOracleManager.updateFee(cu1_000, false);
127 2 : feeOracleManager.updateFee(cu10_000, false);
128 2 : feeOracleManager.updateFee(cu100_000, false);
129 2 : feeOracleManager.updateFee(cu1_000_000, false);
130 :
131 2 : feeOracleManager.setFeeUpdater(router);
132 : }
133 :
134 : /**
135 : * @dev This function adds pools as fee oracles to the main curve fee oracle contract. The oracles are
136 : * chained, this means that multiple pools can be used as one oracle using the library which can be found
137 : * in the contract file. This means:
138 : *
139 : * (...pool contracts as oracles) ===(`price_oracle`)===> CurveFeeOracle ===(`getFee()`)===>
140 : * FeeOracleManager ===(`instanceFeeWithUpdate`)===> RelayerRegistry
141 : */
142 : function _setCurveFeeChainedOracleForInstance(CurveFeeOracle _feeOracle, ITornadoInstance _instance)
143 : internal
144 : {
145 : // Add the oracles which are the USDC/CRVUSD stableswap and tricryptoUSDC pools
146 :
147 10 : ICurvePriceOracle[] memory _oracles = new ICurvePriceOracle[](2);
148 :
149 10 : _oracles[0] = ICurvePriceOracle(crvUSDUSDCStableswap2Pool);
150 10 : _oracles[1] = ICurvePriceOracle(tricryptoUSDCPool);
151 :
152 : // Add the selectors, so which functions to call because tricrypto pools supports getting prices for
153 : // multiple tokens, denominated in the first token, which is usually a stable
154 :
155 10 : bytes4[] memory _selectors = new bytes4[](2);
156 :
157 10 : _selectors[0] = CurveChainedOracles.PRICE_ORACLE_SELECTOR;
158 10 : _selectors[1] = CurveChainedOracles.PRICE_ORACLE_UINT256_SELECTOR;
159 :
160 : // Specify for the second that the ether price must be retrieved
161 :
162 10 : uint8[] memory _coins = new uint8[](2);
163 :
164 10 : _coins[1] = 1; // ETHER
165 :
166 : // In order to receive the CRVUSD price, its price in USDC must be read out (the USDC price in crvUSD
167 : // is worthless because we do not have a common denominator in the oracle then) and then the second
168 : // price must be inverted to receive the accurate ETH/CRVUSD price, meaning ETH per CRVUSD, which will
169 : // then be divided by ETH per TORN, and then (ETH/CRVUSD)/(ETH/TORN) = (ETH/CRVUSD)*(TORN/ETH) =
170 : // (TORN/CRVUSD) which is the price that the oracle should be supplying
171 :
172 10 : bool[] memory _invert = new bool[](2);
173 :
174 10 : _invert[0] = false; // DO NOT INVERT, PRICE IS CRVUSD IN USDC
175 10 : _invert[1] = true; // INVERT, PRICE IS ETH IN USDC, BUT WE NEED USDC IN ETH
176 :
177 : // (USDC/CRVUSD)*(ETH/USDC) = (ETH/CRVUSD)
178 :
179 10 : _feeOracle.modifyChainedOracleForInstance(
180 : _instance, _oracles, _selectors, _coins, _invert, "ETH/CRVUSD"
181 : );
182 : }
183 : }
|