Skip to content

Commit

Permalink
feat: added twap threshold by pool
Browse files Browse the repository at this point in the history
* feat: added twap threshold by pool

* refactor: renamed cooldown to strategyCooldown

* feat: added ZeroThreshold check

* feat: twapThreshold fallbacks to default

* test: added setTwapThreshold to 0 scenario

Co-authored-by: Weißer Hase <wei3erHase@protonmail.com>
  • Loading branch information
0xJabberwock and wei3erHase authored Jan 18, 2023
1 parent d454589 commit 77afdbd
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 200 deletions.
2 changes: 1 addition & 1 deletion solidity/contracts/DataFeed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {PipelineManagement, Governable} from './peripherals/PipelineManagement.s
import {IDataFeed, IDataFeedStrategy, IUniswapV3Pool, IConnextSenderAdapter, IBridgeSenderAdapter, IOracleSidechain} from '../interfaces/IDataFeed.sol';
import {Create2Address} from '../libraries/Create2Address.sol';

/// @title The DataFeed interface
/// @title The DataFeed contract
/// @notice Queries UniV3Pools, stores history proofs on chain, handles data broadcast
contract DataFeed is IDataFeed, PipelineManagement {
/// @inheritdoc IDataFeed
Expand Down
51 changes: 37 additions & 14 deletions solidity/contracts/DataFeedStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ contract DataFeedStrategy is IDataFeedStrategy, Governable {
uint32 public strategyCooldown;

/// @inheritdoc IDataFeedStrategy
uint24 public twapThreshold;
uint24 public defaultTwapThreshold;

mapping(bytes32 => uint24) internal _twapThreshold;

/// @inheritdoc IDataFeedStrategy
uint32 public twapLength;
Expand All @@ -34,9 +36,9 @@ contract DataFeedStrategy is IDataFeedStrategy, Governable {
) Governable(_governor) {
if (address(_dataFeed) == address(0)) revert ZeroAddress();
dataFeed = _dataFeed;
_setStrategyCooldown(_params.cooldown);
_setStrategyCooldown(_params.strategyCooldown);
_setDefaultTwapThreshold(_params.defaultTwapThreshold);
_setTwapLength(_params.twapLength);
_setTwapThreshold(_params.twapThreshold);
_setPeriodDuration(_params.periodDuration);
}

Expand Down Expand Up @@ -69,20 +71,31 @@ contract DataFeedStrategy is IDataFeedStrategy, Governable {
}

/// @inheritdoc IDataFeedStrategy
function setTwapLength(uint32 _twapLength) external onlyGovernor {
_setTwapLength(_twapLength);
function setDefaultTwapThreshold(uint24 _defaultTwapThreshold) external onlyGovernor {
_setDefaultTwapThreshold(_defaultTwapThreshold);
}

/// @inheritdoc IDataFeedStrategy
function setTwapThreshold(bytes32 _poolSalt, uint24 _poolTwapThreshold) external onlyGovernor {
_setTwapThreshold(_poolSalt, _poolTwapThreshold);
}

/// @inheritdoc IDataFeedStrategy
function setTwapThreshold(uint24 _twapThreshold) external onlyGovernor {
_setTwapThreshold(_twapThreshold);
function setTwapLength(uint32 _twapLength) external onlyGovernor {
_setTwapLength(_twapLength);
}

/// @inheritdoc IDataFeedStrategy
function setPeriodDuration(uint32 _periodDuration) external onlyGovernor {
_setPeriodDuration(_periodDuration);
}

/// @inheritdoc IDataFeedStrategy
function twapThreshold(bytes32 _poolSalt) external view returns (uint24 _poolTwapThreshold) {
_poolTwapThreshold = _twapThreshold[_poolSalt];
if (_poolTwapThreshold == 0) return defaultTwapThreshold;
}

/// @inheritdoc IDataFeedStrategy
function isStrategic(bytes32 _poolSalt) external view returns (TriggerReason _reason) {
if (isStrategic(_poolSalt, TriggerReason.TIME)) return TriggerReason.TIME;
Expand Down Expand Up @@ -168,9 +181,12 @@ contract DataFeedStrategy is IDataFeedStrategy, Governable {

int24 _oracleArithmeticMeanTick = _computeTwap(_poolTickCumulatives[0], _oracleTickCumulative, _twapLength);

uint24 _poolTwapThreshold = _twapThreshold[_poolSalt];
if (_poolTwapThreshold == 0) _poolTwapThreshold = defaultTwapThreshold;

return
_poolArithmeticMeanTick > _oracleArithmeticMeanTick + int24(twapThreshold) ||
_poolArithmeticMeanTick < _oracleArithmeticMeanTick - int24(twapThreshold);
_poolArithmeticMeanTick > _oracleArithmeticMeanTick + int24(_poolTwapThreshold) ||
_poolArithmeticMeanTick < _oracleArithmeticMeanTick - int24(_poolTwapThreshold);
}

function _computeTwap(
Expand Down Expand Up @@ -202,18 +218,25 @@ contract DataFeedStrategy is IDataFeedStrategy, Governable {
emit StrategyCooldownSet(_strategyCooldown);
}

function _setDefaultTwapThreshold(uint24 _defaultTwapThreshold) private {
if (_defaultTwapThreshold == 0) revert ZeroThreshold();

defaultTwapThreshold = _defaultTwapThreshold;
emit DefaultTwapThresholdSet(_defaultTwapThreshold);
}

function _setTwapThreshold(bytes32 _poolSalt, uint24 _poolTwapThreshold) private {
_twapThreshold[_poolSalt] = _poolTwapThreshold;
emit TwapThresholdSet(_poolSalt, _poolTwapThreshold);
}

function _setTwapLength(uint32 _twapLength) private {
if ((_twapLength > strategyCooldown) || (_twapLength < periodDuration)) revert WrongSetting();

twapLength = _twapLength;
emit TwapLengthSet(_twapLength);
}

function _setTwapThreshold(uint24 _twapThreshold) private {
twapThreshold = _twapThreshold;
emit TwapThresholdSet(_twapThreshold);
}

function _setPeriodDuration(uint32 _periodDuration) private {
if (_periodDuration > twapLength || _periodDuration == 0) revert WrongSetting();

Expand Down
39 changes: 28 additions & 11 deletions solidity/interfaces/IDataFeedStrategy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ interface IDataFeedStrategy is IGovernable {

struct StrategySettings {
uint32 periodDuration; // Resolution of the oracle, target twap length
uint32 cooldown; // Time since last update to wait to time-trigger update
uint24 twapThreshold; // Twap difference, in ticks, to twap-trigger update
uint32 strategyCooldown; // Time since last update to wait to time-trigger update
uint24 defaultTwapThreshold; // Default twap difference, in ticks, to twap-trigger update
uint32 twapLength; // Twap length, in seconds, used for twap-trigger update
}

Expand All @@ -38,8 +38,12 @@ interface IDataFeedStrategy is IGovernable {
/// @return _strategyCooldown Time in seconds since last update required to time-trigger an update
function strategyCooldown() external view returns (uint32 _strategyCooldown);

/// @return _defaultTwapThreshold Default twap difference, in ticks, to twap-trigger an update
function defaultTwapThreshold() external view returns (uint24 _defaultTwapThreshold);

/// @param _poolSalt The pool salt defined by token0 token1 and fee
/// @return _twapThreshold Twap difference, in ticks, to twap-trigger an update
function twapThreshold() external view returns (uint24 _twapThreshold);
function twapThreshold(bytes32 _poolSalt) external view returns (uint24 _twapThreshold);

/// @return _twapLength The time length, in seconds, used to calculate twap-trigger
function twapLength() external view returns (uint32 _twapLength);
Expand All @@ -55,14 +59,19 @@ interface IDataFeedStrategy is IGovernable {
/// @param _strategyCooldown The new job cooldown
event StrategyCooldownSet(uint32 _strategyCooldown);

/// @notice Emitted when the owner updates the job default twap threshold percentage
/// @param _defaultTwapThreshold The default twap difference threshold used to trigger an update of the oracle
event DefaultTwapThresholdSet(uint24 _defaultTwapThreshold);

/// @notice Emitted when the owner updates the job twap threshold percentage of a pool
/// @param _poolSalt The pool salt defined by token0 token1 and fee
/// @param _twapThreshold The default twap difference threshold used to trigger an update of the oracle
event TwapThresholdSet(bytes32 _poolSalt, uint24 _twapThreshold);

/// @notice Emitted when the owner updates the job twap length
/// @param _twapLength The new length of the twap used to trigger an update of the oracle
event TwapLengthSet(uint32 _twapLength);

/// @notice Emitted when the owner updates the job twap threshold percentage
/// @param _twapThreshold The twap difference threshold used to trigger an update of the oracle
event TwapThresholdSet(uint24 _twapThreshold);

/// @notice Emitted when the owner updates the job period length
/// @param _periodDuration The new length of reading resolution periods
event PeriodDurationSet(uint32 _periodDuration);
Expand All @@ -75,6 +84,9 @@ interface IDataFeedStrategy is IGovernable {
/// @notice Thrown if setting breaks strategyCooldown >= twapLength >= periodDuration
error WrongSetting();

/// @notice Thrown if defaultTwapThreshold is set to zero
error ZeroThreshold();

// FUNCTIONS

/// @notice Permisionless, used to update the oracle state
Expand All @@ -86,14 +98,19 @@ interface IDataFeedStrategy is IGovernable {
/// @param _strategyCooldown The job cooldown to be set
function setStrategyCooldown(uint32 _strategyCooldown) external;

/// @notice Sets the job default twap threshold percentage
/// @param _defaultTwapThreshold The default twap difference threshold used to trigger an update of the oracle
function setDefaultTwapThreshold(uint24 _defaultTwapThreshold) external;

/// @notice Sets the job twap threshold percentage of a pool
/// @param _poolSalt The pool salt defined by token0 token1 and fee
/// @param _twapThreshold The twap difference threshold used to trigger an update of the oracle
function setTwapThreshold(bytes32 _poolSalt, uint24 _twapThreshold) external;

/// @notice Sets the job twap length
/// @param _twapLength The new length of the twap used to trigger an update of the oracle
function setTwapLength(uint32 _twapLength) external;

/// @notice Sets the job twap threshold percentage
/// @param _twapThreshold The twap difference threshold used to trigger an update of the oracle
function setTwapThreshold(uint24 _twapThreshold) external;

/// @notice Sets the job period length
/// @param _periodDuration The new length of reading resolution periods
function setPeriodDuration(uint32 _periodDuration) external;
Expand Down
8 changes: 4 additions & 4 deletions test/e2e/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ const destinationDomain = 1111;
const minLastOracleDelta = 900;

const periodDuration = 1200;
const cooldown = 3600;
const twapThreshold = 500;
const strategyCooldown = 3600;
const defaultTwapThreshold = 500;
const twapLength = 2400;

export async function setupContracts(): Promise<{
Expand Down Expand Up @@ -83,9 +83,9 @@ export async function setupContracts(): Promise<{

const dataFeedStrategy = (await dataFeedStrategyFactory.connect(deployer).deploy(governor.address, dataFeed.address, {
periodDuration,
cooldown,
strategyCooldown,
defaultTwapThreshold,
twapLength,
twapThreshold,
})) as DataFeedStrategy;

currentNonce = await ethers.provider.getTransactionCount(deployer.address);
Expand Down
Loading

0 comments on commit 77afdbd

Please sign in to comment.