From 628b2eaeae48b79fb8e073eb25458c7518500c1e Mon Sep 17 00:00:00 2001 From: Tyler Loewen Date: Mon, 3 Jul 2023 21:33:35 -0700 Subject: [PATCH 1/3] Make functions virtual --- .../algebra/AlgebraLiquidityAccumulator.sol | 2 +- .../proto/algebra/AlgebraPriceAccumulator.sol | 8 ++++---- .../balancer/BalancerV2LiquidityAccumulator.sol | 4 ++-- .../BalancerV2StablePriceAccumulator.sol | 16 ++++++++++------ .../BalancerV2WeightedPriceAccumulator.sol | 6 +++--- .../uniswap/UniswapV2LiquidityAccumulator.sol | 4 ++-- .../proto/uniswap/UniswapV2PriceAccumulator.sol | 6 +++--- .../uniswap/UniswapV3LiquidityAccumulator.sol | 4 ++-- .../proto/uniswap/UniswapV3PriceAccumulator.sol | 10 +++++----- 9 files changed, 32 insertions(+), 28 deletions(-) diff --git a/contracts/accumulators/proto/algebra/AlgebraLiquidityAccumulator.sol b/contracts/accumulators/proto/algebra/AlgebraLiquidityAccumulator.sol index 26a9bcc..aebbd72 100644 --- a/contracts/accumulators/proto/algebra/AlgebraLiquidityAccumulator.sol +++ b/contracts/accumulators/proto/algebra/AlgebraLiquidityAccumulator.sol @@ -71,7 +71,7 @@ contract AlgebraLiquidityAccumulator is LiquidityAccumulator { return _liquidityDecimals; } - function computeAddress(address token, address _quoteToken) internal view returns (address pool) { + function computeAddress(address token, address _quoteToken) internal view virtual returns (address pool) { if (token > _quoteToken) { // Sort tokens so that the first token is the one with the lower address (token, _quoteToken) = (_quoteToken, token); diff --git a/contracts/accumulators/proto/algebra/AlgebraPriceAccumulator.sol b/contracts/accumulators/proto/algebra/AlgebraPriceAccumulator.sol index e93410e..0e5ea7d 100644 --- a/contracts/accumulators/proto/algebra/AlgebraPriceAccumulator.sol +++ b/contracts/accumulators/proto/algebra/AlgebraPriceAccumulator.sol @@ -91,7 +91,7 @@ contract AlgebraPriceAccumulator is PriceAccumulator { address quoteToken_, uint160 sqrtPriceX96, uint128 tokenAmount - ) internal pure returns (uint256 price) { + ) internal pure virtual returns (uint256 price) { // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself if (sqrtPriceX96 <= type(uint128).max) { uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96; @@ -106,7 +106,7 @@ contract AlgebraPriceAccumulator is PriceAccumulator { } } - function calculatePrice(address token) internal view returns (bool hasLiquidity, uint256 price) { + function calculatePrice(address token) internal view virtual returns (bool hasLiquidity, uint256 price) { uint128 wholeTokenAmount = computeWholeUnitAmount(token); address pool = computeAddress(token, quoteToken); @@ -147,7 +147,7 @@ contract AlgebraPriceAccumulator is PriceAccumulator { return _price.toUint112(); } - function computeAddress(address token, address _quoteToken) internal view returns (address pool) { + function computeAddress(address token, address _quoteToken) internal view virtual returns (address pool) { if (token > _quoteToken) { // Sort tokens so that the first token is the one with the lower address (token, _quoteToken) = (_quoteToken, token); @@ -164,7 +164,7 @@ contract AlgebraPriceAccumulator is PriceAccumulator { ); } - function computeWholeUnitAmount(address token) internal view returns (uint128 amount) { + function computeWholeUnitAmount(address token) internal view virtual returns (uint128 amount) { amount = uint128(10) ** IERC20Metadata(token).decimals(); } } diff --git a/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol b/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol index f81d345..715f4c0 100644 --- a/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol +++ b/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol @@ -133,7 +133,7 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { return _liquidityDecimals; } - function inRecoveryMode(address pool) internal view returns (bool) { + function inRecoveryMode(address pool) internal view virtual returns (bool) { (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.inRecoveryMode.selector)); if (success && data.length == 32) { return abi.decode(data, (bool)); @@ -145,7 +145,7 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { function findTokenIndex( address[] memory tokens, address token - ) internal view returns (bool, uint256, bool, uint256) { + ) internal view virtual returns (bool, uint256, bool, uint256) { uint256 length = tokens.length; for (uint256 i = 0; i < length; ++i) { if (tokens[i] == token) { diff --git a/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol b/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol index dcd9b8e..84f5a7c 100644 --- a/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol +++ b/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol @@ -158,7 +158,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { return super.canUpdate(data); } - function inRecoveryMode(address pool) internal view returns (bool) { + function inRecoveryMode(address pool) internal view virtual returns (bool) { (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.inRecoveryMode.selector)); if (success && data.length == 32) { return abi.decode(data, (bool)); @@ -170,7 +170,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { function findTokenIndex( address[] memory tokens, address token - ) internal view returns (bool, uint256, bool, uint256) { + ) internal view virtual returns (bool, uint256, bool, uint256) { uint256 length = tokens.length; for (uint256 i = 0; i < length; ++i) { if (tokens[i] == token) { @@ -286,7 +286,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { if (price == 0) return 1; } - function computeWholeUnitAmount(address token) internal view returns (uint256 amount) { + function computeWholeUnitAmount(address token) internal view virtual returns (uint256 amount) { amount = uint256(10) ** IERC20Metadata(token).decimals(); } @@ -294,7 +294,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { * @dev Reverses the `scalingFactor` applied to `amount`, resulting in a smaller or equal value depending on * whether it needed scaling or not. The result is rounded down. */ - function _downscaleDown(uint256 amount, uint256 scalingFactor) internal pure returns (uint256) { + function _downscaleDown(uint256 amount, uint256 scalingFactor) internal pure virtual returns (uint256) { return FixedPoint.divDown(amount, scalingFactor); } @@ -302,7 +302,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { * @dev Applies `scalingFactor` to `amount`, resulting in a larger or equal value depending on whether it needed * scaling or not. */ - function _upscale(uint256 amount, uint256 scalingFactor) internal pure returns (uint256) { + function _upscale(uint256 amount, uint256 scalingFactor) internal pure virtual returns (uint256) { // Upscale rounding wouldn't necessarily always go in the same direction: in a swap for example the balance of // token in should be rounded up, and that of token out rounded down. This is the only place where we round in // the same direction for all amounts, as the impact of this rounding is expected to be minimal (and there's no @@ -314,7 +314,11 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { * @dev Same as `_upscale`, but for an entire array. This function does not return anything, but instead *mutates* * the `amounts` array. */ - function _upscaleArray(uint256[] memory amounts, uint256[] memory scalingFactors, uint256 numTokens) internal pure { + function _upscaleArray( + uint256[] memory amounts, + uint256[] memory scalingFactors, + uint256 numTokens + ) internal pure virtual { for (uint256 i = 0; i < numTokens; ++i) { amounts[i] = FixedPoint.mulDown(amounts[i], scalingFactors[i]); } diff --git a/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol b/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol index 56894eb..3aaf542 100644 --- a/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol +++ b/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol @@ -91,7 +91,7 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { return super.canUpdate(data); } - function inRecoveryMode(address pool) internal view returns (bool) { + function inRecoveryMode(address pool) internal view virtual returns (bool) { (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.inRecoveryMode.selector)); if (success && data.length == 32) { return abi.decode(data, (bool)); @@ -100,7 +100,7 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { return false; // Doesn't implement the function } - function findTokenIndex(address[] memory tokens, address token) internal pure returns (uint256) { + function findTokenIndex(address[] memory tokens, address token) internal pure virtual returns (uint256) { uint256 length = tokens.length; for (uint256 i = 0; i < length; ++i) { if (tokens[i] == token) { @@ -153,7 +153,7 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { if (price == 0) return 1; } - function computeWholeUnitAmount(address token) internal view returns (uint256 amount) { + function computeWholeUnitAmount(address token) internal view virtual returns (uint256 amount) { amount = uint256(10) ** IERC20Metadata(token).decimals(); } } diff --git a/contracts/accumulators/proto/uniswap/UniswapV2LiquidityAccumulator.sol b/contracts/accumulators/proto/uniswap/UniswapV2LiquidityAccumulator.sol index 1924682..42a2978 100644 --- a/contracts/accumulators/proto/uniswap/UniswapV2LiquidityAccumulator.sol +++ b/contracts/accumulators/proto/uniswap/UniswapV2LiquidityAccumulator.sol @@ -91,7 +91,7 @@ contract UniswapV2LiquidityAccumulator is LiquidityAccumulator { } // returns sorted token addresses, used to handle return values from pairs sorted in this order - function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { + function sortTokens(address tokenA, address tokenB) internal pure virtual returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2Library: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniswapV2Library: ZERO_ADDRESS"); @@ -103,7 +103,7 @@ contract UniswapV2LiquidityAccumulator is LiquidityAccumulator { bytes32 initCodeHash_, address tokenA, address tokenB - ) internal pure returns (address pair) { + ) internal pure virtual returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( uint160( diff --git a/contracts/accumulators/proto/uniswap/UniswapV2PriceAccumulator.sol b/contracts/accumulators/proto/uniswap/UniswapV2PriceAccumulator.sol index 2ecf193..01e52ed 100644 --- a/contracts/accumulators/proto/uniswap/UniswapV2PriceAccumulator.sol +++ b/contracts/accumulators/proto/uniswap/UniswapV2PriceAccumulator.sol @@ -88,12 +88,12 @@ contract UniswapV2PriceAccumulator is PriceAccumulator { if (price == 0) return 1; } - function computeWholeUnitAmount(address token) internal view returns (uint256 amount) { + function computeWholeUnitAmount(address token) internal view virtual returns (uint256 amount) { amount = uint256(10) ** IERC20Metadata(token).decimals(); } // returns sorted token addresses, used to handle return values from pairs sorted in this order - function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { + function sortTokens(address tokenA, address tokenB) internal pure virtual returns (address token0, address token1) { require(tokenA != tokenB, "UniswapV2PriceAccumulator: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "UniswapV2PriceAccumulator: ZERO_ADDRESS"); @@ -105,7 +105,7 @@ contract UniswapV2PriceAccumulator is PriceAccumulator { bytes32 initCodeHash_, address tokenA, address tokenB - ) internal pure returns (address pair) { + ) internal pure virtual returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( uint160( diff --git a/contracts/accumulators/proto/uniswap/UniswapV3LiquidityAccumulator.sol b/contracts/accumulators/proto/uniswap/UniswapV3LiquidityAccumulator.sol index 479ec9a..9cd1676 100644 --- a/contracts/accumulators/proto/uniswap/UniswapV3LiquidityAccumulator.sol +++ b/contracts/accumulators/proto/uniswap/UniswapV3LiquidityAccumulator.sol @@ -78,7 +78,7 @@ contract UniswapV3LiquidityAccumulator is LiquidityAccumulator { /// @param tokenB The second token of a pool, unsorted /// @param fee The fee level of the pool /// @return Poolkey The pool details with ordered token0 and token1 assignments - function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure returns (PoolKey memory) { + function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure virtual returns (PoolKey memory) { if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); return PoolKey({token0: tokenA, token1: tokenB, fee: fee}); } @@ -91,7 +91,7 @@ contract UniswapV3LiquidityAccumulator is LiquidityAccumulator { address factory, bytes32 _initCodeHash, PoolKey memory key - ) internal pure returns (address pool) { + ) internal pure virtual returns (address pool) { require(key.token0 < key.token1); pool = address( uint160( diff --git a/contracts/accumulators/proto/uniswap/UniswapV3PriceAccumulator.sol b/contracts/accumulators/proto/uniswap/UniswapV3PriceAccumulator.sol index 4137c00..bbb84a7 100644 --- a/contracts/accumulators/proto/uniswap/UniswapV3PriceAccumulator.sol +++ b/contracts/accumulators/proto/uniswap/UniswapV3PriceAccumulator.sol @@ -67,7 +67,7 @@ contract UniswapV3PriceAccumulator is PriceAccumulator { address quoteToken_, uint160 sqrtPriceX96, uint128 tokenAmount - ) internal pure returns (uint256 price) { + ) internal pure virtual returns (uint256 price) { // Calculate quoteAmount with better precision if it doesn't overflow when multiplied by itself if (sqrtPriceX96 <= type(uint128).max) { uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96; @@ -91,7 +91,7 @@ contract UniswapV3PriceAccumulator is PriceAccumulator { * @return price The price of the specified token in terms of the quote token, scaled by the quote token decimal * places. If hasLiquidity equals false, the returned price will always equal 0. */ - function calculateWeightedPrice(address token) internal view returns (bool hasLiquidity, uint256 price) { + function calculateWeightedPrice(address token) internal view virtual returns (bool hasLiquidity, uint256 price) { uint24[] memory _poolFees = poolFees; uint128 wholeTokenAmount = computeWholeUnitAmount(token); @@ -156,7 +156,7 @@ contract UniswapV3PriceAccumulator is PriceAccumulator { /// @param tokenB The second token of a pool, unsorted /// @param fee The fee level of the pool /// @return Poolkey The pool details with ordered token0 and token1 assignments - function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure returns (PoolKey memory) { + function getPoolKey(address tokenA, address tokenB, uint24 fee) internal pure virtual returns (PoolKey memory) { if (tokenA > tokenB) (tokenA, tokenB) = (tokenB, tokenA); return PoolKey({token0: tokenA, token1: tokenB, fee: fee}); } @@ -169,7 +169,7 @@ contract UniswapV3PriceAccumulator is PriceAccumulator { address factory, bytes32 _initCodeHash, PoolKey memory key - ) internal pure returns (address pool) { + ) internal pure virtual returns (address pool) { require(key.token0 < key.token1); pool = address( uint160( @@ -187,7 +187,7 @@ contract UniswapV3PriceAccumulator is PriceAccumulator { ); } - function computeWholeUnitAmount(address token) internal view returns (uint128 amount) { + function computeWholeUnitAmount(address token) internal view virtual returns (uint128 amount) { amount = uint128(10) ** IERC20Metadata(token).decimals(); } } From bd8db52f0a117448fd1caafcce4a6d328b5c04c6 Mon Sep 17 00:00:00 2001 From: Tyler Loewen Date: Tue, 4 Jul 2023 14:32:32 -0700 Subject: [PATCH 2/3] Replace Balancer recovery mode checks with pause checks - Some healthy pools keep recovery mode on, which makes checking this unreliable - Swaps, joins, and exits can still be performed in recovery mode, allowing for the continuation of price discovery - Swaps and other functionality are not permitted when paused, so we should not rely on the pools when they're paused --- README.md | 2 +- .../BalancerV2LiquidityAccumulator.sol | 40 +- .../BalancerV2StablePriceAccumulator.sol | 38 +- .../BalancerV2WeightedPriceAccumulator.sol | 26 +- contracts/test/BalancerLinearPoolStub.sol | 46 ++ contracts/test/BalancerStablePoolStub.sol | 46 ++ contracts/test/BalancerWeightedPoolStub.sol | 46 ++ .../balancer-liquidity-accumulator.js | 406 +++++++++++++++--- .../balancer-stable-price-accumulator.js | 185 ++++++-- .../balancer-weighted-price-accumulator.js | 49 ++- 10 files changed, 742 insertions(+), 142 deletions(-) diff --git a/README.md b/README.md index a204c9f..7758b21 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Adrastia Core [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) -![5969 out of 5969 tests passing](https://img.shields.io/badge/tests-5969/5969%20passing-brightgreen.svg?style=flat-square) +![6007 out of 6007 tests passing](https://img.shields.io/badge/tests-6007/6007%20passing-brightgreen.svg?style=flat-square) ![test-coverage >99%](https://img.shields.io/badge/test%20coverage-%3E99%25-brightgreen.svg?style=flat-square) Adrastia Core is a set of Solidity smart contracts for building EVM oracle solutions. diff --git a/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol b/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol index 715f4c0..24ba55a 100644 --- a/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol +++ b/contracts/accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol @@ -17,7 +17,12 @@ interface IVault { interface IBasePool { function getPoolId() external view returns (bytes32); - function inRecoveryMode() external view returns (bool); + function getPausedState() + external + view + returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + + function paused() external view returns (bool); } interface ILinearPool { @@ -45,7 +50,7 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { error TokenNotFound(address token); - error PoolInRecoveryMode(address pool); + error PoolIsPaused(address pool); constructor( IAveragingStrategy averagingStrategy_, @@ -94,7 +99,7 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { return false; } - if (inRecoveryMode(poolAddress)) { + if (isPaused(poolAddress)) { // The pool is in recovery mode return false; } @@ -108,7 +113,7 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { if (quoteTokenIsWrapped) { // Check if the quote token linear pool is in recovery mode - if (inRecoveryMode(tokens[quoteTokenIndex])) { + if (isPaused(tokens[quoteTokenIndex])) { // The quote token linear pool is in recovery mode return false; } @@ -116,7 +121,7 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { if (tokenIsWrapped) { // Check if the token linear pool is in recovery mode - if (inRecoveryMode(tokens[tokenIndex])) { + if (isPaused(tokens[tokenIndex])) { // The token linear pool is in recovery mode return false; } @@ -133,13 +138,20 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { return _liquidityDecimals; } - function inRecoveryMode(address pool) internal view virtual returns (bool) { - (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.inRecoveryMode.selector)); + function isPaused(address pool) internal view virtual returns (bool) { + (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.getPausedState.selector)); + if (success && data.length == 96) { + (bool paused, , ) = abi.decode(data, (bool, uint256, uint256)); + + return paused; + } + + (success, data) = pool.staticcall(abi.encodeWithSelector(IBasePool.paused.selector)); if (success && data.length == 32) { return abi.decode(data, (bool)); } - return false; // Doesn't implement the function + return false; // Doesn't implement any of the pause functions } function findTokenIndex( @@ -173,8 +185,8 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { bytes memory data ) internal view virtual override returns (uint112 tokenLiquidity, uint112 quoteTokenLiquidity) { // Ensure that the pool is not in recovery mode - if (inRecoveryMode(poolAddress)) { - revert PoolInRecoveryMode(poolAddress); + if (isPaused(poolAddress)) { + revert PoolIsPaused(poolAddress); } address token = abi.decode(data, (address)); @@ -197,8 +209,8 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { // Token balance is for the wrapped token, get the balance of the underlying token // Ensure that the token linear pool is not in recovery mode - if (inRecoveryMode(tokens[tokenIndex])) { - revert PoolInRecoveryMode(tokens[tokenIndex]); + if (isPaused(tokens[tokenIndex])) { + revert PoolIsPaused(tokens[tokenIndex]); } // Get the token wrapper pool ID @@ -220,8 +232,8 @@ contract BalancerV2LiquidityAccumulator is LiquidityAccumulator { // Token balance is for the wrapped token, get the balance of the underlying token // Ensure that the quote token linear pool is not in recovery mode - if (inRecoveryMode(tokens[quoteTokenIndex])) { - revert PoolInRecoveryMode(tokens[quoteTokenIndex]); + if (isPaused(tokens[quoteTokenIndex])) { + revert PoolIsPaused(tokens[quoteTokenIndex]); } // Get the balances of the wrapper pool diff --git a/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol b/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol index 84f5a7c..5158ae7 100644 --- a/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol +++ b/contracts/accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol @@ -36,7 +36,12 @@ interface IBasePool { */ function getScalingFactors() external view returns (uint256[] memory); - function inRecoveryMode() external view returns (bool); + function getPausedState() + external + view + returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + + function paused() external view returns (bool); } interface ILinearPool { @@ -65,7 +70,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { error TokenNotFound(address token); - error PoolInRecoveryMode(address pool); + error PoolIsPaused(address pool); error AmplificationParameterUpdating(); constructor( @@ -119,7 +124,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { return false; } - if (inRecoveryMode(poolAddress)) { + if (isPaused(poolAddress)) { // The pool is in recovery mode return false; } @@ -133,7 +138,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { if (quoteTokenIsWrapped) { // Check if the quote token linear pool is in recovery mode - if (inRecoveryMode(tokens[quoteTokenIndex])) { + if (isPaused(tokens[quoteTokenIndex])) { // The quote token linear pool is in recovery mode return false; } @@ -141,7 +146,7 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { if (tokenIsWrapped) { // Check if the token linear pool is in recovery mode - if (inRecoveryMode(tokens[tokenIndex])) { + if (isPaused(tokens[tokenIndex])) { // The token linear pool is in recovery mode return false; } @@ -158,8 +163,15 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { return super.canUpdate(data); } - function inRecoveryMode(address pool) internal view virtual returns (bool) { - (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.inRecoveryMode.selector)); + function isPaused(address pool) internal view virtual returns (bool) { + (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.getPausedState.selector)); + if (success && data.length == 96) { + (bool paused, , ) = abi.decode(data, (bool, uint256, uint256)); + + return paused; + } + + (success, data) = pool.staticcall(abi.encodeWithSelector(IBasePool.paused.selector)); if (success && data.length == 32) { return abi.decode(data, (bool)); } @@ -203,8 +215,8 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { */ function fetchPrice(bytes memory data) internal view virtual override returns (uint112 price) { // Ensure that the pool is not in recovery mode - if (inRecoveryMode(poolAddress)) { - revert PoolInRecoveryMode(poolAddress); + if (isPaused(poolAddress)) { + revert PoolIsPaused(poolAddress); } address token = abi.decode(data, (address)); @@ -227,8 +239,8 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { // The token is inside a linear pool, so we need to convert the amount of the token to the amount of BPT // Ensure that the token linear pool is not in recovery mode - if (inRecoveryMode(tokens[tokenIndex])) { - revert PoolInRecoveryMode(tokens[tokenIndex]); + if (isPaused(tokens[tokenIndex])) { + revert PoolIsPaused(tokens[tokenIndex]); } ILinearPool linearPool = ILinearPool(tokens[tokenIndex]); @@ -272,8 +284,8 @@ contract BalancerV2StablePriceAccumulator is PriceAccumulator { // quote token // Ensure that the quote token linear pool is not in recovery mode - if (inRecoveryMode(tokens[quoteTokenIndex])) { - revert PoolInRecoveryMode(tokens[quoteTokenIndex]); + if (isPaused(tokens[quoteTokenIndex])) { + revert PoolIsPaused(tokens[quoteTokenIndex]); } ILinearPool linearPool = ILinearPool(tokens[quoteTokenIndex]); diff --git a/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol b/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol index 3aaf542..2e7bd1b 100644 --- a/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol +++ b/contracts/accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol @@ -15,7 +15,12 @@ interface IVault { } interface IBasePool { - function inRecoveryMode() external view returns (bool); + function getPausedState() + external + view + returns (bool paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime); + + function paused() external view returns (bool); } interface IWeightedPool { @@ -37,7 +42,7 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { error TokenNotFound(address token); - error PoolInRecoveryMode(address pool); + error PoolIsPaused(address pool); constructor( IAveragingStrategy averagingStrategy_, @@ -71,7 +76,7 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { return false; } - if (inRecoveryMode(poolAddress)) { + if (isPaused(poolAddress)) { // The pool is in recovery mode return false; } @@ -91,8 +96,15 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { return super.canUpdate(data); } - function inRecoveryMode(address pool) internal view virtual returns (bool) { - (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.inRecoveryMode.selector)); + function isPaused(address pool) internal view virtual returns (bool) { + (bool success, bytes memory data) = pool.staticcall(abi.encodeWithSelector(IBasePool.getPausedState.selector)); + if (success && data.length == 96) { + (bool paused, , ) = abi.decode(data, (bool, uint256, uint256)); + + return paused; + } + + (success, data) = pool.staticcall(abi.encodeWithSelector(IBasePool.paused.selector)); if (success && data.length == 32) { return abi.decode(data, (bool)); } @@ -120,8 +132,8 @@ contract BalancerV2WeightedPriceAccumulator is PriceAccumulator { */ function fetchPrice(bytes memory data) internal view virtual override returns (uint112 price) { // Ensure that the pool is not in recovery mode - if (inRecoveryMode(poolAddress)) { - revert PoolInRecoveryMode(poolAddress); + if (isPaused(poolAddress)) { + revert PoolIsPaused(poolAddress); } address token = abi.decode(data, (address)); diff --git a/contracts/test/BalancerLinearPoolStub.sol b/contracts/test/BalancerLinearPoolStub.sol index 8d917ee..bfccd1c 100644 --- a/contracts/test/BalancerLinearPoolStub.sol +++ b/contracts/test/BalancerLinearPoolStub.sol @@ -4,10 +4,20 @@ pragma solidity =0.8.13; import {ILinearPool, IBasePool} from "../accumulators/proto/balancer/BalancerV2LiquidityAccumulator.sol"; contract BalancerLinearPoolStub is IBasePool, ILinearPool { + struct PauseState { + bool paused; + uint256 pauseWindowEndTime; + uint256 bufferPeriodEndTime; + } + bool internal recoveryMode; bool internal supportsRecoveryMode; + bool internal supportsPausedState; + + bool internal supportsPaused; + uint256 internal rate; uint256[] internal scalingFactors; @@ -18,18 +28,34 @@ contract BalancerLinearPoolStub is IBasePool, ILinearPool { uint256 internal immutable mainIndex; + PauseState internal pauseState; + constructor(bytes32 poolId_, address mainToken_, uint256 mainIndex_) { poolId = poolId_; mainToken = mainToken_; mainIndex = mainIndex_; supportsRecoveryMode = true; + supportsPausedState = true; + supportsPaused = true; } function getPoolId() external view returns (bytes32) { return poolId; } + function getPausedState() external view returns (bool, uint256, uint256) { + if (!supportsPausedState) revert(); + + return (pauseState.paused, pauseState.pauseWindowEndTime, pauseState.bufferPeriodEndTime); + } + + function paused() external view returns (bool) { + if (!supportsPaused) revert(); + + return pauseState.paused; + } + function inRecoveryMode() external view returns (bool) { if (!supportsRecoveryMode) revert(); @@ -67,4 +93,24 @@ contract BalancerLinearPoolStub is IBasePool, ILinearPool { function stubSetRecoveryModeSupported(bool supported) external { supportsRecoveryMode = supported; } + + function stubSetPausedStateSupported(bool supported) external { + supportsPausedState = supported; + } + + function stubSetPausedSupported(bool supported) external { + supportsPaused = supported; + } + + function stubSetPausedState(bool _paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime) external { + pauseState.paused = _paused; + pauseState.pauseWindowEndTime = pauseWindowEndTime; + pauseState.bufferPeriodEndTime = bufferPeriodEndTime; + } + + function stubSetPaused(bool _paused) external { + pauseState.paused = _paused; + pauseState.pauseWindowEndTime = type(uint256).max; + pauseState.bufferPeriodEndTime = type(uint256).max; + } } diff --git a/contracts/test/BalancerStablePoolStub.sol b/contracts/test/BalancerStablePoolStub.sol index 5cb248f..49d37e1 100644 --- a/contracts/test/BalancerStablePoolStub.sol +++ b/contracts/test/BalancerStablePoolStub.sol @@ -6,10 +6,20 @@ import "@openzeppelin-v4/contracts/token/ERC20/ERC20.sol"; import {IStablePool, IBasePool} from "../accumulators/proto/balancer/BalancerV2StablePriceAccumulator.sol"; contract BalancerStablePoolStub is IStablePool, IBasePool, ERC20 { + struct PauseState { + bool paused; + uint256 pauseWindowEndTime; + uint256 bufferPeriodEndTime; + } + bool internal recoveryMode; bool internal supportsRecoveryMode; + bool internal supportsPausedState; + + bool internal supportsPaused; + bool internal hasBptToken; uint256 internal bptIndex; @@ -24,11 +34,15 @@ contract BalancerStablePoolStub is IStablePool, IBasePool, ERC20 { bytes32 internal immutable poolId; + PauseState internal pauseState; + constructor(bytes32 poolId_, uint256[] memory scalingFactors_) ERC20("BPT", "BPT") { poolId = poolId_; scalingFactors = scalingFactors_; supportsRecoveryMode = true; + supportsPausedState = true; + supportsPaused = true; } function getBptIndex() external view returns (uint256) { @@ -41,6 +55,18 @@ contract BalancerStablePoolStub is IStablePool, IBasePool, ERC20 { return poolId; } + function getPausedState() external view returns (bool, uint256, uint256) { + if (!supportsPausedState) revert(); + + return (pauseState.paused, pauseState.pauseWindowEndTime, pauseState.bufferPeriodEndTime); + } + + function paused() external view returns (bool) { + if (!supportsPaused) revert(); + + return pauseState.paused; + } + function inRecoveryMode() external view returns (bool) { if (!supportsRecoveryMode) revert(); @@ -88,4 +114,24 @@ contract BalancerStablePoolStub is IStablePool, IBasePool, ERC20 { function stubSetRecoveryModeSupported(bool supported) external { supportsRecoveryMode = supported; } + + function stubSetPausedStateSupported(bool supported) external { + supportsPausedState = supported; + } + + function stubSetPausedSupported(bool supported) external { + supportsPaused = supported; + } + + function stubSetPausedState(bool _paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime) external { + pauseState.paused = _paused; + pauseState.pauseWindowEndTime = pauseWindowEndTime; + pauseState.bufferPeriodEndTime = bufferPeriodEndTime; + } + + function stubSetPaused(bool _paused) external { + pauseState.paused = _paused; + pauseState.pauseWindowEndTime = type(uint256).max; + pauseState.bufferPeriodEndTime = type(uint256).max; + } } diff --git a/contracts/test/BalancerWeightedPoolStub.sol b/contracts/test/BalancerWeightedPoolStub.sol index cdba7ea..0dcb5e1 100644 --- a/contracts/test/BalancerWeightedPoolStub.sol +++ b/contracts/test/BalancerWeightedPoolStub.sol @@ -4,26 +4,52 @@ pragma solidity =0.8.13; import {IBasePool, IWeightedPool} from "../accumulators/proto/balancer/BalancerV2WeightedPriceAccumulator.sol"; contract BalancerWeightedPoolStub is IBasePool, IWeightedPool { + struct PauseState { + bool paused; + uint256 pauseWindowEndTime; + uint256 bufferPeriodEndTime; + } + bool internal recoveryMode; bool internal supportsRecoveryMode; + bool internal supportsPausedState; + + bool internal supportsPaused; + bytes32 internal immutable poolId; uint256[] internal weights; + PauseState internal pauseState; + constructor(bytes32 poolId_, uint256[] memory weights_) { recoveryMode = false; weights = weights_; poolId = poolId_; supportsRecoveryMode = true; + supportsPausedState = true; + supportsPaused = true; } function getPoolId() external view returns (bytes32) { return poolId; } + function getPausedState() external view returns (bool, uint256, uint256) { + if (!supportsPausedState) revert(); + + return (pauseState.paused, pauseState.pauseWindowEndTime, pauseState.bufferPeriodEndTime); + } + + function paused() external view returns (bool) { + if (!supportsPaused) revert(); + + return pauseState.paused; + } + function inRecoveryMode() external view returns (bool) { if (!supportsRecoveryMode) revert(); @@ -41,4 +67,24 @@ contract BalancerWeightedPoolStub is IBasePool, IWeightedPool { function stubSetRecoveryModeSupported(bool supported) external { supportsRecoveryMode = supported; } + + function stubSetPausedStateSupported(bool supported) external { + supportsPausedState = supported; + } + + function stubSetPausedSupported(bool supported) external { + supportsPaused = supported; + } + + function stubSetPausedState(bool _paused, uint256 pauseWindowEndTime, uint256 bufferPeriodEndTime) external { + pauseState.paused = _paused; + pauseState.pauseWindowEndTime = pauseWindowEndTime; + pauseState.bufferPeriodEndTime = bufferPeriodEndTime; + } + + function stubSetPaused(bool _paused) external { + pauseState.paused = _paused; + pauseState.pauseWindowEndTime = type(uint256).max; + pauseState.bufferPeriodEndTime = type(uint256).max; + } } diff --git a/test/liquidity-accumulator/balancer-liquidity-accumulator.js b/test/liquidity-accumulator/balancer-liquidity-accumulator.js index 08ac468..5cd27b9 100644 --- a/test/liquidity-accumulator/balancer-liquidity-accumulator.js +++ b/test/liquidity-accumulator/balancer-liquidity-accumulator.js @@ -314,8 +314,21 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pause states", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -330,12 +343,25 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool paused (with pause states)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the pool paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); }); @@ -397,8 +423,21 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pause states", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -413,21 +452,47 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return false when the linear pool is in recovery mode", async function () { - await linearPool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the linear pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await linearPool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await linearPool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the linear pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await linearPool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); }); @@ -489,8 +554,21 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pause states", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -505,21 +583,47 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the linear pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await linearPool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return false when the linear pool is in recovery mode", async function () { - await linearPool.stubSetRecoveryMode(true); + it("Should return false when the linear pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await linearPool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await linearPool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); }); @@ -707,8 +811,35 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(liquidity[1]).to.equal(usdcWholeTokenLiquidity); }); - it("Doesn't revert if the pool doesn't support recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Doesn't revert if the pool doesn't support pause states", async function () { + await pool.stubSetPausedStateSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + await vault.stubSetBalance(poolId, WETH, wethLiquidity); + await vault.stubSetBalance(poolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if the pool doesn't support simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + await vault.stubSetBalance(poolId, WETH, wethLiquidity); + await vault.stubSetBalance(poolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if the pool doesn't support any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); const wethWholeTokenLiquidity = 1000; const usdcWholeTokenLiquidity = 1000; @@ -1051,18 +1182,63 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(liquidity[1]).to.equal(usdcWholeTokenLiquidity); }); - it("Should revert if the linear pool is in recovery mode", async function () { - await linearPool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if the linear pool is paused (with pause state)", async function () { + await linearPool.stubSetPausedSupported(false); + + await linearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); + }); + + it("Should revert if the linear pool is paused (with simple pausing)", async function () { + await linearPool.stubSetPausedStateSupported(false); + + await linearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Should revert if the token is not in the pool", async function () { await expect(accumulator.stubFetchLiquidity(BAL)).to.be.revertedWith("TokenNotFound"); }); - it("Doesn't revert if none of the pools support recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); - await linearPool.stubSetRecoveryModeSupported(false); + it("Doesn't revert if none of the pools support paused states", async function () { + await pool.stubSetPausedStateSupported(false); + await linearPool.stubSetPausedStateSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + + const wethLinearPoolId = await linearPool.getPoolId(); + + await vault.stubSetBalance(wethLinearPoolId, WETH, wethLiquidity); + await vault.stubSetBalance(poolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if none of the pools support simple pausing", async function () { + await pool.stubSetPausedSupported(false); + await linearPool.stubSetPausedSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + + const wethLinearPoolId = await linearPool.getPoolId(); + + await vault.stubSetBalance(wethLinearPoolId, WETH, wethLiquidity); + await vault.stubSetBalance(poolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if none of the pools support any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await linearPool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); + await linearPool.stubSetPausedSupported(false); const wethWholeTokenLiquidity = 1000; const usdcWholeTokenLiquidity = 1000; @@ -1261,18 +1437,63 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(liquidity[1]).to.equal(usdcWholeTokenLiquidity); }); - it("Should revert if the linear pool is in recovery mode", async function () { - await linearPool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if the linear pool is paused (with pause state)", async function () { + await linearPool.stubSetPausedSupported(false); + + await linearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); + }); + + it("Should revert if the linear pool is paused (with simple pausing)", async function () { + await linearPool.stubSetPausedStateSupported(false); + + await linearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Should revert if the token is not in the pool", async function () { await expect(accumulator.stubFetchLiquidity(BAL)).to.be.revertedWith("TokenNotFound"); }); - it("Doesn't revert if none of the pools support recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); - await linearPool.stubSetRecoveryModeSupported(false); + it("Doesn't revert if none of the pools support paused states", async function () { + await pool.stubSetPausedStateSupported(false); + await linearPool.stubSetPausedStateSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + + const usdcLinearPoolId = await linearPool.getPoolId(); + + await vault.stubSetBalance(poolId, WETH, wethLiquidity); + await vault.stubSetBalance(usdcLinearPoolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if none of the pools support simple pausing", async function () { + await pool.stubSetPausedSupported(false); + await linearPool.stubSetPausedSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + + const usdcLinearPoolId = await linearPool.getPoolId(); + + await vault.stubSetBalance(poolId, WETH, wethLiquidity); + await vault.stubSetBalance(usdcLinearPoolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if none of the pools support any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await linearPool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); + await linearPool.stubSetPausedSupported(false); const wethWholeTokenLiquidity = 1000; const usdcWholeTokenLiquidity = 1000; @@ -1496,30 +1717,101 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate expect(liquidity[1]).to.equal(usdcWholeTokenLiquidity); }); - it("Should revert if the token linear pool is in recovery mode", async function () { - await wethLinearPool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if the token linear pool is paused (with pause state)", async function () { + await wethLinearPool.stubSetPausedStateSupported(false); + + await wethLinearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); + }); + + it("Should revert if the quote token linear pool is paused (with pause state)", async function () { + await usdcLinearPool.stubSetPausedStateSupported(false); + + await usdcLinearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); }); - it("Should revert if the quote token linear pool is in recovery mode", async function () { - await usdcLinearPool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if all of the linear pools are paused (with pause state)", async function () { + await wethLinearPool.stubSetPausedStateSupported(false); + await usdcLinearPool.stubSetPausedStateSupported(false); + + await wethLinearPool.stubSetPaused(true); + await usdcLinearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); }); - it("Should revert if all of the linear pools are in recovery mode", async function () { - await wethLinearPool.stubSetRecoveryMode(true); - await usdcLinearPool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if the token linear pool is paused (with simple pausing)", async function () { + await wethLinearPool.stubSetPausedStateSupported(false); + + await wethLinearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); + }); + + it("Should revert if the quote token linear pool is paused (with simple pausing)", async function () { + await usdcLinearPool.stubSetPausedStateSupported(false); + + await usdcLinearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); + }); + + it("Should revert if all of the linear pools are paused (with simple pausing)", async function () { + await wethLinearPool.stubSetPausedStateSupported(false); + await usdcLinearPool.stubSetPausedStateSupported(false); + + await wethLinearPool.stubSetPaused(true); + await usdcLinearPool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Should revert if the token is not in the pool", async function () { await expect(accumulator.stubFetchLiquidity(BAL)).to.be.revertedWith("TokenNotFound"); }); - it("Doesn't revert if none of the pools support recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); - await wethLinearPool.stubSetRecoveryModeSupported(false); - await usdcLinearPool.stubSetRecoveryModeSupported(false); + it("Doesn't revert if none of the pools support pause states", async function () { + await pool.stubSetPausedStateSupported(false); + await wethLinearPool.stubSetPausedStateSupported(false); + await usdcLinearPool.stubSetPausedStateSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + + const wethLinearPoolId = await wethLinearPool.getPoolId(); + const usdcLinearPoolId = await usdcLinearPool.getPoolId(); + + await vault.stubSetBalance(wethLinearPoolId, WETH, wethLiquidity); + await vault.stubSetBalance(usdcLinearPoolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if none of the pools support simple pausing", async function () { + await pool.stubSetPausedSupported(false); + await wethLinearPool.stubSetPausedSupported(false); + await usdcLinearPool.stubSetPausedSupported(false); + + const wethWholeTokenLiquidity = 1000; + const usdcWholeTokenLiquidity = 1000; + const wethLiquidity = ethers.utils.parseUnits(wethWholeTokenLiquidity.toString(), 18); + const usdcLiquidity = ethers.utils.parseUnits(usdcWholeTokenLiquidity.toString(), 6); + + const wethLinearPoolId = await wethLinearPool.getPoolId(); + const usdcLinearPoolId = await usdcLinearPool.getPoolId(); + + await vault.stubSetBalance(wethLinearPoolId, WETH, wethLiquidity); + await vault.stubSetBalance(usdcLinearPoolId, USDC, usdcLiquidity); + + await expect(accumulator.stubFetchLiquidity(WETH)).to.not.be.reverted; + }); + + it("Doesn't revert if none of the pools support any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await wethLinearPool.stubSetPausedStateSupported(false); + await usdcLinearPool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); + await wethLinearPool.stubSetPausedSupported(false); + await usdcLinearPool.stubSetPausedSupported(false); const wethWholeTokenLiquidity = 1000; const usdcWholeTokenLiquidity = 1000; @@ -2287,9 +2579,9 @@ function describeBalancerLiquidityAccumulatorTests(contractName, averagingStrate }); }); - it("Should revert if the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if the pool is paused", async function () { + await pool.stubSetPaused(true); + await expect(accumulator.stubFetchLiquidity(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Should revert if the token is not in the pool", async function () { diff --git a/test/price-accumulator/balancer-stable-price-accumulator.js b/test/price-accumulator/balancer-stable-price-accumulator.js index 00b0bf0..7d5c9ae 100644 --- a/test/price-accumulator/balancer-stable-price-accumulator.js +++ b/test/price-accumulator/balancer-stable-price-accumulator.js @@ -367,8 +367,21 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pause state", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -383,12 +396,25 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -465,8 +491,21 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pausing (with pause state)", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting pausing (with simple pausing)", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting pausing (with any pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -481,21 +520,47 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return false when the linear pool is in recovery mode", async function () { - await linearPool.stubSetRecoveryMode(true); + it("Should return false when the linear pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await linearPool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await linearPool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the linear pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await linearPool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); }); @@ -556,8 +621,21 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pause state", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -572,21 +650,47 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the linear pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await linearPool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return false when the linear pool is in recovery mode", async function () { - await linearPool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the linear pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await linearPool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await linearPool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await linearPool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); }); @@ -937,10 +1041,10 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra expectEqualsWithTolerance(price, expectedPrice, PRECISION_FACTOR); }); - it("Reverts if the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Reverts if the pool is paused", async function () { + await pool.stubSetPaused(true); - await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Reverts if the token balance is zero", async function () { @@ -1043,19 +1147,21 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra await expect(accumulator.stubFetchPrice(BAL)).to.be.revertedWith("TokenNotFound"); }); - it("Doesn't revert if none of the pools supports recovery mode", async function () { + it("Doesn't revert if none of the pools supports pausing", async function () { const wethBalance = ethers.utils.parseUnits("1000.0", 18); const usdcBalance = ethers.utils.parseUnits("1000.0", 6); await vault.stubSetBalance(wethPoolId, WETH, wethBalance); await vault.stubSetBalance(usdcPoolId, USDC, usdcBalance); - await pool.stubSetRecoveryModeSupported(false); + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); if (wethLinearPool !== undefined) { const linearPoolId = await wethLinearPool.getPoolId(); - await wethLinearPool.stubSetRecoveryModeSupported(false); + await wethLinearPool.stubSetPausedStateSupported(false); + await wethLinearPool.stubSetPausedSupported(false); await wethLinearPool.stubSetRate(wethLinearPoolRate); await vault.stubSetBalance(linearPoolId, WETH, wethBalance); @@ -1064,7 +1170,8 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra if (usdcLinearPool !== undefined) { const linearPoolId = await usdcLinearPool.getPoolId(); - await usdcLinearPool.stubSetRecoveryModeSupported(false); + await usdcLinearPool.stubSetPausedStateSupported(false); + await usdcLinearPool.stubSetPausedSupported(false); await usdcLinearPool.stubSetRate(usdcLinearPoolRate); await vault.stubSetBalance(linearPoolId, USDC, usdcBalance); @@ -1257,7 +1364,7 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra describeCommonTests(); - it("Reverts if the token linear pool is in recovery mode", async function () { + it("Reverts if the token linear pool is paused", async function () { const wethBalance = ethers.utils.parseUnits("1000.0", 18); const usdcBalance = ethers.utils.parseUnits("1000.0", 6); @@ -1286,9 +1393,9 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra await pool.stubSetAmplificationParameter(DEFAULT_AMPLIFICATION, false); - await wethLinearPool.stubSetRecoveryMode(true); + await wethLinearPool.stubSetPaused(true); - await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolIsPaused"); }); }); @@ -1423,7 +1530,7 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra describeCommonTests(); - it("Reverts if the quote token linear pool is in recovery mode", async function () { + it("Reverts if the quote token linear pool is paused", async function () { const wethBalance = ethers.utils.parseUnits("1000.0", 18); const usdcBalance = ethers.utils.parseUnits("1000.0", 6); @@ -1452,9 +1559,9 @@ function describeBalancerStablePriceAccumulatorTests(contractName, averagingStra await pool.stubSetAmplificationParameter(DEFAULT_AMPLIFICATION, false); - await usdcLinearPool.stubSetRecoveryMode(true); + await usdcLinearPool.stubSetPaused(true); - await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Should return 1 if the quote token linear pool's rate is 0", async function () { diff --git a/test/price-accumulator/balancer-weighted-price-accumulator.js b/test/price-accumulator/balancer-weighted-price-accumulator.js index 1db151d..ff84724 100644 --- a/test/price-accumulator/balancer-weighted-price-accumulator.js +++ b/test/price-accumulator/balancer-weighted-price-accumulator.js @@ -128,8 +128,21 @@ function describeBalancerWeightedPriceAccumulatorTests(contractName, averagingSt expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); - it("Should return true when given a token that's in the pool, with the pool not supporting recovery mode", async function () { - await pool.stubSetRecoveryModeSupported(false); + it("Should return true when given a token that's in the pool, with the pool not supporting pause state", async function () { + await pool.stubSetPausedStateSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting simple pausing", async function () { + await pool.stubSetPausedSupported(false); + + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return true when given a token that's in the pool, with the pool not supporting any pausing", async function () { + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -144,12 +157,25 @@ function describeBalancerWeightedPriceAccumulatorTests(contractName, averagingSt expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(USDC, 32))).to.equal(false); }); - it("Should return false when the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); + it("Should return false when the pool is paused (with pause state)", async function () { + await pool.stubSetPausedSupported(false); + + await pool.stubSetPaused(true); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); + + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); + expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); + }); + + it("Should return false when the pool is paused (with simple pausing)", async function () { + await pool.stubSetPausedStateSupported(false); + + await pool.stubSetPaused(true); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(false); - // Sanity check: Returns true when recovery mode is off - await pool.stubSetRecoveryMode(false); + // Sanity check: Returns true when not paused + await pool.stubSetPaused(false); expect(await accumulator.canUpdate(ethers.utils.hexZeroPad(WETH, 32))).to.equal(true); }); @@ -791,9 +817,9 @@ function describeBalancerWeightedPriceAccumulatorTests(contractName, averagingSt }); }); - it("Should revert if the pool is in recovery mode", async function () { - await pool.stubSetRecoveryMode(true); - await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolInRecoveryMode"); + it("Should revert if the pool is paused", async function () { + await pool.stubSetPaused(true); + await expect(accumulator.stubFetchPrice(WETH)).to.be.revertedWith("PoolIsPaused"); }); it("Should revert if the token balance is zero", async function () { @@ -811,11 +837,12 @@ function describeBalancerWeightedPriceAccumulatorTests(contractName, averagingSt await expect(accumulator.stubFetchPrice(BAL)).to.be.revertedWith("TokenNotFound"); }); - it("Doesn't revert if the pool doesn't support recovery mode", async function () { + it("Doesn't revert if the pool doesn't support pausing", async function () { await vault.stubSetBalance(poolId, WETH, ethers.utils.parseUnits("1000.0", 18)); await vault.stubSetBalance(poolId, USDC, ethers.utils.parseUnits("1000.0", 6)); - await pool.stubSetRecoveryModeSupported(false); + await pool.stubSetPausedStateSupported(false); + await pool.stubSetPausedSupported(false); await expect(accumulator.stubFetchPrice(WETH)).to.not.be.reverted; }); From ecd911801686fc6f62317e2475a4dd953aafc757 Mon Sep 17 00:00:00 2001 From: Tyler Loewen Date: Tue, 4 Jul 2023 15:26:26 -0700 Subject: [PATCH 3/3] Update version to v4.0.0-beta.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b29750..cab3981 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@adrastia-oracle/adrastia-core", - "version": "4.0.0-beta.6", + "version": "4.0.0-beta.7", "main": "index.js", "author": "TRILEZ SOFTWARE INC.", "license": "MIT",