Code quality improvements
Signed-off-by: AlienTornadosaurusHex <>
This commit is contained in:
parent
b25f8d569c
commit
1578f5ac69
@ -19,11 +19,11 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
|
||||
|
||||
// Local imports
|
||||
|
||||
import { IFeeOracle } from "./interfaces/IFeeOracle.sol";
|
||||
import { IFeeOracle, FeeData } from "./interfaces/IFeeOracle.sol";
|
||||
|
||||
import { UniswapV3OracleHelper } from "./libraries/UniswapV3OracleHelper.sol";
|
||||
|
||||
import { InstanceData } from "./InstanceRegistry.sol";
|
||||
import { InstanceState } from "./InstanceRegistry.sol";
|
||||
|
||||
/**
|
||||
* @dev The global configuration for the `UniswapV3FeeOracle` contract. TORN is used in all `getFee()` calls,
|
||||
@ -86,12 +86,12 @@ contract UniswapV3FeeOracle is IFeeOracle {
|
||||
function getFee(
|
||||
IERC20 _torn,
|
||||
ITornadoInstance _instance,
|
||||
InstanceData memory _data,
|
||||
uint32 _feePercent,
|
||||
InstanceState memory _data,
|
||||
FeeData memory _lastFee,
|
||||
uint32 _feePercentDivisor
|
||||
) public view virtual override returns (uint160) {
|
||||
// If fee is 0 return
|
||||
if (_feePercent == 0) return 0;
|
||||
if (_lastFee.percent == 0) return 0;
|
||||
|
||||
// If it's not an ERC20 it has to be ETH, use the WETH token
|
||||
_data.token = _data.isERC20 ? _data.token : IERC20(UniswapV3OracleHelper.WETH);
|
||||
@ -109,7 +109,7 @@ contract UniswapV3FeeOracle is IFeeOracle {
|
||||
// And now all according to legacy calculation
|
||||
return uint160(
|
||||
_instance.denomination().mul(UniswapV3OracleHelper.RATIO_DIVIDER).div(tokenPriceRatio).mul(
|
||||
uint256(_feePercent)
|
||||
uint256(_lastFee.percent)
|
||||
).div(uint256(_feePercentDivisor))
|
||||
);
|
||||
}
|
@ -119,8 +119,6 @@ contract InfrastructureUpgradeProposal {
|
||||
|
||||
UniswapFeeOracle uniswapFeeOracle = UniswapFeeOracle(deployedUniswapFeeOracleAddress);
|
||||
|
||||
uniswapFeeOracle.setTwapIntervalSeconds(5400); // Legacy value, still makes sense
|
||||
|
||||
uniswapFeeOracle.setMinObservationCardinality(1); // Set it to minimum so cDAI passes
|
||||
|
||||
// Each of the instances are going to require a Uniswap Pool Fee to be set such that we actually know
|
||||
|
@ -14,13 +14,13 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
|
||||
|
||||
// Local imports
|
||||
|
||||
import { IFeeOracle } from "./interfaces/IFeeOracle.sol";
|
||||
import { IFeeOracle, InstanceWithFee } from "./interfaces/IFeeOracle.sol";
|
||||
|
||||
import { UniswapV3OracleHelper } from "./libraries/UniswapV3OracleHelper.sol";
|
||||
|
||||
import { UniswapFeeOracle } from "./UniswapFeeOracle.sol";
|
||||
|
||||
import { InstanceData } from "./InstanceRegistry.sol";
|
||||
import { InstanceState } from "./InstanceRegistry.sol";
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CURVE FINANCE INTERFACE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
@ -218,35 +218,37 @@ contract CurveFeeOracle is IFeeOracle {
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
function update() public virtual override { }
|
||||
function update(IERC20, InstanceWithFee memory) public virtual override { }
|
||||
|
||||
function getFee(
|
||||
IERC20,
|
||||
ITornadoInstance _instance,
|
||||
InstanceData memory,
|
||||
uint32 _feePercent,
|
||||
uint32 _feePercentDivisor
|
||||
) public view virtual override returns (uint160) {
|
||||
function getFee(IERC20, InstanceWithFee memory _instance)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override
|
||||
returns (uint160)
|
||||
{
|
||||
// If fee is 0 return
|
||||
if (_feePercent == 0) return 0;
|
||||
if (_instance.fee.percent == 0) return 0;
|
||||
|
||||
// Either TOKEN price in ETH or TOKEN price in TORN
|
||||
uint256 price = chainedPriceOracles[_instance].price_oracle();
|
||||
uint256 price = chainedPriceOracles[_instance.logic].price_oracle();
|
||||
|
||||
// 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(IERC20(UniswapV3OracleHelper.WETH));
|
||||
/ uniswapFeeOracle.getTokenPerTORN(
|
||||
IERC20(UniswapV3OracleHelper.WETH), _instance.fee.updateInterval
|
||||
);
|
||||
}
|
||||
|
||||
// The price is now either prepared by the chained oracles or by Uniswap V3, in any case we do the
|
||||
// legacy calculation and return the fee value
|
||||
return uint160(
|
||||
_instance.denomination().mul(price).div(UniswapV3OracleHelper.RATIO_DIVIDER).mul(
|
||||
uint256(_feePercent)
|
||||
).div(uint256(_feePercentDivisor))
|
||||
_instance.logic.denomination().mul(price).div(UniswapV3OracleHelper.RATIO_DIVIDER).mul(
|
||||
uint256(_instance.fee.percent)
|
||||
).div(uint256(_instance.fee.divisor))
|
||||
);
|
||||
}
|
||||
|
||||
@ -301,7 +303,7 @@ contract CurveFeeOracle is IFeeOracle {
|
||||
emit UniswapFeeOracleUpdated(address(_uniswapFeeOracle));
|
||||
}
|
||||
|
||||
function setTornOracleIsUniswapV3(bool _is) public virtual onlyGovernance {
|
||||
function setTornOracleIsUniswap(bool _is) public virtual onlyGovernance {
|
||||
tornOracleIsUniswapV3 = _is;
|
||||
if (_is) emit TornOracleIsUniswapV3();
|
||||
else emit TornOracleIsCurve();
|
||||
|
@ -14,9 +14,9 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
|
||||
|
||||
// Local Imports
|
||||
|
||||
import { InstanceRegistry } from "./InstanceRegistry.sol";
|
||||
import { IFeeOracle, FeeData, FeeDataForOracle, InstanceWithFee } from "./interfaces/IFeeOracle.sol";
|
||||
|
||||
import { IFeeOracle } from "./interfaces/IFeeOracle.sol";
|
||||
import { InstanceRegistry } from "./InstanceRegistry.sol";
|
||||
|
||||
/**
|
||||
* @title FeeManagerLegacyStorage
|
||||
@ -51,16 +51,6 @@ contract FeeManagerLegacyStorage {
|
||||
mapping(ITornadoInstance => uint256) internal _oldFeesForInstanceUpdateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Fee data which is valid and also influences fee updating across all oracles.
|
||||
*/
|
||||
struct FeeData {
|
||||
uint160 amount;
|
||||
uint32 percent;
|
||||
uint32 updateInterval;
|
||||
uint32 lastUpdateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title FeeOracleManager
|
||||
* @author AlienTornadosaurusHex
|
||||
@ -132,6 +122,7 @@ contract FeeOracleManager is FeeManagerLegacyStorage, Initializable {
|
||||
) external onlyGovernance initializer {
|
||||
// Get num of existing instances
|
||||
uint256 numInstances = _instances.length;
|
||||
uint32 feeUpdateInterval = _oldFeeUpdateInterval;
|
||||
|
||||
for (uint256 i = 0; i < numInstances; i++) {
|
||||
// For each instance
|
||||
@ -141,7 +132,7 @@ contract FeeOracleManager is FeeManagerLegacyStorage, Initializable {
|
||||
feesByInstance[instance] = FeeData({
|
||||
amount: _oldFeesForInstance[instance],
|
||||
percent: uint32(_percents[i]),
|
||||
updateInterval: _oldFeeUpdateInterval,
|
||||
updateInterval: feeUpdateInterval,
|
||||
lastUpdateTime: uint32(_oldFeesForInstanceUpdateTime[instance])
|
||||
});
|
||||
|
||||
@ -192,22 +183,15 @@ contract FeeOracleManager is FeeManagerLegacyStorage, Initializable {
|
||||
require(address(oracle) != address(0), "FeeOracleManager: instance has no oracle");
|
||||
|
||||
// Now update if we do not respect the interval or we respect it and are in the interval
|
||||
if (!_respectFeeUpdateInterval || (fee.updateInterval < now - fee.lastUpdateTime)) {
|
||||
if (!_respectFeeUpdateInterval || (fee.updateInterval <= now - fee.lastUpdateTime)) {
|
||||
// Prepare data for the process
|
||||
InstanceWithFee memory _feeInstance = populateInstanceWithFeeData(_instance, fee);
|
||||
|
||||
// Allow oracle to gate for fee manager and implement own logic
|
||||
oracle.update();
|
||||
oracle.update(torn, _feeInstance);
|
||||
|
||||
// There must a be a fee set otherwise it's just 0
|
||||
if (fee.percent != 0) {
|
||||
fee.amount = oracle.getFee(
|
||||
torn,
|
||||
_instance,
|
||||
instanceRegistry.getInstanceData(_instance),
|
||||
fee.percent,
|
||||
FEE_PERCENT_DIVISOR
|
||||
);
|
||||
} else {
|
||||
fee.amount = 0;
|
||||
}
|
||||
fee.amount = fee.percent != 0 ? oracle.getFee(torn, _feeInstance) : 0;
|
||||
|
||||
// Store
|
||||
feesByInstance[_instance] = FeeData({
|
||||
@ -243,13 +227,14 @@ contract FeeOracleManager is FeeManagerLegacyStorage, Initializable {
|
||||
|
||||
// An address(0) oracle means we're removing an oracle for an instance
|
||||
if (_oracleAddress != address(0)) {
|
||||
// Reverts if oracle doesn't implement
|
||||
oracle.update();
|
||||
// Prepare data for the process
|
||||
InstanceWithFee memory _feeInstance = populateInstanceWithFeeData(instance, fee);
|
||||
|
||||
// Reverts if oracle doesn't implement
|
||||
fee.amount = oracle.getFee(
|
||||
torn, instance, instanceRegistry.getInstanceData(instance), fee.percent, FEE_PERCENT_DIVISOR
|
||||
);
|
||||
oracle.update(torn, _feeInstance);
|
||||
|
||||
// Reverts if oracle doesn't implement
|
||||
fee.amount = oracle.getFee(torn, _feeInstance);
|
||||
|
||||
// Note down updated fee
|
||||
feesByInstance[instance] = FeeData({
|
||||
@ -293,13 +278,35 @@ contract FeeOracleManager is FeeManagerLegacyStorage, Initializable {
|
||||
}
|
||||
|
||||
function getUpdatedFeeForInstance(ITornadoInstance instance) public view virtual returns (uint160) {
|
||||
return instanceFeeOracles[instance].getFee(
|
||||
torn,
|
||||
instance,
|
||||
instanceRegistry.getInstanceData(instance),
|
||||
feesByInstance[instance].percent,
|
||||
FEE_PERCENT_DIVISOR
|
||||
);
|
||||
return instanceFeeOracles[instance].getFee(torn, populateInstanceWithFeeData(instance));
|
||||
}
|
||||
|
||||
function populateInstanceWithFeeData(ITornadoInstance _regularInstance)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
returns (InstanceWithFee memory)
|
||||
{
|
||||
return populateInstanceWithFeeData(_regularInstance, feesByInstance[_regularInstance]);
|
||||
}
|
||||
|
||||
function populateInstanceWithFeeData(ITornadoInstance _regularInstance, FeeData memory _fee)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
returns (InstanceWithFee memory)
|
||||
{
|
||||
return InstanceWithFee({
|
||||
logic: _regularInstance,
|
||||
state: instanceRegistry.getInstanceState(_regularInstance),
|
||||
fee: FeeDataForOracle({
|
||||
amount: _fee.amount,
|
||||
percent: _fee.percent,
|
||||
divisor: FEE_PERCENT_DIVISOR,
|
||||
updateInterval: _fee.updateInterval,
|
||||
lastUpdateTime: _fee.lastUpdateTime
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function getLastFeeForInstance(ITornadoInstance instance) public view virtual returns (uint160) {
|
||||
@ -342,9 +349,8 @@ contract FeeOracleManager is FeeManagerLegacyStorage, Initializable {
|
||||
|
||||
FeeData memory fee = feesByInstance[instance];
|
||||
|
||||
uint256 marketFee = instanceFeeOracles[instance].getFee(
|
||||
torn, instance, instanceRegistry.getInstanceData(instance), fee.percent, FEE_PERCENT_DIVISOR
|
||||
);
|
||||
uint256 marketFee =
|
||||
instanceFeeOracles[instance].getFee(torn, populateInstanceWithFeeData(instance, fee));
|
||||
|
||||
if (marketFee != 0) {
|
||||
deviations[i] = int256((fee.amount * 1000) / marketFee) - 1000;
|
||||
|
@ -73,7 +73,7 @@ contract InstanceRegistryLegacyStorage {
|
||||
/**
|
||||
* @dev This struct holds barebones information regarding an instance and its data location in storage.
|
||||
*/
|
||||
struct InstanceData {
|
||||
struct InstanceState {
|
||||
IERC20 token;
|
||||
uint80 index;
|
||||
bool isERC20;
|
||||
@ -100,7 +100,7 @@ contract InstanceRegistry is InstanceRegistryLegacyStorage, EnsResolve, Initiali
|
||||
/**
|
||||
* @notice Essential data regarding instances, see struct above
|
||||
*/
|
||||
mapping(ITornadoInstance => InstanceData) public instanceData;
|
||||
mapping(ITornadoInstance => InstanceState) public instanceData;
|
||||
|
||||
/**
|
||||
* @notice All instances enumerable
|
||||
@ -183,7 +183,7 @@ contract InstanceRegistry is InstanceRegistryLegacyStorage, EnsResolve, Initiali
|
||||
|
||||
// Store the collected data of the instance
|
||||
instanceData[_instance] =
|
||||
InstanceData({ token: token, index: instanceIndex, isERC20: isERC20, isEnabled: true });
|
||||
InstanceState({ token: token, index: instanceIndex, isERC20: isERC20, isEnabled: true });
|
||||
|
||||
// Log
|
||||
emit InstanceAdded(address(_instance), instanceIndex, isERC20);
|
||||
@ -211,7 +211,7 @@ contract InstanceRegistry is InstanceRegistryLegacyStorage, EnsResolve, Initiali
|
||||
// Grab data needed to remove the instance
|
||||
|
||||
ITornadoInstance instance = ITornadoInstance(_instanceAddress);
|
||||
InstanceData memory data = instanceData[instance];
|
||||
InstanceState memory data = instanceData[instance];
|
||||
|
||||
// Checks whether already removed, so allowance can't be killed
|
||||
|
||||
@ -280,32 +280,32 @@ contract InstanceRegistry is InstanceRegistryLegacyStorage, EnsResolve, Initiali
|
||||
}
|
||||
}
|
||||
|
||||
function getAllInstanceData() public view virtual returns (InstanceData[] memory data) {
|
||||
return getInstanceData(0, instances.length - 1);
|
||||
function getAllInstanceState() public view virtual returns (InstanceState[] memory data) {
|
||||
return getInstanceState(0, instances.length - 1);
|
||||
}
|
||||
|
||||
function getInstanceData(uint256 _inclusiveStartIndex, uint256 _inclusiveEndIndex)
|
||||
function getInstanceState(uint256 _inclusiveStartIndex, uint256 _inclusiveEndIndex)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
returns (InstanceData[] memory data)
|
||||
returns (InstanceState[] memory data)
|
||||
{
|
||||
data = new InstanceData[](1 + _inclusiveEndIndex - _inclusiveStartIndex);
|
||||
data = new InstanceState[](1 + _inclusiveEndIndex - _inclusiveStartIndex);
|
||||
|
||||
for (uint256 i = _inclusiveStartIndex; i < _inclusiveEndIndex + 1; i++) {
|
||||
data[i - _inclusiveStartIndex] = instanceData[instances[i]];
|
||||
}
|
||||
}
|
||||
|
||||
function getInstanceData(uint256 _index) public view virtual returns (InstanceData memory data) {
|
||||
function getInstanceState(uint256 _index) public view virtual returns (InstanceState memory data) {
|
||||
return instanceData[instances[_index]];
|
||||
}
|
||||
|
||||
function getInstanceData(ITornadoInstance _instance)
|
||||
function getInstanceState(ITornadoInstance _instance)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
returns (InstanceData memory data)
|
||||
returns (InstanceState memory data)
|
||||
{
|
||||
return instanceData[_instance];
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
|
||||
// Local imports
|
||||
|
||||
import { RelayerRegistry } from "../v1/RelayerRegistry.sol";
|
||||
import { InstanceRegistry, InstanceData } from "./InstanceRegistry.sol";
|
||||
import { InstanceRegistry, InstanceState } from "./InstanceRegistry.sol";
|
||||
|
||||
/**
|
||||
* @title TornadoRouter
|
||||
|
@ -19,11 +19,11 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
|
||||
|
||||
// Local imports
|
||||
|
||||
import { IFeeOracle } from "./interfaces/IFeeOracle.sol";
|
||||
import { IFeeOracle, InstanceWithFee } from "./interfaces/IFeeOracle.sol";
|
||||
|
||||
import { UniswapV3OracleHelper } from "./libraries/UniswapV3OracleHelper.sol";
|
||||
|
||||
import { InstanceData } from "./InstanceRegistry.sol";
|
||||
import { InstanceState } from "./InstanceRegistry.sol";
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UNISWAP INLINED ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
@ -210,11 +210,6 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
*/
|
||||
address public feeOracleManagerAddress;
|
||||
|
||||
/**
|
||||
* @notice The TWAP interval in seconds (this is common)
|
||||
*/
|
||||
uint32 public twapIntervalSeconds;
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ V3 ORACLE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
/**
|
||||
@ -252,10 +247,13 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
governanceProxyAddress = _governanceProxyAddress;
|
||||
feeOracleManagerAddress = _feeOracleManagerAddress;
|
||||
|
||||
// We're immediately doing this because we want to immediately be ready with a price on execution
|
||||
|
||||
(, uint256 _price1CumulativeLast, uint32 _timestamp) =
|
||||
UniswapV2OracleLibrary.currentCumulativePrices(v2TORNPoolAddress);
|
||||
|
||||
lastCumulativeTORNPriceInETH = _price1CumulativeLast;
|
||||
|
||||
last.updatedTimestamp = _timestamp;
|
||||
}
|
||||
|
||||
@ -271,42 +269,33 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MAIN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
function getFee(
|
||||
IERC20,
|
||||
ITornadoInstance _instance,
|
||||
InstanceData memory _data,
|
||||
uint32 _feePercent,
|
||||
uint32 _feePercentDivisor
|
||||
) public view virtual override returns (uint160) {
|
||||
function getFee(IERC20, InstanceWithFee memory _instance)
|
||||
public
|
||||
view
|
||||
virtual
|
||||
override
|
||||
returns (uint160)
|
||||
{
|
||||
// If 0%, 0
|
||||
if (_feePercent == 0) return 0;
|
||||
if (_instance.fee.percent == 0) return 0;
|
||||
|
||||
// If it's not an ERC20 it has to be ETH, use the WETH token
|
||||
_data.token = _data.isERC20 ? _data.token : IERC20(UniswapV3OracleHelper.WETH);
|
||||
_instance.state.token =
|
||||
_instance.state.isERC20 ? _instance.state.token : IERC20(UniswapV3OracleHelper.WETH);
|
||||
|
||||
// Now get the price ratio
|
||||
uint256 priceRatio = getTokenPerTORN(_data.token);
|
||||
uint256 priceRatio = getTokenPerTORN(_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.denomination().mul(1e18).div(priceRatio).mul(uint256(_feePercent)).div(
|
||||
uint256(_feePercentDivisor)
|
||||
_instance.logic.denomination().mul(1e18).div(priceRatio).mul(uint256(_instance.fee.percent)).div(
|
||||
uint256(_instance.fee.divisor)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getTokenPerTORN(IERC20 _token) public view virtual returns (uint256) {
|
||||
// Get the average price of ETH in the TOKEN
|
||||
uint256 ethPerTokenAverage = UniswapV3OracleHelper.getPriceOfTokenInWETH(
|
||||
address(_token), poolFeesByToken[_token], twapIntervalSeconds
|
||||
);
|
||||
|
||||
// Now get average price of TORN per TOKEN
|
||||
return ethPerTokenAverage * last.averagePrice.decode() / 1e18;
|
||||
}
|
||||
|
||||
function update() public virtual override onlyFeeOracleManager {
|
||||
function update(IERC20, InstanceWithFee memory _instance) public virtual override onlyFeeOracleManager {
|
||||
// Get the timestamp of the last update
|
||||
uint32 timestampLastUpdate = last.updatedTimestamp;
|
||||
|
||||
@ -316,8 +305,12 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
// Calculate elapsed time, no matter whether overflow (uniswap logic)
|
||||
uint32 elapsed = currentTimestamp - timestampLastUpdate;
|
||||
|
||||
// Get last token0/token1 meaning TORN per ETH
|
||||
(, uint256 _price1CumulativeLast,) = UniswapV2OracleLibrary.currentCumulativePrices(v2TORNPoolAddress);
|
||||
// Multiple instances may refer to this oracle
|
||||
// For this reason we will basically allow only one to update
|
||||
if (_instance.fee.updateInterval <= elapsed) {
|
||||
// Get last token0/token1 meaning TORN per ETH counterfactually
|
||||
(, uint256 _price1CumulativeLast,) =
|
||||
UniswapV2OracleLibrary.currentCumulativePrices(v2TORNPoolAddress);
|
||||
|
||||
// Save TWAP data, meaning the average price (TORN per ETH)
|
||||
last = TWAPData({
|
||||
@ -330,15 +323,21 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
// Update the cumulative value
|
||||
lastCumulativeTORNPriceInETH = _price1CumulativeLast;
|
||||
}
|
||||
}
|
||||
|
||||
function getTokenPerTORN(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;
|
||||
}
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
function setPoolFeeForToken(IERC20 _token, uint24 _tokenPoolFee) public virtual onlyGovernance {
|
||||
// Get global config
|
||||
|
||||
// Check whether globals are initialized
|
||||
|
||||
require(twapIntervalSeconds != 0, "UniswapV3FeeOracle: time period not initialized");
|
||||
// Check whether cardinality is initialized
|
||||
require(minObservationCardinality != 0, "UniswapV3FeeOracle: cardinality not initialized");
|
||||
|
||||
// Only do this if not zeroing out
|
||||
@ -368,11 +367,6 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
emit PoolFeeUpdated(_token, _tokenPoolFee);
|
||||
}
|
||||
|
||||
function setTwapIntervalSeconds(uint32 _newGlobalTwapIntervalSeconds) public virtual onlyGovernance {
|
||||
twapIntervalSeconds = _newGlobalTwapIntervalSeconds;
|
||||
emit GlobalTwapIntervalSecondsUpdated(_newGlobalTwapIntervalSeconds);
|
||||
}
|
||||
|
||||
function setMinObservationCardinality(uint16 _newGlobalMinObservationCardinality)
|
||||
public
|
||||
virtual
|
||||
@ -388,7 +382,15 @@ contract UniswapFeeOracle is IFeeOracle {
|
||||
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GETTERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
|
||||
function getTWAPData() public view virtual returns (TWAPData memory) {
|
||||
return last;
|
||||
}
|
||||
|
||||
function getAverageTORNPerETH() public view virtual returns (uint256) {
|
||||
return last.averagePrice.decode();
|
||||
}
|
||||
|
||||
function getLastUpdatedTimet() public view virtual returns (uint32) {
|
||||
return last.updatedTimestamp;
|
||||
}
|
||||
}
|
||||
|
@ -13,16 +13,51 @@ import { ITornadoInstance } from "tornado-anonymity-mining/contracts/interfaces/
|
||||
|
||||
// Local imports
|
||||
|
||||
import { InstanceData } from "../InstanceRegistry.sol";
|
||||
import { InstanceState } from "../InstanceRegistry.sol";
|
||||
|
||||
interface IFeeOracle {
|
||||
function update() external;
|
||||
|
||||
function getFee(
|
||||
IERC20 _torn,
|
||||
ITornadoInstance _instance,
|
||||
InstanceData memory _data,
|
||||
uint32 _feePercent,
|
||||
uint32 _feePercentDivisor
|
||||
) external view returns (uint160);
|
||||
/**
|
||||
* @notice Fee data which is valid across all instances, stored in the fee oracle manager.
|
||||
*/
|
||||
struct FeeData {
|
||||
uint160 amount;
|
||||
uint32 percent;
|
||||
uint32 updateInterval;
|
||||
uint32 lastUpdateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Fee data which is only used and constructed when updating and oracle fee or getting it.
|
||||
*/
|
||||
struct FeeDataForOracle {
|
||||
uint160 amount;
|
||||
uint32 percent;
|
||||
uint32 divisor;
|
||||
uint32 updateInterval;
|
||||
uint32 lastUpdateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice This is the full bundled data for an instance.
|
||||
*/
|
||||
struct InstanceWithFee {
|
||||
ITornadoInstance logic;
|
||||
InstanceState state;
|
||||
FeeDataForOracle fee;
|
||||
}
|
||||
|
||||
/**
|
||||
* @title IFeeOracle
|
||||
* @author AlienTornadosaurusHex
|
||||
* @notice The interface which all fee oracles for Tornado should implement.
|
||||
*/
|
||||
interface IFeeOracle {
|
||||
/**
|
||||
* @dev This function is intended to allow oracles to configure their state
|
||||
*/
|
||||
function update(IERC20 _torn, InstanceWithFee memory _instance) external;
|
||||
|
||||
/**
|
||||
* @dev This function must return a uint160 compatible TORN fee
|
||||
*/
|
||||
function getFee(IERC20 _torn, InstanceWithFee memory _instance) external view returns (uint160);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import { console2 } from "forge-std/console2.sol";
|
||||
|
||||
// Local imports
|
||||
|
||||
import { FeeOracleManager } from "src/v2/FeeOracleManager.sol";
|
||||
import { FeeOracleManager, FeeDataForOracle, InstanceWithFee } from "src/v2/FeeOracleManager.sol";
|
||||
|
||||
import { IGovernance, Proposal } from "common/interfaces/IGovernance.sol";
|
||||
|
||||
@ -29,7 +29,7 @@ import { UniswapFeeOracle } from "src/v2/UniswapFeeOracle.sol";
|
||||
|
||||
import { CurveFeeOracle, ICurvePriceOracle, CurveChainedOracles } from "src/v2/CurveFeeOracle.sol";
|
||||
|
||||
import { InstanceData } from "src/v2/InstanceRegistry.sol";
|
||||
import { InstanceState } from "src/v2/InstanceRegistry.sol";
|
||||
|
||||
contract OracleTests is Test {
|
||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ VARIABLES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||
@ -55,11 +55,10 @@ contract OracleTests is Test {
|
||||
vm.createSelectFork(vm.envString("MAINNET_RPC_URL"));
|
||||
|
||||
uniswapFeeOracle = new UniswapFeeOracle(address(this), address(feeOracleManager));
|
||||
uniswapFeeOracle.setTwapIntervalSeconds(5400);
|
||||
uniswapFeeOracle.setMinObservationCardinality(10);
|
||||
|
||||
feeOracle = new CurveFeeOracle(address(this));
|
||||
feeOracle.setTornOracleIsUniswapV3(false);
|
||||
feeOracle.setTornOracleIsUniswap(false);
|
||||
feeOracle.setUniswapFeeOracle(uniswapFeeOracle);
|
||||
}
|
||||
|
||||
@ -70,7 +69,12 @@ contract OracleTests is Test {
|
||||
"\nShould be 30 * (ETH/USD) ------------------------------------------------\n",
|
||||
uint256(
|
||||
feeOracle.getFee(
|
||||
TORN, cu10_000, InstanceData(IERC20(cu10_000.token()), 0, true, true), 30, 10_000
|
||||
TORN,
|
||||
InstanceWithFee({
|
||||
logic: cu10_000,
|
||||
state: InstanceState(IERC20(cu10_000.token()), 0, true, true),
|
||||
fee: FeeDataForOracle(0, 30, 10_000, 2 days, 0)
|
||||
})
|
||||
)
|
||||
),
|
||||
"\n------------------------------------------------------------------------\n"
|
||||
@ -78,7 +82,7 @@ contract OracleTests is Test {
|
||||
}
|
||||
|
||||
function test_curveFeeChainedTORN() public {
|
||||
feeOracle.setTornOracleIsUniswapV3(true);
|
||||
feeOracle.setTornOracleIsUniswap(true);
|
||||
|
||||
_setCurveFeeChainedOracleForInstance(feeOracle, cu10_000); // CRVUSD 10_000
|
||||
|
||||
@ -86,7 +90,12 @@ contract OracleTests is Test {
|
||||
"\nTORN Fee calculated ------------------------------------------------------\n",
|
||||
uint256(
|
||||
feeOracle.getFee(
|
||||
TORN, cu10_000, InstanceData(IERC20(cu10_000.token()), 0, true, true), 30, 10_000
|
||||
TORN,
|
||||
InstanceWithFee({
|
||||
logic: cu10_000,
|
||||
state: InstanceState(IERC20(cu10_000.token()), 0, true, true),
|
||||
fee: FeeDataForOracle(0, 30, 10_000, 2 days, 0)
|
||||
})
|
||||
)
|
||||
),
|
||||
"\n------------------------------------------------------------------------\n"
|
||||
|
@ -21,7 +21,7 @@ import { UniswapFeeOracle } from "src/v2/UniswapFeeOracle.sol";
|
||||
|
||||
import { CurveFeeOracle, ICurvePriceOracle, CurveChainedOracles } from "src/v2/CurveFeeOracle.sol";
|
||||
|
||||
import { InstanceRegistry, InstanceData } from "src/v2/InstanceRegistry.sol";
|
||||
import { InstanceRegistry, InstanceState } from "src/v2/InstanceRegistry.sol";
|
||||
|
||||
import { FeeOracleManager } from "src/v2/FeeOracleManager.sol";
|
||||
|
||||
@ -161,7 +161,7 @@ contract ProposalTests is Instances, TornadoProposalTest {
|
||||
delimit();
|
||||
|
||||
console2.log("\n~~~~~~~~~~~~~~~~~~ DATA ~~~~~~~~~~~~~~~~~~\n");
|
||||
InstanceData memory data = instanceRegistry.getInstanceData(cu100);
|
||||
InstanceState memory data = instanceRegistry.getInstanceState(cu100);
|
||||
delimit();
|
||||
console2.log("cu100:");
|
||||
console2.log("token: ", address(data.token));
|
||||
@ -169,28 +169,28 @@ contract ProposalTests is Instances, TornadoProposalTest {
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(cu1_000);
|
||||
data = instanceRegistry.getInstanceState(cu1_000);
|
||||
console2.log("cu1_000:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(cu10_000);
|
||||
data = instanceRegistry.getInstanceState(cu10_000);
|
||||
console2.log("cu10_000:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(cu100_000);
|
||||
data = instanceRegistry.getInstanceState(cu100_000);
|
||||
console2.log("cu100_000:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(cu1_000_000);
|
||||
data = instanceRegistry.getInstanceState(cu1_000_000);
|
||||
console2.log("cu1_000_000:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
@ -294,7 +294,7 @@ contract ProposalTests is Instances, TornadoProposalTest {
|
||||
delimit();
|
||||
|
||||
console2.log("\n~~~~~~~~~~~~~~~~~~ DATA ~~~~~~~~~~~~~~~~~~\n");
|
||||
InstanceData memory data = instanceRegistry.getInstanceData(eth10);
|
||||
InstanceState memory data = instanceRegistry.getInstanceState(eth10);
|
||||
delimit();
|
||||
console2.log("eth10:");
|
||||
console2.log("token: ", address(data.token));
|
||||
@ -302,21 +302,21 @@ contract ProposalTests is Instances, TornadoProposalTest {
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(eth100);
|
||||
data = instanceRegistry.getInstanceState(eth100);
|
||||
console2.log("eth100:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(dai10000);
|
||||
data = instanceRegistry.getInstanceState(dai10000);
|
||||
console2.log("dai10000:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(usdt100);
|
||||
data = instanceRegistry.getInstanceState(usdt100);
|
||||
console2.log("usdt100:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
@ -335,14 +335,14 @@ contract ProposalTests is Instances, TornadoProposalTest {
|
||||
// Now log again
|
||||
console2.log("\n~~~~~~~~~~~~~~~~~~ SHOULD HAVE CHANGED ~~~~~~~~~~~~~~~~~~\n");
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(2);
|
||||
data = instanceRegistry.getInstanceState(2);
|
||||
console2.log("NOT eth10:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
console2.log("iserc20: ", data.isERC20);
|
||||
console2.log("isenabled: ", data.isEnabled);
|
||||
delimit();
|
||||
data = instanceRegistry.getInstanceData(6);
|
||||
data = instanceRegistry.getInstanceState(6);
|
||||
console2.log("NOT dai10000:");
|
||||
console2.log("token: ", address(data.token));
|
||||
console2.log("index: ", uint256(data.index));
|
||||
@ -358,14 +358,14 @@ contract ProposalTests is Instances, TornadoProposalTest {
|
||||
instanceRegistry.addInstance(eth10);
|
||||
|
||||
vm.prank(address(governance));
|
||||
data = instanceRegistry.getInstanceData(dai10000);
|
||||
data = instanceRegistry.getInstanceState(dai10000);
|
||||
require(data.token == DAI, "not dai");
|
||||
require(data.index == 15, "not 15");
|
||||
require(data.isERC20, "not token");
|
||||
require(data.isEnabled, "not enabled");
|
||||
|
||||
vm.prank(address(governance));
|
||||
data = instanceRegistry.getInstanceData(eth10);
|
||||
data = instanceRegistry.getInstanceState(eth10);
|
||||
require(data.token == IERC20(0), "not eth");
|
||||
require(data.index == 16, "not last");
|
||||
require(!data.isERC20, "not not token");
|
||||
|
Loading…
Reference in New Issue
Block a user