Working oracle

Signed-off-by: AlienTornadosaurusHex <>
This commit is contained in:
AlienTornadosaurusHex 2023-06-16 19:49:44 +00:00
parent 1578f5ac69
commit 3f93127d19
6 changed files with 330 additions and 186 deletions

@ -195,7 +195,7 @@ contract CurveFeeOracle is IFeeOracle {
/**
* @notice We will not need the Uniswap V3 Oracle forever though, TORN/ETH pools are possible on Curve too
*/
bool public tornOracleIsUniswapV3;
bool public tornOracleIsUniswap;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EVENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@ -208,7 +208,7 @@ contract CurveFeeOracle is IFeeOracle {
constructor(address _governanceProxyAddress) public {
governanceProxyAddress = _governanceProxyAddress;
tornOracleIsUniswapV3 = true;
tornOracleIsUniswap = true;
}
modifier onlyGovernance() {
@ -236,11 +236,11 @@ contract CurveFeeOracle is IFeeOracle {
// If the below is true, then this will finalize the price and give the TOKEN price in TORN
// Above MUST be TOKEN price in ETH, then (ETH/TOKEN)/(ETH/TORN)=TORN/TOKEN, meaning the TOKEN price
// in TORN
if (tornOracleIsUniswapV3) {
price = price * UniswapV3OracleHelper.RATIO_DIVIDER
/ uniswapFeeOracle.getTokenPerTORN(
if (tornOracleIsUniswap) {
price = price
* uniswapFeeOracle.getTORNPerToken(
IERC20(UniswapV3OracleHelper.WETH), _instance.fee.updateInterval
);
) / UniswapV3OracleHelper.RATIO_DIVIDER;
}
// The price is now either prepared by the chained oracles or by Uniswap V3, in any case we do the
@ -304,7 +304,7 @@ contract CurveFeeOracle is IFeeOracle {
}
function setTornOracleIsUniswap(bool _is) public virtual onlyGovernance {
tornOracleIsUniswapV3 = _is;
tornOracleIsUniswap = _is;
if (_is) emit TornOracleIsUniswapV3();
else emit TornOracleIsCurve();
}

@ -19,169 +19,18 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
// Local imports
import { IUniswapV2Pair } from "./interfaces/IUniswapV2Pair.sol";
import { IFeeOracle, InstanceWithFee } from "./interfaces/IFeeOracle.sol";
import { UniswapV3OracleHelper } from "./libraries/UniswapV3OracleHelper.sol";
import { UniswapV2OracleLibrary } from "./libraries/UniswapV2OracleLibrary.sol";
import { FixedPoint } from "./libraries/FixedPoint.sol";
import { InstanceState } from "./InstanceRegistry.sol";
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UNISWAP INLINED ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function mint(address to) external returns (uint256 liquidity);
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
library FixedPoint {
// range: [0, 2**112 - 1]
// resolution: 1 / 2**112
struct uq112x112 {
uint224 _x;
}
// range: [0, 2**144 - 1]
// resolution: 1 / 2**112
struct uq144x112 {
uint256 _x;
}
uint8 private constant RESOLUTION = 112;
// encode a uint112 as a UQ112x112
function encode(uint112 x) internal pure returns (uq112x112 memory) {
return uq112x112(uint224(x) << RESOLUTION);
}
// encodes a uint144 as a UQ144x112
function encode144(uint144 x) internal pure returns (uq144x112 memory) {
return uq144x112(uint256(x) << RESOLUTION);
}
// divide a UQ112x112 by a uint112, returning a UQ112x112
function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) {
require(x != 0, "FixedPoint: DIV_BY_ZERO");
return uq112x112(self._x / uint224(x));
}
// multiply a UQ112x112 by a uint, returning a UQ144x112
// reverts on overflow
function mul(uq112x112 memory self, uint256 y) internal pure returns (uq144x112 memory) {
uint256 z;
require(
y == 0 || (z = uint256(self._x) * y) / y == uint256(self._x),
"FixedPoint: MULTIPLICATION_OVERFLOW"
);
return uq144x112(z);
}
// returns a UQ112x112 which represents the ratio of the numerator to the denominator
// equivalent to encode(numerator).div(denominator)
function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) {
require(denominator > 0, "FixedPoint: DIV_BY_ZERO");
return uq112x112((uint224(numerator) << RESOLUTION) / denominator);
}
// decode a UQ112x112 into a uint112 by truncating after the radix point
function decode(uq112x112 memory self) internal pure returns (uint112) {
return uint112(self._x >> RESOLUTION);
}
// decode a UQ144x112 into a uint144 by truncating after the radix point
function decode144(uq144x112 memory self) internal pure returns (uint144) {
return uint144(self._x >> RESOLUTION);
}
}
library UniswapV2OracleLibrary {
using FixedPoint for *;
// helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 -
// 1]
function currentBlockTimestamp() internal view returns (uint32) {
return uint32(block.timestamp % 2 ** 32);
}
// produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
function currentCumulativePrices(address pair)
internal
view
returns (uint256 price0Cumulative, uint256 price1Cumulative, uint32 blockTimestamp)
{
blockTimestamp = currentBlockTimestamp();
price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();
price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();
// if time has elapsed since the last update on the pair, mock the accumulated price values
(uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves();
if (blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
// addition overflow is desired
// counterfactual
price0Cumulative += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
// counterfactual
price1Cumulative += uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed;
}
}
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OUR CONTRACT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
struct TWAPData {
@ -195,6 +44,11 @@ contract UniswapFeeOracle is IFeeOracle {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/**
* @notice Ratio for TWAP calcs
*/
uint256 public constant Q112Ratio = 1_000_000_000;
/**
* @notice Address of the Uniswap V2 TORN pool
*/
@ -237,9 +91,8 @@ contract UniswapFeeOracle is IFeeOracle {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EVENTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
event PoolFeeUpdated(IERC20 token, uint24 newPoolFee);
event GlobalTORNPoolFeeUpdated(uint24 newPoolFee);
event GlobalTwapIntervalSecondsUpdated(uint32 newUniswapTimePeriod);
event GlobalMinObservationCardinalityUpdated(uint16 newMinObservationCardinality);
event MinObservationCardinalityUpdated(uint16 newMinObservationCardinality);
event FeeOracleManagerAddressUpdated(address newFeeOracleManagerAddress);
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LOGIC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@ -258,12 +111,12 @@ contract UniswapFeeOracle is IFeeOracle {
}
modifier onlyGovernance() {
require(msg.sender == governanceProxyAddress, "UniswapV3FeeOracle: onlyGovernance");
require(msg.sender == governanceProxyAddress, "UniswapFeeOracle: onlyGovernance");
_;
}
modifier onlyFeeOracleManager() {
require(msg.sender == feeOracleManagerAddress, "UniswapV3FeeOracle: onlyGovernance");
require(msg.sender == feeOracleManagerAddress, "UniswapFeeOracle: onlyFeeOracleManager");
_;
}
@ -284,12 +137,12 @@ contract UniswapFeeOracle is IFeeOracle {
_instance.state.isERC20 ? _instance.state.token : IERC20(UniswapV3OracleHelper.WETH);
// Now get the price ratio
uint256 priceRatio = getTokenPerTORN(_instance.state.token, _instance.fee.updateInterval);
uint256 priceRatio = getTORNPerToken(_instance.state.token, _instance.fee.updateInterval);
// Denomination (tokens) times torn per token, through e18 because both are in e18,
// times fee percent and then through for proper value
return uint160(
_instance.logic.denomination().mul(1e18).div(priceRatio).mul(uint256(_instance.fee.percent)).div(
_instance.logic.denomination().mul(priceRatio).div(1e18).mul(uint256(_instance.fee.percent)).div(
uint256(_instance.fee.divisor)
)
);
@ -315,7 +168,7 @@ contract UniswapFeeOracle is IFeeOracle {
// Save TWAP data, meaning the average price (TORN per ETH)
last = TWAPData({
averagePrice: FixedPoint.uq112x112(
uint224((_price1CumulativeLast - lastCumulativeTORNPriceInETH) / elapsed)
uint224(((_price1CumulativeLast - lastCumulativeTORNPriceInETH) * Q112Ratio) / elapsed)
),
updatedTimestamp: currentTimestamp
});
@ -325,20 +178,20 @@ contract UniswapFeeOracle is IFeeOracle {
}
}
function getTokenPerTORN(IERC20 _token, uint32 _interval) public view virtual returns (uint256) {
function getTORNPerToken(IERC20 _token, uint32 _interval) public view virtual returns (uint256) {
// Get the average price of TOKEN in WETH
uint256 ethPerTokenAverage =
UniswapV3OracleHelper.getPriceOfTokenInWETH(address(_token), poolFeesByToken[_token], _interval);
// TORN PER ETH * ETH PER TOKEN = TORN per TOKEN
return ethPerTokenAverage * last.averagePrice.decode() / 1e18;
return ethPerTokenAverage * last.averagePrice.decode() / Q112Ratio;
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
function setPoolFeeForToken(IERC20 _token, uint24 _tokenPoolFee) public virtual onlyGovernance {
// Check whether cardinality is initialized
require(minObservationCardinality != 0, "UniswapV3FeeOracle: cardinality not initialized");
require(minObservationCardinality != 0, "UniswapFeeOracle: cardinality not initialized");
// Only do this if not zeroing out
if (_tokenPoolFee != 0) {
@ -348,7 +201,7 @@ contract UniswapFeeOracle is IFeeOracle {
address(_token), UniswapV3OracleHelper.WETH, _tokenPoolFee
);
require(poolAddress != address(0), "UniswapV3FeeOracle: pool for token and fee does not exist");
require(poolAddress != address(0), "UniswapFeeOracle: pool for token and fee does not exist");
// Check whether the pool has a large enough observation cardinality
@ -356,7 +209,7 @@ contract UniswapFeeOracle is IFeeOracle {
require(
minObservationCardinality <= observationCardinalityNext,
"UniswapV3FeeOracle: pool observation cardinality low"
"UniswapFeeOracle: pool observation cardinality low"
);
}
@ -373,11 +226,12 @@ contract UniswapFeeOracle is IFeeOracle {
onlyGovernance
{
minObservationCardinality = _newGlobalMinObservationCardinality;
emit GlobalMinObservationCardinalityUpdated(_newGlobalMinObservationCardinality);
emit MinObservationCardinalityUpdated(_newGlobalMinObservationCardinality);
}
function setFeeOracleManagerAddress(address _newFeeOracleManagerAddress) public virtual onlyGovernance {
feeOracleManagerAddress = _newFeeOracleManagerAddress;
emit FeeOracleManagerAddressUpdated(_newFeeOracleManagerAddress);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */

@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function mint(address to) external returns (uint256 liquidity);
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}

@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
library FixedPoint {
// range: [0, 2**112 - 1]
// resolution: 1 / 2**112
struct uq112x112 {
uint224 _x;
}
// range: [0, 2**144 - 1]
// resolution: 1 / 2**112
struct uq144x112 {
uint256 _x;
}
uint8 private constant RESOLUTION = 112;
// encode a uint112 as a UQ112x112
function encode(uint112 x) internal pure returns (uq112x112 memory) {
return uq112x112(uint224(x) << RESOLUTION);
}
// encodes a uint144 as a UQ144x112
function encode144(uint144 x) internal pure returns (uq144x112 memory) {
return uq144x112(uint256(x) << RESOLUTION);
}
// divide a UQ112x112 by a uint112, returning a UQ112x112
function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) {
require(x != 0, "FixedPoint: DIV_BY_ZERO");
return uq112x112(self._x / uint224(x));
}
// multiply a UQ112x112 by a uint, returning a UQ144x112
// reverts on overflow
function mul(uq112x112 memory self, uint256 y) internal pure returns (uq144x112 memory) {
uint256 z;
require(
y == 0 || (z = uint256(self._x) * y) / y == uint256(self._x),
"FixedPoint: MULTIPLICATION_OVERFLOW"
);
return uq144x112(z);
}
// returns a UQ112x112 which represents the ratio of the numerator to the denominator
// equivalent to encode(numerator).div(denominator)
function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) {
require(denominator > 0, "FixedPoint: DIV_BY_ZERO");
return uq112x112((uint224(numerator) << RESOLUTION) / denominator);
}
// decode a UQ112x112 into a uint112 by truncating after the radix point
function decode(uq112x112 memory self) internal pure returns (uint112) {
return uint112(self._x >> RESOLUTION);
}
// decode a UQ144x112 into a uint144 by truncating after the radix point
function decode144(uq144x112 memory self) internal pure returns (uint144) {
return uint144(self._x >> RESOLUTION);
}
}

@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
// Local imports
import { IUniswapV2Pair } from "../interfaces/IUniswapV2Pair.sol";
import { FixedPoint } from "./FixedPoint.sol";
library UniswapV2OracleLibrary {
using FixedPoint for *;
// helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 -
// 1]
function currentBlockTimestamp() internal view returns (uint32) {
return uint32(block.timestamp % 2 ** 32);
}
// produces the cumulative price using counterfactuals to save gas and avoid a call to sync.
function currentCumulativePrices(address pair)
internal
view
returns (uint256 price0Cumulative, uint256 price1Cumulative, uint32 blockTimestamp)
{
blockTimestamp = currentBlockTimestamp();
price0Cumulative = IUniswapV2Pair(pair).price0CumulativeLast();
price1Cumulative = IUniswapV2Pair(pair).price1CumulativeLast();
// if time has elapsed since the last update on the pair, mock the accumulated price values
(uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = IUniswapV2Pair(pair).getReserves();
if (blockTimestampLast != blockTimestamp) {
// subtraction overflow is desired
uint32 timeElapsed = blockTimestamp - blockTimestampLast;
// addition overflow is desired
// counterfactual
price0Cumulative += uint256(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed;
// counterfactual
price1Cumulative += uint256(FixedPoint.fraction(reserve0, reserve1)._x) * timeElapsed;
}
}
}

@ -19,31 +19,84 @@ import { console2 } from "forge-std/console2.sol";
// Local imports
import { FeeOracleManager, FeeDataForOracle, InstanceWithFee } from "src/v2/FeeOracleManager.sol";
import { TornadoProposalTest } from "./TornadoProposalTest.sol";
import { IGovernance, Proposal } from "common/interfaces/IGovernance.sol";
import { IUniswapV2Pair } from "src/v2/interfaces/IUniswapV2Pair.sol";
import { TornadoAddresses } from "common/TornadoAddresses.sol";
import { FeeOracleManager, FeeDataForOracle, InstanceWithFee } from "src/v2/FeeOracleManager.sol";
import { UniswapFeeOracle } from "src/v2/UniswapFeeOracle.sol";
import { CurveFeeOracle, ICurvePriceOracle, CurveChainedOracles } from "src/v2/CurveFeeOracle.sol";
import { InstanceState } from "src/v2/InstanceRegistry.sol";
contract OracleTests is Test {
interface IWethDepositable {
function deposit() external payable;
}
contract Instances {
/* ETH instances */
ITornadoInstance public constant eth01 = ITornadoInstance(0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc);
ITornadoInstance public constant eth1 = ITornadoInstance(0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936);
ITornadoInstance public constant eth10 = ITornadoInstance(0x910Cbd523D972eb0a6f4cAe4618aD62622b39DbF);
ITornadoInstance public constant eth100 = ITornadoInstance(0xA160cdAB225685dA1d56aa342Ad8841c3b53f291);
/* DAI instances */
ITornadoInstance public constant dai100 = ITornadoInstance(0xD4B88Df4D29F5CedD6857912842cff3b20C8Cfa3);
ITornadoInstance public constant dai1000 = ITornadoInstance(0xFD8610d20aA15b7B2E3Be39B396a1bC3516c7144);
ITornadoInstance public constant dai10000 = ITornadoInstance(0x07687e702b410Fa43f4cB4Af7FA097918ffD2730);
ITornadoInstance public constant dai100000 = ITornadoInstance(0x23773E65ed146A459791799d01336DB287f25334);
/* cDAI instances */
ITornadoInstance public constant cdai100 = ITornadoInstance(0x22aaA7720ddd5388A3c0A3333430953C68f1849b);
ITornadoInstance public constant cdai1000 = ITornadoInstance(0x03893a7c7463AE47D46bc7f091665f1893656003);
ITornadoInstance public constant cdai10000 = ITornadoInstance(0x2717c5e28cf931547B621a5dddb772Ab6A35B701);
ITornadoInstance public constant cdai100000 = ITornadoInstance(0xD21be7248e0197Ee08E0c20D4a96DEBdaC3D20Af);
/* USDT instances */
ITornadoInstance public constant usdt100 = ITornadoInstance(0x169AD27A470D064DEDE56a2D3ff727986b15D52B);
ITornadoInstance public constant usdt1000 = ITornadoInstance(0x0836222F2B2B24A3F36f98668Ed8F0B38D1a872f);
/* WBTC instances */
ITornadoInstance public constant wbtc01 = ITornadoInstance(0x178169B423a011fff22B9e3F3abeA13414dDD0F1);
ITornadoInstance public constant wbtc1 = ITornadoInstance(0x610B717796ad172B316836AC95a2ffad065CeaB4);
ITornadoInstance public constant wbtc10 = ITornadoInstance(0xbB93e510BbCD0B7beb5A853875f9eC60275CF498);
/* CRVUSD instances */
ITornadoInstance public constant cu100 = ITornadoInstance(0x913a73486Dc4AA3832A56d461542836C1eeB93be);
ITornadoInstance public constant cu1_000 = ITornadoInstance(0x5A6b3C829dB3e938C885000c6E93CF35E74876a4);
ITornadoInstance public constant cu10_000 = ITornadoInstance(0x49f173CDAB99a2C3800F1255393DF9B7a17B82Bb);
ITornadoInstance public constant cu100_000 = ITornadoInstance(0x4640Dffc9fD0B113B983e3A350b070a119CA143C);
ITornadoInstance public constant cu1_000_000 =
ITornadoInstance(0xc4eA8Bd3Fd76f3c255395793B47F7c55aD59d991);
}
contract OracleTests is Instances, TornadoProposalTest {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
// Tokens - constant
IERC20 internal constant WETH = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C);
// Contracts - constant
FeeOracleManager public constant feeOracleManager =
FeeOracleManager(0x5f6c97C6AD7bdd0AE7E0Dd4ca33A4ED3fDabD4D7);
IUniswapV2Pair public constant uniTornPool = IUniswapV2Pair(0x0C722a487876989Af8a05FFfB6e32e45cc23FB3A);
address public constant crvUSDUSDCStableswap2Pool = 0x4DEcE678ceceb27446b35C672dC7d61F30bAD69E;
address public constant tricryptoUSDCPool = 0x7F86Bf177Dd4F3494b841a37e810A34dD56c829B;
ITornadoInstance public constant cu10_000 = ITornadoInstance(0x49f173CDAB99a2C3800F1255393DF9B7a17B82Bb);
IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C);
// Contracts - mutable
UniswapFeeOracle uniswapFeeOracle;
@ -51,11 +104,14 @@ contract OracleTests is Test {
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TESTING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
function setUp() public {
function setUp() public virtual override {
vm.createSelectFork(vm.envString("MAINNET_RPC_URL"));
vm.rollFork(17_493_778);
uniswapFeeOracle = new UniswapFeeOracle(address(this), address(this));
uniswapFeeOracle = new UniswapFeeOracle(address(this), address(feeOracleManager));
uniswapFeeOracle.setMinObservationCardinality(10);
uniswapFeeOracle.setPoolFeeForToken(WETH, 0);
feeOracle = new CurveFeeOracle(address(this));
feeOracle.setTornOracleIsUniswap(false);
@ -82,10 +138,23 @@ contract OracleTests is Test {
}
function test_curveFeeChainedTORN() public {
uint256 timeBeforeSwap = now;
feeOracle.setTornOracleIsUniswap(true);
_setCurveFeeChainedOracleForInstance(feeOracle, cu10_000); // CRVUSD 10_000
_advanceTORNETHMarket();
uniswapFeeOracle.update(
TORN,
InstanceWithFee({
logic: cu10_000,
state: InstanceState(IERC20(address(0)), 0, false, false),
fee: FeeDataForOracle(0, 0, 0, 0, uint32(timeBeforeSwap))
})
);
console2.log(
"\nTORN Fee calculated ------------------------------------------------------\n",
uint256(
@ -94,7 +163,7 @@ contract OracleTests is Test {
InstanceWithFee({
logic: cu10_000,
state: InstanceState(IERC20(cu10_000.token()), 0, true, true),
fee: FeeDataForOracle(0, 30, 10_000, 2 days, 0)
fee: FeeDataForOracle(0, 30, 10_000, 2 days, uint32(timeBeforeSwap))
})
)
),
@ -102,8 +171,56 @@ contract OracleTests is Test {
);
}
function test_UniswapTORNOracle() public {
uint256 timeBeforeSwap = now;
_advanceTORNETHMarket();
InstanceWithFee memory feepool = InstanceWithFee({
logic: eth100,
state: InstanceState(WETH, 0, false, true),
fee: FeeDataForOracle(0, 30, 10_000, 2 days, uint32(timeBeforeSwap))
});
uniswapFeeOracle.update(TORN, feepool);
console2.log(
"\nTORN Fee calculated ------------------------------------------------------\n",
uniswapFeeOracle.getFee(TORN, feepool),
"\n------------------------------------------------------------------------\n"
);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HELPERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
function _advanceTORNETHMarket() internal {
console2.log("\ntrader is now going to move the price\n");
uint256 lastPriceAvg0 = uniTornPool.price0CumulativeLast();
uint256 lastPriceAvg1 = uniTornPool.price0CumulativeLast();
uint256 rn = now;
address trader = address(bytes20(keccak256("trader")));
vm.deal(trader, 20 ether);
vm.prank(trader);
IWethDepositable(address(WETH)).deposit{ value: 19 ether }();
require(WETH.balanceOf(trader) == 19 ether, "deposit for weth");
vm.warp(rn + 2 days + 1 hours);
vm.prank(trader);
WETH.transfer(address(uniTornPool), 19 ether);
uniTornPool.swap(6_600_000_000_000_000_000_000, 0, trader, new bytes(0));
console2.log("\ntrader received =>", TORN.balanceOf(trader), "TORN\n");
require(lastPriceAvg0 != uniTornPool.price0CumulativeLast(), "twap moving 0 fail");
require(lastPriceAvg1 != uniTornPool.price1CumulativeLast(), "twap moving 1 fail");
}
function _setCurveFeeSimpleTricryptoOracleForInstance(
CurveFeeOracle _feeOracle,
ITornadoInstance _instance