From 2c9846f5ab275a7fa8830bef1e3bd68758bc2bed Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Thu, 16 Nov 2023 09:06:08 +0530 Subject: [PATCH 01/19] overriden getSwapFeePercent --- .../contracts/BaseWeightedPool.sol | 8 +-- .../contracts/CustomFeeAuthorizer.sol | 40 +++++++++++++++ pkg/pool-weighted/contracts/WeightedPool.sol | 51 ++++++++++++++++++- pkg/pool-weighted/hardhat.config.ts | 13 ++++- .../lbp/LiquidityBootstrappingPool.sol | 0 .../lbp/LiquidityBootstrappingPoolFactory.sol | 0 .../LiquidityBootstrappingPoolSettings.sol | 0 .../LiquidityBootstrappingPoolStorageLib.sol | 0 .../managed/CircuitBreakerStorageLib.sol | 0 .../{contracts => }/managed/ManagedPool.sol | 0 .../managed/ManagedPoolAddRemoveTokenLib.sol | 0 .../managed/ManagedPoolAmmLib.sol | 0 .../managed/ManagedPoolAumStorageLib.sol | 0 .../managed/ManagedPoolFactory.sol | 0 .../managed/ManagedPoolSettings.sol | 0 .../managed/ManagedPoolStorageLib.sol | 0 .../managed/ManagedPoolTokenStorageLib.sol | 0 .../{contracts => }/managed/README.md | 0 .../test => test1}/MockCircuitBreakerLib.sol | 0 .../test => test1}/MockGradualValueChange.sol | 0 ...ckLiquidityBootstrappingPoolStorageLib.sol | 0 .../test => test1}/MockManagedPool.sol | 0 .../MockManagedPoolSettings.sol | 0 .../MockManagedPoolTokenStorageLib.sol | 0 .../test => test1}/MockValueCompression.sol | 0 .../test => test1}/MockWeightedPool.sol | 0 .../MockWeightedPoolProtocolFees.sol | 0 .../MockWithdrawDepositAssetManager.sol | 0 28 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol rename pkg/pool-weighted/{contracts => }/lbp/LiquidityBootstrappingPool.sol (100%) rename pkg/pool-weighted/{contracts => }/lbp/LiquidityBootstrappingPoolFactory.sol (100%) rename pkg/pool-weighted/{contracts => }/lbp/LiquidityBootstrappingPoolSettings.sol (100%) rename pkg/pool-weighted/{contracts => }/lbp/LiquidityBootstrappingPoolStorageLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/CircuitBreakerStorageLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPool.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolAddRemoveTokenLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolAmmLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolAumStorageLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolFactory.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolSettings.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolStorageLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/ManagedPoolTokenStorageLib.sol (100%) rename pkg/pool-weighted/{contracts => }/managed/README.md (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockCircuitBreakerLib.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockGradualValueChange.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockLiquidityBootstrappingPoolStorageLib.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockManagedPool.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockManagedPoolSettings.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockManagedPoolTokenStorageLib.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockValueCompression.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockWeightedPool.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockWeightedPoolProtocolFees.sol (100%) rename pkg/pool-weighted/{contracts/test => test1}/MockWithdrawDepositAssetManager.sol (100%) diff --git a/pkg/pool-weighted/contracts/BaseWeightedPool.sol b/pkg/pool-weighted/contracts/BaseWeightedPool.sol index 718ec756bb..d608def446 100644 --- a/pkg/pool-weighted/contracts/BaseWeightedPool.sol +++ b/pkg/pool-weighted/contracts/BaseWeightedPool.sol @@ -280,7 +280,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights, amountsIn, totalSupply, - getSwapFeePercentage() + getSwapFeePercentage(userData, OperationType.JOIN) ); _require(bptAmountOut >= minBPTAmountOut, Errors.BPT_OUT_MIN_AMOUNT); @@ -304,7 +304,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights[tokenIndex], bptAmountOut, totalSupply, - getSwapFeePercentage() + getSwapFeePercentage(userData, OperationType.JOIN) ); // We join in a single token, so we initialize amountsIn with zeros @@ -407,7 +407,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights[tokenIndex], bptAmountIn, totalSupply, - getSwapFeePercentage() + getSwapFeePercentage(userData, OperationType.EXIT) ); // This is an exceptional situation in which the fee is charged on a token out instead of a token in. @@ -448,7 +448,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights, amountsOut, totalSupply, - getSwapFeePercentage() + getSwapFeePercentage(userData, OperationType.EXIT) ); _require(bptAmountIn <= maxBPTAmountIn, Errors.BPT_IN_MAX_AMOUNT); diff --git a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol new file mode 100644 index 0000000000..031f1eb3b1 --- /dev/null +++ b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.0; + +import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/Ownable.sol"; + +contract CustomFeeAuthorizer is Ownable { + event authorizorAdded(address indexed _authorizor); + event authorizorRemoved(address indexed _authorizor); + + mapping(address => bool) private authorized; + bool public isCustomFeeEnabled = false; + + function isCustomFeeAuthorised(address _authAdd) public view returns(bool _isAuth){ + if(isCustomFeeEnabled){ + _isAuth = (authorized[_authAdd] || owner() == _authAdd) ; + }else{ + _isAuth = false; + } + } + + function addAuthorized(address _toAdd) onlyOwner public { + require(_toAdd != address(0)); + require(isCustomFeeEnabled,"Custom Fee Not Enabled"); + authorized[_toAdd] = true; + emit authorizorAdded(_toAdd); + } + + function removeAuthorized(address _toRemove) onlyOwner public { + require(_toRemove != msg.sender); + authorized[_toRemove] = false; + emit authorizorRemoved(_toRemove); + } + + function enableCustomFee() onlyOwner() internal { + require(!isCustomFeeEnabled, "Already Enabled"); + isCustomFeeEnabled = true; + } + + +} \ No newline at end of file diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index efa78788f6..016bcbd5a4 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -17,12 +17,14 @@ pragma experimental ABIEncoderV2; import "./BaseWeightedPool.sol"; import "./WeightedPoolProtocolFees.sol"; +import "./CustomFeeAuthorizer.sol"; /** * @dev Basic Weighted Pool with immutable weights. */ -contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees { +contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees,CustomFeeAuthorizer { using FixedPoint for uint256; + using WeightedPoolUserData for bytes; uint256 private constant _MAX_TOKENS = 8; @@ -401,4 +403,51 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees { { return super._isOwnerOnlyAction(actionId); } + + function getSwapFeePercentage(bytes memory userData, + OperationType _operation) public view virtual override returns (uint256 _fee) { + // using tx.origin insted of msg.sender as these functions are called + // during join/exit/swap via vault + if(isCustomFeeEnabled && isCustomFeeAuthorised(tx.origin)){ + if(_operation == OperationType.JOIN ){ + WeightedPoolUserData.JoinKind kind = userData.joinKind(); + if(kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT){ + _fee = userData.exactTokensInForBptOutCustomFee(); + } else { + if(kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT){ + _fee = userData.tokenInForExactBptOutCustomFee(); + } + } + }else{ + if(_operation == OperationType.EXIT){ + WeightedPoolUserData.ExitKind kind = userData.exitKind(); + if(kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT){ + _fee = userData.exactBptInForTokenOutCustomFee(); + } else { + if(kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT){ + _fee = userData.bptInForExactTokensOutCustomFee(); + } + } + } else{ + if(_operation == OperationType.SWAP){ + _fee = userData.swapCustomFee(); + } + } + } + }else{ + // return _miscData.decodeUint(_SWAP_FEE_PERCENTAGE_OFFSET, _SWAP_FEE_PERCENTAGE_BIT_LENGTH); + _fee = super.getSwapFeePercentage(hex"00", OperationType.NONE); + } + } + + function setSwapFeePercentage(uint256 swapFeePercentage) public virtual override whenNotPaused { + // here msg.sender is used as this function directlly be called by the admin + // not via any other contract + if(isCustomFeeEnabled && owner() == msg.sender){ + _setSwapFeePercentage(swapFeePercentage); + }else { + super.setSwapFeePercentage(swapFeePercentage); + } + } + // used if else so that it should not break the existing flow } diff --git a/pkg/pool-weighted/hardhat.config.ts b/pkg/pool-weighted/hardhat.config.ts index b6cb857258..78a37c9ff7 100644 --- a/pkg/pool-weighted/hardhat.config.ts +++ b/pkg/pool-weighted/hardhat.config.ts @@ -18,7 +18,18 @@ export default { }, }, solidity: { - compilers: hardhatBaseConfig.compilers, + // compilers: hardhatBaseConfig.compilers, + compilers: [ + { + version: '0.7.1', + settings: { + optimizer: { + enabled: true, + runs: 10, + }, + }, + }, + ], overrides: { ...hardhatBaseConfig.overrides(name) }, }, warnings: hardhatBaseConfig.warnings, diff --git a/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPool.sol b/pkg/pool-weighted/lbp/LiquidityBootstrappingPool.sol similarity index 100% rename from pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPool.sol rename to pkg/pool-weighted/lbp/LiquidityBootstrappingPool.sol diff --git a/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolFactory.sol b/pkg/pool-weighted/lbp/LiquidityBootstrappingPoolFactory.sol similarity index 100% rename from pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolFactory.sol rename to pkg/pool-weighted/lbp/LiquidityBootstrappingPoolFactory.sol diff --git a/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolSettings.sol b/pkg/pool-weighted/lbp/LiquidityBootstrappingPoolSettings.sol similarity index 100% rename from pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolSettings.sol rename to pkg/pool-weighted/lbp/LiquidityBootstrappingPoolSettings.sol diff --git a/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolStorageLib.sol b/pkg/pool-weighted/lbp/LiquidityBootstrappingPoolStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolStorageLib.sol rename to pkg/pool-weighted/lbp/LiquidityBootstrappingPoolStorageLib.sol diff --git a/pkg/pool-weighted/contracts/managed/CircuitBreakerStorageLib.sol b/pkg/pool-weighted/managed/CircuitBreakerStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/CircuitBreakerStorageLib.sol rename to pkg/pool-weighted/managed/CircuitBreakerStorageLib.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPool.sol b/pkg/pool-weighted/managed/ManagedPool.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPool.sol rename to pkg/pool-weighted/managed/ManagedPool.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolAddRemoveTokenLib.sol b/pkg/pool-weighted/managed/ManagedPoolAddRemoveTokenLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolAddRemoveTokenLib.sol rename to pkg/pool-weighted/managed/ManagedPoolAddRemoveTokenLib.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolAmmLib.sol b/pkg/pool-weighted/managed/ManagedPoolAmmLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolAmmLib.sol rename to pkg/pool-weighted/managed/ManagedPoolAmmLib.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolAumStorageLib.sol b/pkg/pool-weighted/managed/ManagedPoolAumStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolAumStorageLib.sol rename to pkg/pool-weighted/managed/ManagedPoolAumStorageLib.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol b/pkg/pool-weighted/managed/ManagedPoolFactory.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol rename to pkg/pool-weighted/managed/ManagedPoolFactory.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolSettings.sol b/pkg/pool-weighted/managed/ManagedPoolSettings.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolSettings.sol rename to pkg/pool-weighted/managed/ManagedPoolSettings.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolStorageLib.sol b/pkg/pool-weighted/managed/ManagedPoolStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolStorageLib.sol rename to pkg/pool-weighted/managed/ManagedPoolStorageLib.sol diff --git a/pkg/pool-weighted/contracts/managed/ManagedPoolTokenStorageLib.sol b/pkg/pool-weighted/managed/ManagedPoolTokenStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/managed/ManagedPoolTokenStorageLib.sol rename to pkg/pool-weighted/managed/ManagedPoolTokenStorageLib.sol diff --git a/pkg/pool-weighted/contracts/managed/README.md b/pkg/pool-weighted/managed/README.md similarity index 100% rename from pkg/pool-weighted/contracts/managed/README.md rename to pkg/pool-weighted/managed/README.md diff --git a/pkg/pool-weighted/contracts/test/MockCircuitBreakerLib.sol b/pkg/pool-weighted/test1/MockCircuitBreakerLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockCircuitBreakerLib.sol rename to pkg/pool-weighted/test1/MockCircuitBreakerLib.sol diff --git a/pkg/pool-weighted/contracts/test/MockGradualValueChange.sol b/pkg/pool-weighted/test1/MockGradualValueChange.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockGradualValueChange.sol rename to pkg/pool-weighted/test1/MockGradualValueChange.sol diff --git a/pkg/pool-weighted/contracts/test/MockLiquidityBootstrappingPoolStorageLib.sol b/pkg/pool-weighted/test1/MockLiquidityBootstrappingPoolStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockLiquidityBootstrappingPoolStorageLib.sol rename to pkg/pool-weighted/test1/MockLiquidityBootstrappingPoolStorageLib.sol diff --git a/pkg/pool-weighted/contracts/test/MockManagedPool.sol b/pkg/pool-weighted/test1/MockManagedPool.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockManagedPool.sol rename to pkg/pool-weighted/test1/MockManagedPool.sol diff --git a/pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol b/pkg/pool-weighted/test1/MockManagedPoolSettings.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol rename to pkg/pool-weighted/test1/MockManagedPoolSettings.sol diff --git a/pkg/pool-weighted/contracts/test/MockManagedPoolTokenStorageLib.sol b/pkg/pool-weighted/test1/MockManagedPoolTokenStorageLib.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockManagedPoolTokenStorageLib.sol rename to pkg/pool-weighted/test1/MockManagedPoolTokenStorageLib.sol diff --git a/pkg/pool-weighted/contracts/test/MockValueCompression.sol b/pkg/pool-weighted/test1/MockValueCompression.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockValueCompression.sol rename to pkg/pool-weighted/test1/MockValueCompression.sol diff --git a/pkg/pool-weighted/contracts/test/MockWeightedPool.sol b/pkg/pool-weighted/test1/MockWeightedPool.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockWeightedPool.sol rename to pkg/pool-weighted/test1/MockWeightedPool.sol diff --git a/pkg/pool-weighted/contracts/test/MockWeightedPoolProtocolFees.sol b/pkg/pool-weighted/test1/MockWeightedPoolProtocolFees.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockWeightedPoolProtocolFees.sol rename to pkg/pool-weighted/test1/MockWeightedPoolProtocolFees.sol diff --git a/pkg/pool-weighted/contracts/test/MockWithdrawDepositAssetManager.sol b/pkg/pool-weighted/test1/MockWithdrawDepositAssetManager.sol similarity index 100% rename from pkg/pool-weighted/contracts/test/MockWithdrawDepositAssetManager.sol rename to pkg/pool-weighted/test1/MockWithdrawDepositAssetManager.sol From 0e848c4dbdd9fe34f6f4a85d503652216d5715c6 Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Thu, 16 Nov 2023 09:08:34 +0530 Subject: [PATCH 02/19] module changes --- .../pool-weighted/WeightedPoolUserData.sol | 33 +++++++++++++++++++ pkg/interfaces/contracts/vault/IBasePool.sol | 5 ++- .../contracts/BaseMinimalSwapInfoPool.sol | 4 +-- pkg/pool-utils/contracts/BasePool.sol | 17 +++++++--- 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol b/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol index e192e5a7c1..3d057aba77 100644 --- a/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol +++ b/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol @@ -68,4 +68,37 @@ library WeightedPoolUserData { { (, amountsOut, maxBPTAmountIn) = abi.decode(self, (ExitKind, uint256[], uint256)); } + + // function related to custom fee + function tokenInForExactBptOutCustomFee(bytes memory self) internal pure returns (uint256 customFee) { + (, , , customFee) = abi.decode(self, (JoinKind, uint256, uint256, uint256)); + } + + function exactTokensInForBptOutCustomFee(bytes memory self) + internal + pure + returns (uint256 customFee) + { + (, , , customFee) = abi.decode(self, (JoinKind, uint256[], uint256, uint256)); + } + + function exactBptInForTokenOutCustomFee(bytes memory self) internal pure returns (uint256 customFee) { + (, , , customFee) = abi.decode(self, (ExitKind, uint256, uint256, uint256)); + } + + function bptInForExactTokensOutCustomFee(bytes memory self) + internal + pure + returns (uint256 customFee) + { + (, , , customFee) = abi.decode(self, (ExitKind, uint256[], uint256, uint256)); + } + + function swapCustomFee(bytes memory self) + internal + pure + returns (uint256 customFee) + { + (customFee) = abi.decode(self, (uint256)); + } } diff --git a/pkg/interfaces/contracts/vault/IBasePool.sol b/pkg/interfaces/contracts/vault/IBasePool.sol index 4411e51d10..588b6f7a61 100644 --- a/pkg/interfaces/contracts/vault/IBasePool.sol +++ b/pkg/interfaces/contracts/vault/IBasePool.sol @@ -45,6 +45,9 @@ interface IBasePool is IPoolSwapStructs { * Contracts implementing this function should check that the caller is indeed the Vault before performing any * state-changing operations, such as minting pool shares. */ + // enum for transaction type + enum OperationType { JOIN, EXIT, SWAP, NONE } + function onJoinPool( bytes32 poolId, address sender, @@ -96,7 +99,7 @@ interface IBasePool is IPoolSwapStructs { * @dev Returns the current swap fee percentage as a 18 decimal fixed point number, so e.g. 1e17 corresponds to a * 10% swap fee. */ - function getSwapFeePercentage() external view returns (uint256); + function getSwapFeePercentage(bytes memory userData, OperationType _operation) external view returns (uint256); /** * @dev Returns the scaling factors of each of the Pool's tokens. This is an implementation detail that is typically diff --git a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol index 7828e5eae0..3c178015c5 100644 --- a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol +++ b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol @@ -44,7 +44,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { if (request.kind == IVault.SwapKind.GIVEN_IN) { // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis. - request.amount = _subtractSwapFeeAmount(request.amount); + request.amount = _subtractSwapFeeAmount(request.amount, request.userData); // All token amounts are upscaled. request.amount = _upscale(request.amount, scalingFactorTokenIn); @@ -63,7 +63,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { amountIn = _downscaleUp(amountIn, scalingFactorTokenIn); // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis. - return _addSwapFeeAmount(amountIn); + return _addSwapFeeAmount(amountIn, request.userData); } } diff --git a/pkg/pool-utils/contracts/BasePool.sol b/pkg/pool-utils/contracts/BasePool.sol index 58f57d0ce2..db8bd434e5 100644 --- a/pkg/pool-utils/contracts/BasePool.sol +++ b/pkg/pool-utils/contracts/BasePool.sol @@ -169,7 +169,14 @@ abstract contract BasePool is * @notice Return the current value of the swap fee percentage. * @dev This is stored in `_miscData`. */ - function getSwapFeePercentage() public view virtual override returns (uint256) { + function getSwapFeePercentage(bytes memory userData, + OperationType _operation) public view virtual override returns (uint256) { + // this code is just to avoid un-used variable warning. + // this will have no impact on the execution + // will remove this code in future + if(_operation == OperationType.SWAP){ + userData = hex"00"; + } return _miscData.decodeUint(_SWAP_FEE_PERCENTAGE_OFFSET, _SWAP_FEE_PERCENTAGE_BIT_LENGTH); } @@ -592,17 +599,17 @@ abstract contract BasePool is /** * @dev Adds swap fee amount to `amount`, returning a higher value. */ - function _addSwapFeeAmount(uint256 amount) internal view returns (uint256) { + function _addSwapFeeAmount(uint256 amount, bytes memory userData) internal view returns (uint256) { // This returns amount + fee amount, so we round up (favoring a higher fee amount). - return amount.divUp(getSwapFeePercentage().complement()); + return amount.divUp(getSwapFeePercentage(userData, OperationType.SWAP).complement()); } /** * @dev Subtracts swap fee amount from `amount`, returning a lower value. */ - function _subtractSwapFeeAmount(uint256 amount) internal view returns (uint256) { + function _subtractSwapFeeAmount(uint256 amount, bytes memory userData) internal view returns (uint256) { // This returns amount - fee amount, so we round up (favoring a higher fee amount). - uint256 feeAmount = amount.mulUp(getSwapFeePercentage()); + uint256 feeAmount = amount.mulUp(getSwapFeePercentage(userData, OperationType.SWAP)); return amount.sub(feeAmount); } From 6c37f0d6f0c6296aad5d873b16f1262a339e3979 Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Mon, 20 Nov 2023 22:33:48 +0530 Subject: [PATCH 03/19] emit event SwapFeePercentageChanged --- .../contracts/BaseWeightedPool.sol | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pkg/pool-weighted/contracts/BaseWeightedPool.sol b/pkg/pool-weighted/contracts/BaseWeightedPool.sol index d608def446..19bd96d1b8 100644 --- a/pkg/pool-weighted/contracts/BaseWeightedPool.sol +++ b/pkg/pool-weighted/contracts/BaseWeightedPool.sol @@ -225,6 +225,15 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { userData ); + // _doJoin performs actions specific to type of join + // but it's a view function so can not emit event + + WeightedPoolUserData.JoinKind kind = userData.joinKind(); + if(kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT || + kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT){ + emit SwapFeePercentageChanged(getSwapFeePercentage(userData, OperationType.JOIN)); + } + _afterJoinExit( preJoinExitInvariant, balances, @@ -353,6 +362,15 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { userData ); + // _doExit performs actions specific to type of exit + // but it's a view function so can not emit event + + WeightedPoolUserData.ExitKind kind = userData.exitKind(); + if(kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT || + kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT){ + emit SwapFeePercentageChanged(getSwapFeePercentage(userData, OperationType.EXIT)); + } + _afterJoinExit( preJoinExitInvariant, balances, From 8ad43186aec3d82db368916b3b9df787ed7d4359 Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Mon, 20 Nov 2023 22:34:16 +0530 Subject: [PATCH 04/19] emit event SwapFeePercentageChanged in swap --- pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol index 3c178015c5..2b20cd735b 100644 --- a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol +++ b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol @@ -46,6 +46,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis. request.amount = _subtractSwapFeeAmount(request.amount, request.userData); + emit SwapFeePercentageChanged(getSwapFeePercentage(request.userData, OperationType.SWAP)); // All token amounts are upscaled. request.amount = _upscale(request.amount, scalingFactorTokenIn); @@ -63,6 +64,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { amountIn = _downscaleUp(amountIn, scalingFactorTokenIn); // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis. + emit SwapFeePercentageChanged(getSwapFeePercentage(request.userData, OperationType.SWAP)); return _addSwapFeeAmount(amountIn, request.userData); } } From bac31ed45037e834e32050510899e1eecb68a72f Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Wed, 29 Nov 2023 22:50:48 +0530 Subject: [PATCH 05/19] resolving conversation --- .../contracts/CustomFeeAuthorizer.sol | 40 ++++++++++++------- pkg/pool-weighted/contracts/WeightedPool.sol | 7 ++-- .../lbp/LiquidityBootstrappingPool.sol | 0 .../lbp/LiquidityBootstrappingPoolFactory.sol | 0 .../LiquidityBootstrappingPoolSettings.sol | 0 .../LiquidityBootstrappingPoolStorageLib.sol | 0 .../managed/CircuitBreakerStorageLib.sol | 0 .../{ => contracts}/managed/ManagedPool.sol | 0 .../managed/ManagedPoolAddRemoveTokenLib.sol | 0 .../managed/ManagedPoolAmmLib.sol | 0 .../managed/ManagedPoolAumStorageLib.sol | 0 .../managed/ManagedPoolFactory.sol | 0 .../managed/ManagedPoolSettings.sol | 0 .../managed/ManagedPoolStorageLib.sol | 0 .../managed/ManagedPoolTokenStorageLib.sol | 0 .../{ => contracts}/managed/README.md | 0 pkg/pool-weighted/test1/MockWeightedPool.sol | 2 +- 17 files changed, 29 insertions(+), 20 deletions(-) rename pkg/pool-weighted/{ => contracts}/lbp/LiquidityBootstrappingPool.sol (100%) rename pkg/pool-weighted/{ => contracts}/lbp/LiquidityBootstrappingPoolFactory.sol (100%) rename pkg/pool-weighted/{ => contracts}/lbp/LiquidityBootstrappingPoolSettings.sol (100%) rename pkg/pool-weighted/{ => contracts}/lbp/LiquidityBootstrappingPoolStorageLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/CircuitBreakerStorageLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPool.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolAddRemoveTokenLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolAmmLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolAumStorageLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolFactory.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolSettings.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolStorageLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/ManagedPoolTokenStorageLib.sol (100%) rename pkg/pool-weighted/{ => contracts}/managed/README.md (100%) diff --git a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol index 031f1eb3b1..45a5d6b7c7 100644 --- a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol +++ b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol @@ -1,40 +1,50 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.7.0; -import "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/Ownable.sol"; -contract CustomFeeAuthorizer is Ownable { - event authorizorAdded(address indexed _authorizor); - event authorizorRemoved(address indexed _authorizor); +contract CustomFeeAuthorizer { + event feeSetterAdded(address indexed feeSetter); + event feeSetterRemoved(address indexed feeSetter); - mapping(address => bool) private authorized; - bool public isCustomFeeEnabled = false; + mapping(address => bool) private isCustomFeeSetter; + bool public isCustomFeeEnabled = false ; + address public solver; - function isCustomFeeAuthorised(address _authAdd) public view returns(bool _isAuth){ + function canSetCustomFee(address _setterAddress) public view returns(bool _isAuth){ if(isCustomFeeEnabled){ - _isAuth = (authorized[_authAdd] || owner() == _authAdd) ; + _isAuth = (isCustomFeeSetter[_setterAddress] || solver == _setterAddress) ; }else{ _isAuth = false; } } - function addAuthorized(address _toAdd) onlyOwner public { + function addCustomFeeSetter(address _toAdd) onlySolver public { require(_toAdd != address(0)); require(isCustomFeeEnabled,"Custom Fee Not Enabled"); - authorized[_toAdd] = true; - emit authorizorAdded(_toAdd); + isCustomFeeSetter[_toAdd] = true; + emit feeSetterAdded(_toAdd); } - function removeAuthorized(address _toRemove) onlyOwner public { + function removeCustomFeeSetter(address _toRemove) onlySolver public { require(_toRemove != msg.sender); - authorized[_toRemove] = false; - emit authorizorRemoved(_toRemove); + isCustomFeeSetter[_toRemove] = false; + emit feeSetterRemoved(_toRemove); } - function enableCustomFee() onlyOwner() internal { + function enableCustomFee() onlySolver() internal { require(!isCustomFeeEnabled, "Already Enabled"); isCustomFeeEnabled = true; } + function _setSolverAddress(address _solver) internal { + require(_solver != address(0)); + solver = _solver; + } + + modifier onlySolver() { + require(solver == msg.sender,'CALLER_IS_NOT_SOLVER'); + _; + } + } \ No newline at end of file diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index 016bcbd5a4..812cc28476 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -408,7 +408,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees,CustomFeeAut OperationType _operation) public view virtual override returns (uint256 _fee) { // using tx.origin insted of msg.sender as these functions are called // during join/exit/swap via vault - if(isCustomFeeEnabled && isCustomFeeAuthorised(tx.origin)){ + if(isCustomFeeEnabled && canSetCustomFee(tx.origin)){ if(_operation == OperationType.JOIN ){ WeightedPoolUserData.JoinKind kind = userData.joinKind(); if(kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT){ @@ -435,15 +435,14 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees,CustomFeeAut } } }else{ - // return _miscData.decodeUint(_SWAP_FEE_PERCENTAGE_OFFSET, _SWAP_FEE_PERCENTAGE_BIT_LENGTH); - _fee = super.getSwapFeePercentage(hex"00", OperationType.NONE); + _fee = getSwapFeePercentage(); } } function setSwapFeePercentage(uint256 swapFeePercentage) public virtual override whenNotPaused { // here msg.sender is used as this function directlly be called by the admin // not via any other contract - if(isCustomFeeEnabled && owner() == msg.sender){ + if(isCustomFeeEnabled && solver == msg.sender){ _setSwapFeePercentage(swapFeePercentage); }else { super.setSwapFeePercentage(swapFeePercentage); diff --git a/pkg/pool-weighted/lbp/LiquidityBootstrappingPool.sol b/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPool.sol similarity index 100% rename from pkg/pool-weighted/lbp/LiquidityBootstrappingPool.sol rename to pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPool.sol diff --git a/pkg/pool-weighted/lbp/LiquidityBootstrappingPoolFactory.sol b/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolFactory.sol similarity index 100% rename from pkg/pool-weighted/lbp/LiquidityBootstrappingPoolFactory.sol rename to pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolFactory.sol diff --git a/pkg/pool-weighted/lbp/LiquidityBootstrappingPoolSettings.sol b/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolSettings.sol similarity index 100% rename from pkg/pool-weighted/lbp/LiquidityBootstrappingPoolSettings.sol rename to pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolSettings.sol diff --git a/pkg/pool-weighted/lbp/LiquidityBootstrappingPoolStorageLib.sol b/pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolStorageLib.sol similarity index 100% rename from pkg/pool-weighted/lbp/LiquidityBootstrappingPoolStorageLib.sol rename to pkg/pool-weighted/contracts/lbp/LiquidityBootstrappingPoolStorageLib.sol diff --git a/pkg/pool-weighted/managed/CircuitBreakerStorageLib.sol b/pkg/pool-weighted/contracts/managed/CircuitBreakerStorageLib.sol similarity index 100% rename from pkg/pool-weighted/managed/CircuitBreakerStorageLib.sol rename to pkg/pool-weighted/contracts/managed/CircuitBreakerStorageLib.sol diff --git a/pkg/pool-weighted/managed/ManagedPool.sol b/pkg/pool-weighted/contracts/managed/ManagedPool.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPool.sol rename to pkg/pool-weighted/contracts/managed/ManagedPool.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolAddRemoveTokenLib.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolAddRemoveTokenLib.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolAddRemoveTokenLib.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolAddRemoveTokenLib.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolAmmLib.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolAmmLib.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolAmmLib.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolAmmLib.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolAumStorageLib.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolAumStorageLib.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolAumStorageLib.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolAumStorageLib.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolFactory.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolFactory.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolFactory.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolSettings.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolSettings.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolSettings.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolSettings.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolStorageLib.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolStorageLib.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolStorageLib.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolStorageLib.sol diff --git a/pkg/pool-weighted/managed/ManagedPoolTokenStorageLib.sol b/pkg/pool-weighted/contracts/managed/ManagedPoolTokenStorageLib.sol similarity index 100% rename from pkg/pool-weighted/managed/ManagedPoolTokenStorageLib.sol rename to pkg/pool-weighted/contracts/managed/ManagedPoolTokenStorageLib.sol diff --git a/pkg/pool-weighted/managed/README.md b/pkg/pool-weighted/contracts/managed/README.md similarity index 100% rename from pkg/pool-weighted/managed/README.md rename to pkg/pool-weighted/contracts/managed/README.md diff --git a/pkg/pool-weighted/test1/MockWeightedPool.sol b/pkg/pool-weighted/test1/MockWeightedPool.sol index 1372492f38..dc9e4db5c9 100644 --- a/pkg/pool-weighted/test1/MockWeightedPool.sol +++ b/pkg/pool-weighted/test1/MockWeightedPool.sol @@ -25,7 +25,7 @@ contract MockWeightedPool is WeightedPool { uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner - ) WeightedPool(params, vault, protocolFeeProvider, pauseWindowDuration, bufferPeriodDuration, owner) { + ) WeightedPool(params, vault, protocolFeeProvider, pauseWindowDuration, bufferPeriodDuration, owner, false) { // solhint-disable-previous-line no-empty-blocks } From c38d1fbc846ae7f103f29c0da65c9b0aa4062d02 Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Wed, 29 Nov 2023 22:51:56 +0530 Subject: [PATCH 06/19] optimizing --- pkg/interfaces/contracts/vault/IBasePool.sol | 4 ++-- .../contracts/BaseMinimalSwapInfoPool.sol | 8 ++++---- pkg/pool-utils/contracts/BasePool.sol | 18 ++++++++++++------ 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/pkg/interfaces/contracts/vault/IBasePool.sol b/pkg/interfaces/contracts/vault/IBasePool.sol index 588b6f7a61..22ec9a4f5b 100644 --- a/pkg/interfaces/contracts/vault/IBasePool.sol +++ b/pkg/interfaces/contracts/vault/IBasePool.sol @@ -46,7 +46,7 @@ interface IBasePool is IPoolSwapStructs { * state-changing operations, such as minting pool shares. */ // enum for transaction type - enum OperationType { JOIN, EXIT, SWAP, NONE } + enum OperationType { JOIN, EXIT, SWAP } function onJoinPool( bytes32 poolId, @@ -99,7 +99,7 @@ interface IBasePool is IPoolSwapStructs { * @dev Returns the current swap fee percentage as a 18 decimal fixed point number, so e.g. 1e17 corresponds to a * 10% swap fee. */ - function getSwapFeePercentage(bytes memory userData, OperationType _operation) external view returns (uint256); + function getSwapFeePercentage() external view returns (uint256); /** * @dev Returns the scaling factors of each of the Pool's tokens. This is an implementation detail that is typically diff --git a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol index 2b20cd735b..6840ca9c4e 100644 --- a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol +++ b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol @@ -36,6 +36,8 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { ) public override onlyVault(request.poolId) returns (uint256) { _beforeSwapJoinExit(); + emit SwapFeePercentageChanged(getSwapFeePercentage(request.userData, OperationType.SWAP)); + uint256 scalingFactorTokenIn = _scalingFactor(request.tokenIn); uint256 scalingFactorTokenOut = _scalingFactor(request.tokenOut); @@ -44,9 +46,8 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { if (request.kind == IVault.SwapKind.GIVEN_IN) { // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis. - request.amount = _subtractSwapFeeAmount(request.amount, request.userData); + request.amount = _subtractSwapFeeAmount(request.amount, request.userData, OperationType.SWAP); - emit SwapFeePercentageChanged(getSwapFeePercentage(request.userData, OperationType.SWAP)); // All token amounts are upscaled. request.amount = _upscale(request.amount, scalingFactorTokenIn); @@ -64,8 +65,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { amountIn = _downscaleUp(amountIn, scalingFactorTokenIn); // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis. - emit SwapFeePercentageChanged(getSwapFeePercentage(request.userData, OperationType.SWAP)); - return _addSwapFeeAmount(amountIn, request.userData); + return _addSwapFeeAmount(amountIn, request.userData, OperationType.SWAP); } } diff --git a/pkg/pool-utils/contracts/BasePool.sol b/pkg/pool-utils/contracts/BasePool.sol index db8bd434e5..c4655c8bb8 100644 --- a/pkg/pool-utils/contracts/BasePool.sol +++ b/pkg/pool-utils/contracts/BasePool.sol @@ -169,15 +169,20 @@ abstract contract BasePool is * @notice Return the current value of the swap fee percentage. * @dev This is stored in `_miscData`. */ + function getSwapFeePercentage() public view virtual override returns (uint256) { + return _miscData.decodeUint(_SWAP_FEE_PERCENTAGE_OFFSET, _SWAP_FEE_PERCENTAGE_BIT_LENGTH); + } + + // overloaded method implementation function getSwapFeePercentage(bytes memory userData, - OperationType _operation) public view virtual override returns (uint256) { + OperationType _operation) public view virtual returns (uint256) { // this code is just to avoid un-used variable warning. // this will have no impact on the execution // will remove this code in future if(_operation == OperationType.SWAP){ userData = hex"00"; } - return _miscData.decodeUint(_SWAP_FEE_PERCENTAGE_OFFSET, _SWAP_FEE_PERCENTAGE_BIT_LENGTH); + return getSwapFeePercentage(); } /** @@ -599,17 +604,18 @@ abstract contract BasePool is /** * @dev Adds swap fee amount to `amount`, returning a higher value. */ - function _addSwapFeeAmount(uint256 amount, bytes memory userData) internal view returns (uint256) { + function _addSwapFeeAmount(uint256 amount, bytes memory userData, OperationType _operationType) internal view returns (uint256) { // This returns amount + fee amount, so we round up (favoring a higher fee amount). - return amount.divUp(getSwapFeePercentage(userData, OperationType.SWAP).complement()); + return amount.divUp(getSwapFeePercentage(userData, _operationType).complement()); } + /** * @dev Subtracts swap fee amount from `amount`, returning a lower value. */ - function _subtractSwapFeeAmount(uint256 amount, bytes memory userData) internal view returns (uint256) { + function _subtractSwapFeeAmount(uint256 amount, bytes memory userData, OperationType _operationType) internal view returns (uint256) { // This returns amount - fee amount, so we round up (favoring a higher fee amount). - uint256 feeAmount = amount.mulUp(getSwapFeePercentage(userData, OperationType.SWAP)); + uint256 feeAmount = amount.mulUp(getSwapFeePercentage(userData, _operationType)); return amount.sub(feeAmount); } From 16f5533fc1fb02e75f50b2a8383e9d91a279038d Mon Sep 17 00:00:00 2001 From: Markus Buhatem Koch Date: Fri, 1 Dec 2023 11:04:23 +0000 Subject: [PATCH 07/19] lint --- pkg/pool-utils/contracts/BasePool.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pool-utils/contracts/BasePool.sol b/pkg/pool-utils/contracts/BasePool.sol index c4655c8bb8..2a42ef863d 100644 --- a/pkg/pool-utils/contracts/BasePool.sol +++ b/pkg/pool-utils/contracts/BasePool.sol @@ -169,7 +169,7 @@ abstract contract BasePool is * @notice Return the current value of the swap fee percentage. * @dev This is stored in `_miscData`. */ - function getSwapFeePercentage() public view virtual override returns (uint256) { + function getSwapFeePercentage() public view virtual override returns (uint256) { return _miscData.decodeUint(_SWAP_FEE_PERCENTAGE_OFFSET, _SWAP_FEE_PERCENTAGE_BIT_LENGTH); } From 7f40f1611a6fce1e5d54091108fb75b0d968177f Mon Sep 17 00:00:00 2001 From: Markus Buhatem Koch Date: Fri, 1 Dec 2023 11:04:46 +0000 Subject: [PATCH 08/19] lint --- pkg/pool-weighted/contracts/WeightedPool.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index 812cc28476..0ea30e730b 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -22,7 +22,7 @@ import "./CustomFeeAuthorizer.sol"; /** * @dev Basic Weighted Pool with immutable weights. */ -contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees,CustomFeeAuthorizer { +contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAuthorizer { using FixedPoint for uint256; using WeightedPoolUserData for bytes; From b7af5dd889ff2871a32a75f2284593734eb42e01 Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Sat, 2 Dec 2023 12:27:47 +0530 Subject: [PATCH 09/19] updated conditions --- pkg/pool-weighted/contracts/WeightedPool.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index 0ea30e730b..c40827bb8b 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -442,9 +442,10 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu function setSwapFeePercentage(uint256 swapFeePercentage) public virtual override whenNotPaused { // here msg.sender is used as this function directlly be called by the admin // not via any other contract - if(isCustomFeeEnabled && solver == msg.sender){ - _setSwapFeePercentage(swapFeePercentage); - }else { + if (isCustomFeeEnabled) { + require(solver == msg.sender,'CALLER_IS_NOT_SOLVER'); + _setSwapFeePercentage(swapFeePercentage); + } else { super.setSwapFeePercentage(swapFeePercentage); } } From e5bb1d16dc79a3d5e4d12350d821b400cdb3b03c Mon Sep 17 00:00:00 2001 From: Sourav Suman Date: Sun, 7 Jan 2024 20:51:33 +0530 Subject: [PATCH 10/19] worked on suggsted PR changes --- pkg/pool-utils/contracts/BaseGeneralPool.sol | 4 ++-- .../contracts/BaseMinimalSwapInfoPool.sol | 10 ++++----- pkg/pool-utils/contracts/BasePool.sol | 21 +++++++------------ pkg/pool-weighted/test1/MockWeightedPool.sol | 4 ++-- 4 files changed, 17 insertions(+), 22 deletions(-) diff --git a/pkg/pool-utils/contracts/BaseGeneralPool.sol b/pkg/pool-utils/contracts/BaseGeneralPool.sol index bfbd43a3c1..79d24f51dd 100644 --- a/pkg/pool-utils/contracts/BaseGeneralPool.sol +++ b/pkg/pool-utils/contracts/BaseGeneralPool.sol @@ -54,7 +54,7 @@ abstract contract BaseGeneralPool is IGeneralPool, BasePool { uint256[] memory scalingFactors ) internal virtual returns (uint256) { // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis. - swapRequest.amount = _subtractSwapFeeAmount(swapRequest.amount); + swapRequest.amount = _subtractSwapFeeAmount(swapRequest.amount, getSwapFeePercentage()); _upscaleArray(balances, scalingFactors); swapRequest.amount = _upscale(swapRequest.amount, scalingFactors[indexIn]); @@ -81,7 +81,7 @@ abstract contract BaseGeneralPool is IGeneralPool, BasePool { amountIn = _downscaleUp(amountIn, scalingFactors[indexIn]); // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis. - return _addSwapFeeAmount(amountIn); + return _addSwapFeeAmount(amountIn, getSwapFeePercentage()); } /* diff --git a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol index 6840ca9c4e..86ab5a4e3f 100644 --- a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol +++ b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol @@ -35,8 +35,8 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { uint256 balanceTokenOut ) public override onlyVault(request.poolId) returns (uint256) { _beforeSwapJoinExit(); - - emit SwapFeePercentageChanged(getSwapFeePercentage(request.userData, OperationType.SWAP)); + uint256 _fee = getSwapFeePercentage(request.userData, OperationType.SWAP); + emit SwapFeePercentageChanged(_fee); uint256 scalingFactorTokenIn = _scalingFactor(request.tokenIn); uint256 scalingFactorTokenOut = _scalingFactor(request.tokenOut); @@ -46,7 +46,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { if (request.kind == IVault.SwapKind.GIVEN_IN) { // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis. - request.amount = _subtractSwapFeeAmount(request.amount, request.userData, OperationType.SWAP); + request.amount = _subtractSwapFeeAmount(request.amount, _fee); // All token amounts are upscaled. request.amount = _upscale(request.amount, scalingFactorTokenIn); @@ -65,7 +65,7 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { amountIn = _downscaleUp(amountIn, scalingFactorTokenIn); // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis. - return _addSwapFeeAmount(amountIn, request.userData, OperationType.SWAP); + return _addSwapFeeAmount(amountIn, _fee); } } @@ -101,4 +101,4 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { uint256 balanceTokenIn, uint256 balanceTokenOut ) internal virtual returns (uint256); -} +} \ No newline at end of file diff --git a/pkg/pool-utils/contracts/BasePool.sol b/pkg/pool-utils/contracts/BasePool.sol index 2a42ef863d..df16ce2e21 100644 --- a/pkg/pool-utils/contracts/BasePool.sol +++ b/pkg/pool-utils/contracts/BasePool.sol @@ -174,14 +174,9 @@ abstract contract BasePool is } // overloaded method implementation - function getSwapFeePercentage(bytes memory userData, - OperationType _operation) public view virtual returns (uint256) { - // this code is just to avoid un-used variable warning. - // this will have no impact on the execution - // will remove this code in future - if(_operation == OperationType.SWAP){ - userData = hex"00"; - } + function getSwapFeePercentage(bytes memory , + OperationType ) public view virtual returns (uint256) { + // override the function as per the need in the derived classes return getSwapFeePercentage(); } @@ -604,18 +599,18 @@ abstract contract BasePool is /** * @dev Adds swap fee amount to `amount`, returning a higher value. */ - function _addSwapFeeAmount(uint256 amount, bytes memory userData, OperationType _operationType) internal view returns (uint256) { + function _addSwapFeeAmount(uint256 amount,uint256 _fee) internal pure returns (uint256) { // This returns amount + fee amount, so we round up (favoring a higher fee amount). - return amount.divUp(getSwapFeePercentage(userData, _operationType).complement()); + return amount.divUp(_fee.complement()); } /** * @dev Subtracts swap fee amount from `amount`, returning a lower value. */ - function _subtractSwapFeeAmount(uint256 amount, bytes memory userData, OperationType _operationType) internal view returns (uint256) { + function _subtractSwapFeeAmount(uint256 amount, uint256 _fee) internal pure returns (uint256) { // This returns amount - fee amount, so we round up (favoring a higher fee amount). - uint256 feeAmount = amount.mulUp(getSwapFeePercentage(userData, _operationType)); + uint256 feeAmount = amount.mulUp(_fee); return amount.sub(feeAmount); } @@ -797,4 +792,4 @@ abstract contract BasePool is } } } -} +} \ No newline at end of file diff --git a/pkg/pool-weighted/test1/MockWeightedPool.sol b/pkg/pool-weighted/test1/MockWeightedPool.sol index dc9e4db5c9..8c81b62537 100644 --- a/pkg/pool-weighted/test1/MockWeightedPool.sol +++ b/pkg/pool-weighted/test1/MockWeightedPool.sol @@ -25,11 +25,11 @@ contract MockWeightedPool is WeightedPool { uint256 pauseWindowDuration, uint256 bufferPeriodDuration, address owner - ) WeightedPool(params, vault, protocolFeeProvider, pauseWindowDuration, bufferPeriodDuration, owner, false) { + ) WeightedPool(params, vault, protocolFeeProvider, pauseWindowDuration, bufferPeriodDuration, owner) { // solhint-disable-previous-line no-empty-blocks } function isOwnerOnlyAction(bytes32 actionId) external view returns (bool) { return _isOwnerOnlyAction(actionId); } -} +} \ No newline at end of file From 7d04e807ad59f5ca66fa0496bc1fb9e88d976691 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Fri, 2 Feb 2024 17:29:01 -0300 Subject: [PATCH 11/19] Undo mock files move. --- .../{test1 => contracts/test}/MockCircuitBreakerLib.sol | 0 .../{test1 => contracts/test}/MockGradualValueChange.sol | 0 .../test}/MockLiquidityBootstrappingPoolStorageLib.sol | 0 pkg/pool-weighted/{test1 => contracts/test}/MockManagedPool.sol | 0 .../{test1 => contracts/test}/MockManagedPoolSettings.sol | 0 .../{test1 => contracts/test}/MockManagedPoolTokenStorageLib.sol | 0 .../{test1 => contracts/test}/MockValueCompression.sol | 0 pkg/pool-weighted/{test1 => contracts/test}/MockWeightedPool.sol | 0 .../{test1 => contracts/test}/MockWeightedPoolProtocolFees.sol | 0 .../{test1 => contracts/test}/MockWithdrawDepositAssetManager.sol | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename pkg/pool-weighted/{test1 => contracts/test}/MockCircuitBreakerLib.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockGradualValueChange.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockLiquidityBootstrappingPoolStorageLib.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockManagedPool.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockManagedPoolSettings.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockManagedPoolTokenStorageLib.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockValueCompression.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockWeightedPool.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockWeightedPoolProtocolFees.sol (100%) rename pkg/pool-weighted/{test1 => contracts/test}/MockWithdrawDepositAssetManager.sol (100%) diff --git a/pkg/pool-weighted/test1/MockCircuitBreakerLib.sol b/pkg/pool-weighted/contracts/test/MockCircuitBreakerLib.sol similarity index 100% rename from pkg/pool-weighted/test1/MockCircuitBreakerLib.sol rename to pkg/pool-weighted/contracts/test/MockCircuitBreakerLib.sol diff --git a/pkg/pool-weighted/test1/MockGradualValueChange.sol b/pkg/pool-weighted/contracts/test/MockGradualValueChange.sol similarity index 100% rename from pkg/pool-weighted/test1/MockGradualValueChange.sol rename to pkg/pool-weighted/contracts/test/MockGradualValueChange.sol diff --git a/pkg/pool-weighted/test1/MockLiquidityBootstrappingPoolStorageLib.sol b/pkg/pool-weighted/contracts/test/MockLiquidityBootstrappingPoolStorageLib.sol similarity index 100% rename from pkg/pool-weighted/test1/MockLiquidityBootstrappingPoolStorageLib.sol rename to pkg/pool-weighted/contracts/test/MockLiquidityBootstrappingPoolStorageLib.sol diff --git a/pkg/pool-weighted/test1/MockManagedPool.sol b/pkg/pool-weighted/contracts/test/MockManagedPool.sol similarity index 100% rename from pkg/pool-weighted/test1/MockManagedPool.sol rename to pkg/pool-weighted/contracts/test/MockManagedPool.sol diff --git a/pkg/pool-weighted/test1/MockManagedPoolSettings.sol b/pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol similarity index 100% rename from pkg/pool-weighted/test1/MockManagedPoolSettings.sol rename to pkg/pool-weighted/contracts/test/MockManagedPoolSettings.sol diff --git a/pkg/pool-weighted/test1/MockManagedPoolTokenStorageLib.sol b/pkg/pool-weighted/contracts/test/MockManagedPoolTokenStorageLib.sol similarity index 100% rename from pkg/pool-weighted/test1/MockManagedPoolTokenStorageLib.sol rename to pkg/pool-weighted/contracts/test/MockManagedPoolTokenStorageLib.sol diff --git a/pkg/pool-weighted/test1/MockValueCompression.sol b/pkg/pool-weighted/contracts/test/MockValueCompression.sol similarity index 100% rename from pkg/pool-weighted/test1/MockValueCompression.sol rename to pkg/pool-weighted/contracts/test/MockValueCompression.sol diff --git a/pkg/pool-weighted/test1/MockWeightedPool.sol b/pkg/pool-weighted/contracts/test/MockWeightedPool.sol similarity index 100% rename from pkg/pool-weighted/test1/MockWeightedPool.sol rename to pkg/pool-weighted/contracts/test/MockWeightedPool.sol diff --git a/pkg/pool-weighted/test1/MockWeightedPoolProtocolFees.sol b/pkg/pool-weighted/contracts/test/MockWeightedPoolProtocolFees.sol similarity index 100% rename from pkg/pool-weighted/test1/MockWeightedPoolProtocolFees.sol rename to pkg/pool-weighted/contracts/test/MockWeightedPoolProtocolFees.sol diff --git a/pkg/pool-weighted/test1/MockWithdrawDepositAssetManager.sol b/pkg/pool-weighted/contracts/test/MockWithdrawDepositAssetManager.sol similarity index 100% rename from pkg/pool-weighted/test1/MockWithdrawDepositAssetManager.sol rename to pkg/pool-weighted/contracts/test/MockWithdrawDepositAssetManager.sol From 6efa83756c2df5e7ef5eec337d072cd3887c27d3 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Fri, 2 Feb 2024 17:58:18 -0300 Subject: [PATCH 12/19] Fix hardhat tests with polymorphic getSwapFeePercentage. --- pkg/pool-utils/test/BasePool.test.ts | 6 +++--- pkg/pool-weighted/test/WeightedPoolFactory.test.ts | 2 +- pvt/helpers/src/models/pools/base/BasePool.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/pool-utils/test/BasePool.test.ts b/pkg/pool-utils/test/BasePool.test.ts index 59e154f0ec..43ae083fd2 100644 --- a/pkg/pool-utils/test/BasePool.test.ts +++ b/pkg/pool-utils/test/BasePool.test.ts @@ -154,7 +154,7 @@ describe('BasePool', function () { const swapFeePercentage = fp(0.003); const pool = await deployBasePool({ swapFeePercentage }); - expect(await pool.getSwapFeePercentage()).to.equal(swapFeePercentage); + expect(await pool['getSwapFeePercentage()']()).to.equal(swapFeePercentage); }); }); @@ -169,7 +169,7 @@ describe('BasePool', function () { it('can change the swap fee', async () => { await pool.connect(sender).setSwapFeePercentage(newSwapFeePercentage); - expect(await pool.getSwapFeePercentage()).to.equal(newSwapFeePercentage); + expect(await pool['getSwapFeePercentage()']()).to.equal(newSwapFeePercentage); }); it('emits an event', async () => { @@ -815,7 +815,7 @@ describe('BasePool', function () { }); it('stores the swap fee pct in the most-significant 64 bits', async () => { - expect(await pool.getSwapFeePercentage()).to.equal(swapFeePercentage); + expect(await pool['getSwapFeePercentage()']()).to.equal(swapFeePercentage); const swapFeeHex = swapFeePercentage.toHexString().slice(2); // remove 0x const expectedMiscData = swapFeeHex.padStart(16, '0').padEnd(64, '0'); // pad first 8 bytes and fill with zeros diff --git a/pkg/pool-weighted/test/WeightedPoolFactory.test.ts b/pkg/pool-weighted/test/WeightedPoolFactory.test.ts index a78c05a6e0..554c25d169 100644 --- a/pkg/pool-weighted/test/WeightedPoolFactory.test.ts +++ b/pkg/pool-weighted/test/WeightedPoolFactory.test.ts @@ -104,7 +104,7 @@ describe('WeightedPoolFactory', function () { }); it('sets swap fee', async () => { - expect(await pool.getSwapFeePercentage()).to.equal(POOL_SWAP_FEE_PERCENTAGE); + expect(await pool['getSwapFeePercentage()']()).to.equal(POOL_SWAP_FEE_PERCENTAGE); }); it('sets the owner ', async () => { diff --git a/pvt/helpers/src/models/pools/base/BasePool.ts b/pvt/helpers/src/models/pools/base/BasePool.ts index 1507d9b901..b4cd5485b2 100644 --- a/pvt/helpers/src/models/pools/base/BasePool.ts +++ b/pvt/helpers/src/models/pools/base/BasePool.ts @@ -84,7 +84,7 @@ export default class BasePool { } async getSwapFeePercentage(): Promise { - return this.instance.getSwapFeePercentage(); + return this.instance['getSwapFeePercentage()'](); } async getScalingFactors(): Promise { From bff430287da64a9d8c13f4821042bddc53901a80 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Fri, 2 Feb 2024 18:57:04 -0300 Subject: [PATCH 13/19] Linter pass. --- .../pool-weighted/WeightedPoolUserData.sol | 20 ++----- .../solidity-utils/helpers/BalancerErrors.sol | 1 + pkg/interfaces/contracts/vault/IBasePool.sol | 2 +- .../contracts/BaseMinimalSwapInfoPool.sol | 2 +- pkg/pool-utils/contracts/BasePool.sol | 14 +++-- .../contracts/BaseWeightedPool.sol | 12 +++-- .../contracts/CustomFeeAuthorizer.sol | 47 ++++++++-------- pkg/pool-weighted/contracts/WeightedPool.sol | 54 ++++++++++--------- 8 files changed, 74 insertions(+), 78 deletions(-) diff --git a/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol b/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol index 3d057aba77..20b43c6447 100644 --- a/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol +++ b/pkg/interfaces/contracts/pool-weighted/WeightedPoolUserData.sol @@ -74,31 +74,19 @@ library WeightedPoolUserData { (, , , customFee) = abi.decode(self, (JoinKind, uint256, uint256, uint256)); } - function exactTokensInForBptOutCustomFee(bytes memory self) - internal - pure - returns (uint256 customFee) - { + function exactTokensInForBptOutCustomFee(bytes memory self) internal pure returns (uint256 customFee) { (, , , customFee) = abi.decode(self, (JoinKind, uint256[], uint256, uint256)); } - function exactBptInForTokenOutCustomFee(bytes memory self) internal pure returns (uint256 customFee) { + function exactBptInForTokenOutCustomFee(bytes memory self) internal pure returns (uint256 customFee) { (, , , customFee) = abi.decode(self, (ExitKind, uint256, uint256, uint256)); } - function bptInForExactTokensOutCustomFee(bytes memory self) - internal - pure - returns (uint256 customFee) - { + function bptInForExactTokensOutCustomFee(bytes memory self) internal pure returns (uint256 customFee) { (, , , customFee) = abi.decode(self, (ExitKind, uint256[], uint256, uint256)); } - function swapCustomFee(bytes memory self) - internal - pure - returns (uint256 customFee) - { + function swapCustomFee(bytes memory self) internal pure returns (uint256 customFee) { (customFee) = abi.decode(self, (uint256)); } } diff --git a/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol b/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol index fa2df50cee..dd211fe9a2 100644 --- a/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol +++ b/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol @@ -246,6 +246,7 @@ library Errors { uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442; uint256 internal constant UNHANDLED_FEE_TYPE = 443; uint256 internal constant BURN_FROM_ZERO = 444; + uint256 internal constant INVALID_INPUT_ADDRESS = 445; // Vault uint256 internal constant INVALID_POOL_ID = 500; diff --git a/pkg/interfaces/contracts/vault/IBasePool.sol b/pkg/interfaces/contracts/vault/IBasePool.sol index 22ec9a4f5b..1c194b5b9a 100644 --- a/pkg/interfaces/contracts/vault/IBasePool.sol +++ b/pkg/interfaces/contracts/vault/IBasePool.sol @@ -45,7 +45,7 @@ interface IBasePool is IPoolSwapStructs { * Contracts implementing this function should check that the caller is indeed the Vault before performing any * state-changing operations, such as minting pool shares. */ - // enum for transaction type + // enum for transaction type enum OperationType { JOIN, EXIT, SWAP } function onJoinPool( diff --git a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol index 86ab5a4e3f..8a594bd51d 100644 --- a/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol +++ b/pkg/pool-utils/contracts/BaseMinimalSwapInfoPool.sol @@ -101,4 +101,4 @@ abstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool { uint256 balanceTokenIn, uint256 balanceTokenOut ) internal virtual returns (uint256); -} \ No newline at end of file +} diff --git a/pkg/pool-utils/contracts/BasePool.sol b/pkg/pool-utils/contracts/BasePool.sol index df16ce2e21..2fed496720 100644 --- a/pkg/pool-utils/contracts/BasePool.sol +++ b/pkg/pool-utils/contracts/BasePool.sol @@ -174,8 +174,7 @@ abstract contract BasePool is } // overloaded method implementation - function getSwapFeePercentage(bytes memory , - OperationType ) public view virtual returns (uint256) { + function getSwapFeePercentage(bytes memory, OperationType) public view virtual returns (uint256) { // override the function as per the need in the derived classes return getSwapFeePercentage(); } @@ -599,18 +598,17 @@ abstract contract BasePool is /** * @dev Adds swap fee amount to `amount`, returning a higher value. */ - function _addSwapFeeAmount(uint256 amount,uint256 _fee) internal pure returns (uint256) { + function _addSwapFeeAmount(uint256 amount, uint256 fee) internal pure returns (uint256) { // This returns amount + fee amount, so we round up (favoring a higher fee amount). - return amount.divUp(_fee.complement()); + return amount.divUp(fee.complement()); } - /** * @dev Subtracts swap fee amount from `amount`, returning a lower value. */ - function _subtractSwapFeeAmount(uint256 amount, uint256 _fee) internal pure returns (uint256) { + function _subtractSwapFeeAmount(uint256 amount, uint256 fee) internal pure returns (uint256) { // This returns amount - fee amount, so we round up (favoring a higher fee amount). - uint256 feeAmount = amount.mulUp(_fee); + uint256 feeAmount = amount.mulUp(fee); return amount.sub(feeAmount); } @@ -792,4 +790,4 @@ abstract contract BasePool is } } } -} \ No newline at end of file +} diff --git a/pkg/pool-weighted/contracts/BaseWeightedPool.sol b/pkg/pool-weighted/contracts/BaseWeightedPool.sol index 19bd96d1b8..fb6261f38e 100644 --- a/pkg/pool-weighted/contracts/BaseWeightedPool.sol +++ b/pkg/pool-weighted/contracts/BaseWeightedPool.sol @@ -229,8 +229,10 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { // but it's a view function so can not emit event WeightedPoolUserData.JoinKind kind = userData.joinKind(); - if(kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT || - kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT){ + if ( + kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT || + kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT + ) { emit SwapFeePercentageChanged(getSwapFeePercentage(userData, OperationType.JOIN)); } @@ -366,8 +368,10 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { // but it's a view function so can not emit event WeightedPoolUserData.ExitKind kind = userData.exitKind(); - if(kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT || - kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT){ + if ( + kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT || + kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT + ) { emit SwapFeePercentageChanged(getSwapFeePercentage(userData, OperationType.EXIT)); } diff --git a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol index 45a5d6b7c7..e17f1dfef8 100644 --- a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol +++ b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol @@ -1,50 +1,49 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.7.0; +import "@balancer-labs/v2-interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol"; contract CustomFeeAuthorizer { - event feeSetterAdded(address indexed feeSetter); - event feeSetterRemoved(address indexed feeSetter); + event FeeSetterAdded(address indexed feeSetter); + event FeeSetterRemoved(address indexed feeSetter); - mapping(address => bool) private isCustomFeeSetter; - bool public isCustomFeeEnabled = false ; + mapping(address => bool) private _isCustomFeeSetter; + bool public isCustomFeeEnabled = false; address public solver; - function canSetCustomFee(address _setterAddress) public view returns(bool _isAuth){ - if(isCustomFeeEnabled){ - _isAuth = (isCustomFeeSetter[_setterAddress] || solver == _setterAddress) ; - }else{ - _isAuth = false; + function canSetCustomFee(address setterAddress) public view returns (bool isAuthorized) { + if (isCustomFeeEnabled) { + isAuthorized = (_isCustomFeeSetter[setterAddress] || solver == setterAddress); + } else { + isAuthorized = false; } } - function addCustomFeeSetter(address _toAdd) onlySolver public { - require(_toAdd != address(0)); - require(isCustomFeeEnabled,"Custom Fee Not Enabled"); - isCustomFeeSetter[_toAdd] = true; - emit feeSetterAdded(_toAdd); + function addCustomFeeSetter(address newCustomFeeSetter) public onlySolver { + _require(newCustomFeeSetter != address(0), Errors.INVALID_INPUT_ADDRESS); + _require(isCustomFeeEnabled, Errors.FEATURE_DISABLED); + _isCustomFeeSetter[newCustomFeeSetter] = true; + emit FeeSetterAdded(newCustomFeeSetter); } - function removeCustomFeeSetter(address _toRemove) onlySolver public { - require(_toRemove != msg.sender); - isCustomFeeSetter[_toRemove] = false; - emit feeSetterRemoved(_toRemove); + function removeCustomFeeSetter(address customFeeSetter) public onlySolver { + _require(customFeeSetter != msg.sender, Errors.SENDER_NOT_ALLOWED); + _isCustomFeeSetter[customFeeSetter] = false; + emit FeeSetterRemoved(customFeeSetter); } - function enableCustomFee() onlySolver() internal { + function _enableCustomFee() internal onlySolver { require(!isCustomFeeEnabled, "Already Enabled"); isCustomFeeEnabled = true; } function _setSolverAddress(address _solver) internal { - require(_solver != address(0)); + _require(_solver != address(0), Errors.INVALID_INPUT_ADDRESS); solver = _solver; } modifier onlySolver() { - require(solver == msg.sender,'CALLER_IS_NOT_SOLVER'); + _require(solver == msg.sender, Errors.SENDER_NOT_ALLOWED); _; } - - -} \ No newline at end of file +} diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index c40827bb8b..524a838584 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -404,38 +404,44 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu return super._isOwnerOnlyAction(actionId); } - function getSwapFeePercentage(bytes memory userData, - OperationType _operation) public view virtual override returns (uint256 _fee) { - // using tx.origin insted of msg.sender as these functions are called + function getSwapFeePercentage(bytes memory userData, OperationType operation) + public + view + virtual + override + returns (uint256 fee) + { + // using tx.origin insted of msg.sender as these functions are called // during join/exit/swap via vault - if(isCustomFeeEnabled && canSetCustomFee(tx.origin)){ - if(_operation == OperationType.JOIN ){ + // solhint-disable-next-line avoid-tx-origin + if (isCustomFeeEnabled && canSetCustomFee(tx.origin)) { + if (operation == OperationType.JOIN) { WeightedPoolUserData.JoinKind kind = userData.joinKind(); - if(kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT){ - _fee = userData.exactTokensInForBptOutCustomFee(); + if (kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT) { + fee = userData.exactTokensInForBptOutCustomFee(); } else { - if(kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT){ - _fee = userData.tokenInForExactBptOutCustomFee(); - } + if (kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT) { + fee = userData.tokenInForExactBptOutCustomFee(); + } } - }else{ - if(_operation == OperationType.EXIT){ + } else { + if (operation == OperationType.EXIT) { WeightedPoolUserData.ExitKind kind = userData.exitKind(); - if(kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT){ - _fee = userData.exactBptInForTokenOutCustomFee(); + if (kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT) { + fee = userData.exactBptInForTokenOutCustomFee(); } else { - if(kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT){ - _fee = userData.bptInForExactTokensOutCustomFee(); - } + if (kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT) { + fee = userData.bptInForExactTokensOutCustomFee(); + } } - } else{ - if(_operation == OperationType.SWAP){ - _fee = userData.swapCustomFee(); + } else { + if (operation == OperationType.SWAP) { + fee = userData.swapCustomFee(); } } } - }else{ - _fee = getSwapFeePercentage(); + } else { + fee = getSwapFeePercentage(); } } @@ -443,8 +449,8 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu // here msg.sender is used as this function directlly be called by the admin // not via any other contract if (isCustomFeeEnabled) { - require(solver == msg.sender,'CALLER_IS_NOT_SOLVER'); - _setSwapFeePercentage(swapFeePercentage); + require(solver == msg.sender, "CALLER_IS_NOT_SOLVER"); + _setSwapFeePercentage(swapFeePercentage); } else { super.setSwapFeePercentage(swapFeePercentage); } From 9af72a5a9ef2fe05f4bb18d915ab64f9f9ed6b00 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Mon, 5 Feb 2024 13:04:38 -0300 Subject: [PATCH 14/19] Make `isCustomFeeEnabled` immutable. --- .../contracts/CustomFeeAuthorizer.sol | 29 ++++++++++--------- pkg/pool-weighted/contracts/WeightedPool.sol | 6 ++-- .../contracts/WeightedPoolFactory.sol | 4 ++- .../test/WeightedPoolFactory.test.ts | 1 + .../src/models/pools/weighted/WeightedPool.ts | 10 +++++-- .../src/models/pools/weighted/types.ts | 2 ++ .../src/models/types/TypesConverter.ts | 3 ++ 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol index e17f1dfef8..925e87c985 100644 --- a/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol +++ b/pkg/pool-weighted/contracts/CustomFeeAuthorizer.sol @@ -8,11 +8,24 @@ contract CustomFeeAuthorizer { event FeeSetterRemoved(address indexed feeSetter); mapping(address => bool) private _isCustomFeeSetter; - bool public isCustomFeeEnabled = false; + bool private immutable _isCustomFeeEnabled; address public solver; + modifier onlySolver() { + _require(solver == msg.sender, Errors.SENDER_NOT_ALLOWED); + _; + } + + constructor(bool isCustomFeeEnabled) { + _isCustomFeeEnabled = isCustomFeeEnabled; + } + + function isCustomFeeEnabled() public view returns (bool) { + return _isCustomFeeEnabled; + } + function canSetCustomFee(address setterAddress) public view returns (bool isAuthorized) { - if (isCustomFeeEnabled) { + if (_isCustomFeeEnabled) { isAuthorized = (_isCustomFeeSetter[setterAddress] || solver == setterAddress); } else { isAuthorized = false; @@ -21,7 +34,7 @@ contract CustomFeeAuthorizer { function addCustomFeeSetter(address newCustomFeeSetter) public onlySolver { _require(newCustomFeeSetter != address(0), Errors.INVALID_INPUT_ADDRESS); - _require(isCustomFeeEnabled, Errors.FEATURE_DISABLED); + _require(_isCustomFeeEnabled, Errors.FEATURE_DISABLED); _isCustomFeeSetter[newCustomFeeSetter] = true; emit FeeSetterAdded(newCustomFeeSetter); } @@ -32,18 +45,8 @@ contract CustomFeeAuthorizer { emit FeeSetterRemoved(customFeeSetter); } - function _enableCustomFee() internal onlySolver { - require(!isCustomFeeEnabled, "Already Enabled"); - isCustomFeeEnabled = true; - } - function _setSolverAddress(address _solver) internal { _require(_solver != address(0), Errors.INVALID_INPUT_ADDRESS); solver = _solver; } - - modifier onlySolver() { - _require(solver == msg.sender, Errors.SENDER_NOT_ALLOWED); - _; - } } diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index 524a838584..fd8ff4e612 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -69,6 +69,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu IRateProvider[] rateProviders; address[] assetManagers; uint256 swapFeePercentage; + bool isCustomFeeEnabled; } constructor( @@ -96,6 +97,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu ProviderFeeIDs({ swap: ProtocolFeeType.SWAP, yield: ProtocolFeeType.YIELD, aum: ProtocolFeeType.AUM }) ) WeightedPoolProtocolFees(params.tokens.length, params.rateProviders) + CustomFeeAuthorizer(params.isCustomFeeEnabled) { uint256 numTokens = params.tokens.length; InputHelpers.ensureInputLengthMatch(numTokens, params.normalizedWeights.length); @@ -414,7 +416,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu // using tx.origin insted of msg.sender as these functions are called // during join/exit/swap via vault // solhint-disable-next-line avoid-tx-origin - if (isCustomFeeEnabled && canSetCustomFee(tx.origin)) { + if (isCustomFeeEnabled() && canSetCustomFee(tx.origin)) { if (operation == OperationType.JOIN) { WeightedPoolUserData.JoinKind kind = userData.joinKind(); if (kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT) { @@ -448,7 +450,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu function setSwapFeePercentage(uint256 swapFeePercentage) public virtual override whenNotPaused { // here msg.sender is used as this function directlly be called by the admin // not via any other contract - if (isCustomFeeEnabled) { + if (isCustomFeeEnabled()) { require(solver == msg.sender, "CALLER_IS_NOT_SOLVER"); _setSwapFeePercentage(swapFeePercentage); } else { diff --git a/pkg/pool-weighted/contracts/WeightedPoolFactory.sol b/pkg/pool-weighted/contracts/WeightedPoolFactory.sol index c443177fc0..e613834c52 100644 --- a/pkg/pool-weighted/contracts/WeightedPoolFactory.sol +++ b/pkg/pool-weighted/contracts/WeightedPoolFactory.sol @@ -50,6 +50,7 @@ contract WeightedPoolFactory is BasePoolFactory { IRateProvider[] memory rateProviders, uint256 swapFeePercentage, address owner, + bool isCustomFeeEnabled, bytes32 salt ) external returns (address) { (uint256 pauseWindowDuration, uint256 bufferPeriodDuration) = getPauseConfiguration(); @@ -64,7 +65,8 @@ contract WeightedPoolFactory is BasePoolFactory { normalizedWeights: normalizedWeights, rateProviders: rateProviders, assetManagers: new address[](tokens.length), // Don't allow asset managers, - swapFeePercentage: swapFeePercentage + swapFeePercentage: swapFeePercentage, + isCustomFeeEnabled: isCustomFeeEnabled }), getVault(), getProtocolFeePercentagesProvider(), diff --git a/pkg/pool-weighted/test/WeightedPoolFactory.test.ts b/pkg/pool-weighted/test/WeightedPoolFactory.test.ts index 554c25d169..38de47f35a 100644 --- a/pkg/pool-weighted/test/WeightedPoolFactory.test.ts +++ b/pkg/pool-weighted/test/WeightedPoolFactory.test.ts @@ -59,6 +59,7 @@ describe('WeightedPoolFactory', function () { rateProviders, POOL_SWAP_FEE_PERCENTAGE, owner.address, + false, randomBytes(32) ) ).wait(); diff --git a/pvt/helpers/src/models/pools/weighted/WeightedPool.ts b/pvt/helpers/src/models/pools/weighted/WeightedPool.ts index 40b63a6eb1..9a63c9377a 100644 --- a/pvt/helpers/src/models/pools/weighted/WeightedPool.ts +++ b/pvt/helpers/src/models/pools/weighted/WeightedPool.ts @@ -15,6 +15,7 @@ import { randomBytes } from 'ethers/lib/utils'; export default class WeightedPool extends BaseWeightedPool { rateProviders: Account[]; assetManagers: string[]; + isCustomFeeEnabled: boolean; constructor( instance: Contract, @@ -25,12 +26,14 @@ export default class WeightedPool extends BaseWeightedPool { rateProviders: Account[], assetManagers: string[], swapFeePercentage: BigNumberish, + isCustomFeeEnabled: boolean, owner?: Account ) { super(instance, poolId, vault, tokens, weights, swapFeePercentage, owner); this.rateProviders = rateProviders; this.assetManagers = assetManagers; + this.isCustomFeeEnabled = isCustomFeeEnabled; } static async create(params: RawWeightedPoolDeployment = {}): Promise { @@ -39,7 +42,7 @@ export default class WeightedPool extends BaseWeightedPool { const pool = await (params.fromFactory ? this._deployFromFactory : this._deployStandalone)(deployment, vault); const poolId = await pool.getPoolId(); - const { tokens, weights, rateProviders, assetManagers, swapFeePercentage, owner } = deployment; + const { tokens, weights, rateProviders, assetManagers, swapFeePercentage, owner, isCustomFeeEnabled } = deployment; return new WeightedPool( pool, @@ -50,6 +53,7 @@ export default class WeightedPool extends BaseWeightedPool { rateProviders, assetManagers, swapFeePercentage, + isCustomFeeEnabled, owner ); } @@ -67,6 +71,7 @@ export default class WeightedPool extends BaseWeightedPool { rateProviders: TypesConverter.toAddresses(params.rateProviders), assetManagers: params.assetManagers, swapFeePercentage: params.swapFeePercentage, + isCustomFeeEnabled: params.isCustomFeeEnabled, }, vault.address, vault.protocolFeesProvider.address, @@ -81,7 +86,7 @@ export default class WeightedPool extends BaseWeightedPool { static async _deployFromFactory(params: WeightedPoolDeployment, vault: Vault): Promise { // Note that we only support asset managers with the standalone deploy method. - const { tokens, weights, rateProviders, swapFeePercentage, owner, from } = params; + const { tokens, weights, rateProviders, swapFeePercentage, owner, isCustomFeeEnabled, from } = params; const factory = await deploy('v2-pool-weighted/WeightedPoolFactory', { args: [vault.address, vault.getFeesProvider().address, PAUSE_WINDOW_DURATION, BUFFER_PERIOD_DURATION], @@ -96,6 +101,7 @@ export default class WeightedPool extends BaseWeightedPool { rateProviders, swapFeePercentage, owner, + isCustomFeeEnabled, randomBytes(32) ); const receipt = await tx.wait(); diff --git a/pvt/helpers/src/models/pools/weighted/types.ts b/pvt/helpers/src/models/pools/weighted/types.ts index ebeef3a537..0bef557c44 100644 --- a/pvt/helpers/src/models/pools/weighted/types.ts +++ b/pvt/helpers/src/models/pools/weighted/types.ts @@ -29,6 +29,7 @@ export type RawWeightedPoolDeployment = { pauseWindowDuration?: BigNumberish; bufferPeriodDuration?: BigNumberish; owner?: Account; + isCustomFeeEnabled?: boolean; admin?: SignerWithAddress; from?: SignerWithAddress; vault?: Vault; @@ -44,6 +45,7 @@ export type WeightedPoolDeployment = { pauseWindowDuration: BigNumberish; bufferPeriodDuration: BigNumberish; owner: Account; + isCustomFeeEnabled: boolean; admin?: SignerWithAddress; from?: SignerWithAddress; }; diff --git a/pvt/helpers/src/models/types/TypesConverter.ts b/pvt/helpers/src/models/types/TypesConverter.ts index 609a9e3a0c..cb1b594943 100644 --- a/pvt/helpers/src/models/types/TypesConverter.ts +++ b/pvt/helpers/src/models/types/TypesConverter.ts @@ -69,6 +69,7 @@ export default { swapFeePercentage, pauseWindowDuration, bufferPeriodDuration, + isCustomFeeEnabled, } = params; if (!params.owner) params.owner = ZERO_ADDRESS; if (!tokens) tokens = new TokenList(); @@ -79,6 +80,7 @@ export default { if (!bufferPeriodDuration) bufferPeriodDuration = DEFAULT_BUFFER_PERIOD_DURATION; if (!rateProviders) rateProviders = Array(tokens.length).fill(ZERO_ADDRESS); if (!assetManagers) assetManagers = Array(tokens.length).fill(ZERO_ADDRESS); + if (isCustomFeeEnabled === undefined) isCustomFeeEnabled = false; return { tokens, @@ -89,6 +91,7 @@ export default { pauseWindowDuration, bufferPeriodDuration, owner: this.toAddress(params.owner), + isCustomFeeEnabled, from: params.from, }; }, From db9ccbeb6c2a215fe1b6698b9d0e6780843fc5b4 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Mon, 5 Feb 2024 15:20:27 -0300 Subject: [PATCH 15/19] Simplify getSwapFeePercentage. --- .../solidity-utils/helpers/BalancerErrors.sol | 1 + pkg/pool-weighted/contracts/WeightedPool.sol | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol b/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol index dd211fe9a2..2adb157725 100644 --- a/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol +++ b/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol @@ -247,6 +247,7 @@ library Errors { uint256 internal constant UNHANDLED_FEE_TYPE = 443; uint256 internal constant BURN_FROM_ZERO = 444; uint256 internal constant INVALID_INPUT_ADDRESS = 445; + uint256 internal constant INVALID_OPERATION_TYPE = 446; // Vault uint256 internal constant INVALID_POOL_ID = 500; diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index fd8ff4e612..0ca5bc5ba6 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -426,8 +426,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu fee = userData.tokenInForExactBptOutCustomFee(); } } - } else { - if (operation == OperationType.EXIT) { + } else if (operation == OperationType.EXIT) { WeightedPoolUserData.ExitKind kind = userData.exitKind(); if (kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT) { fee = userData.exactBptInForTokenOutCustomFee(); @@ -436,11 +435,10 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu fee = userData.bptInForExactTokensOutCustomFee(); } } - } else { - if (operation == OperationType.SWAP) { - fee = userData.swapCustomFee(); - } - } + } else if (operation == OperationType.SWAP) { + fee = userData.swapCustomFee(); + } else { + _revert(Errors.INVALID_OPERATION_TYPE); } } else { fee = getSwapFeePercentage(); From e15ec3ba020beb7e87f7da602e13410e10cdd2f6 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Mon, 5 Feb 2024 15:50:12 -0300 Subject: [PATCH 16/19] Polish: getSwapFeePercentage only once, lint. --- .../contracts/BaseWeightedPool.sol | 54 ++++++++++++++----- pkg/pool-weighted/contracts/WeightedPool.sol | 16 +++--- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/pkg/pool-weighted/contracts/BaseWeightedPool.sol b/pkg/pool-weighted/contracts/BaseWeightedPool.sol index fb6261f38e..c2ae0a47b8 100644 --- a/pkg/pool-weighted/contracts/BaseWeightedPool.sol +++ b/pkg/pool-weighted/contracts/BaseWeightedPool.sol @@ -216,12 +216,14 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { (uint256 preJoinExitSupply, uint256 preJoinExitInvariant) = _beforeJoinExit(balances, normalizedWeights); + uint256 swapFeePercentage = getSwapFeePercentage(userData, OperationType.JOIN); (uint256 bptAmountOut, uint256[] memory amountsIn) = _doJoin( sender, balances, normalizedWeights, scalingFactors, preJoinExitSupply, + swapFeePercentage, userData ); @@ -233,7 +235,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT || kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT ) { - emit SwapFeePercentageChanged(getSwapFeePercentage(userData, OperationType.JOIN)); + emit SwapFeePercentageChanged(swapFeePercentage); } _afterJoinExit( @@ -259,14 +261,23 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { uint256[] memory normalizedWeights, uint256[] memory scalingFactors, uint256 totalSupply, + uint256 swapFeePercentage, bytes memory userData ) internal view virtual returns (uint256, uint256[] memory) { WeightedPoolUserData.JoinKind kind = userData.joinKind(); if (kind == WeightedPoolUserData.JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT) { - return _joinExactTokensInForBPTOut(balances, normalizedWeights, scalingFactors, totalSupply, userData); + return + _joinExactTokensInForBPTOut( + balances, + normalizedWeights, + scalingFactors, + totalSupply, + swapFeePercentage, + userData + ); } else if (kind == WeightedPoolUserData.JoinKind.TOKEN_IN_FOR_EXACT_BPT_OUT) { - return _joinTokenInForExactBPTOut(balances, normalizedWeights, totalSupply, userData); + return _joinTokenInForExactBPTOut(balances, normalizedWeights, totalSupply, swapFeePercentage, userData); } else if (kind == WeightedPoolUserData.JoinKind.ALL_TOKENS_IN_FOR_EXACT_BPT_OUT) { return _joinAllTokensInForExactBPTOut(balances, totalSupply, userData); } else { @@ -279,8 +290,9 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { uint256[] memory normalizedWeights, uint256[] memory scalingFactors, uint256 totalSupply, + uint256 swapFeePercentage, bytes memory userData - ) private view returns (uint256, uint256[] memory) { + ) private pure returns (uint256, uint256[] memory) { (uint256[] memory amountsIn, uint256 minBPTAmountOut) = userData.exactTokensInForBptOut(); InputHelpers.ensureInputLengthMatch(balances.length, amountsIn.length); @@ -291,7 +303,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights, amountsIn, totalSupply, - getSwapFeePercentage(userData, OperationType.JOIN) + swapFeePercentage ); _require(bptAmountOut >= minBPTAmountOut, Errors.BPT_OUT_MIN_AMOUNT); @@ -303,8 +315,9 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { uint256[] memory balances, uint256[] memory normalizedWeights, uint256 totalSupply, + uint256 swapFeePercentage, bytes memory userData - ) private view returns (uint256, uint256[] memory) { + ) private pure returns (uint256, uint256[] memory) { (uint256 bptAmountOut, uint256 tokenIndex) = userData.tokenInForExactBptOut(); // Note that there is no maximum amountIn parameter: this is handled by `IVault.joinPool`. @@ -315,7 +328,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights[tokenIndex], bptAmountOut, totalSupply, - getSwapFeePercentage(userData, OperationType.JOIN) + swapFeePercentage ); // We join in a single token, so we initialize amountsIn with zeros @@ -355,12 +368,14 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { (uint256 preJoinExitSupply, uint256 preJoinExitInvariant) = _beforeJoinExit(balances, normalizedWeights); + uint256 swapFeePercentage = getSwapFeePercentage(userData, OperationType.EXIT); (uint256 bptAmountIn, uint256[] memory amountsOut) = _doExit( sender, balances, normalizedWeights, scalingFactors, preJoinExitSupply, + swapFeePercentage, userData ); @@ -372,7 +387,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT || kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT ) { - emit SwapFeePercentageChanged(getSwapFeePercentage(userData, OperationType.EXIT)); + emit SwapFeePercentageChanged(swapFeePercentage); } _afterJoinExit( @@ -398,16 +413,25 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { uint256[] memory normalizedWeights, uint256[] memory scalingFactors, uint256 totalSupply, + uint256 swapFeePercentage, bytes memory userData ) internal view virtual returns (uint256, uint256[] memory) { WeightedPoolUserData.ExitKind kind = userData.exitKind(); if (kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT) { - return _exitExactBPTInForTokenOut(balances, normalizedWeights, totalSupply, userData); + return _exitExactBPTInForTokenOut(balances, normalizedWeights, totalSupply, swapFeePercentage, userData); } else if (kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT) { return _exitExactBPTInForTokensOut(balances, totalSupply, userData); } else if (kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT) { - return _exitBPTInForExactTokensOut(balances, normalizedWeights, scalingFactors, totalSupply, userData); + return + _exitBPTInForExactTokensOut( + balances, + normalizedWeights, + scalingFactors, + totalSupply, + swapFeePercentage, + userData + ); } else { _revert(Errors.UNHANDLED_EXIT_KIND); } @@ -417,8 +441,9 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { uint256[] memory balances, uint256[] memory normalizedWeights, uint256 totalSupply, + uint256 swapFeePercentage, bytes memory userData - ) private view returns (uint256, uint256[] memory) { + ) private pure returns (uint256, uint256[] memory) { (uint256 bptAmountIn, uint256 tokenIndex) = userData.exactBptInForTokenOut(); // Note that there is no minimum amountOut parameter: this is handled by `IVault.exitPool`. @@ -429,7 +454,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights[tokenIndex], bptAmountIn, totalSupply, - getSwapFeePercentage(userData, OperationType.EXIT) + swapFeePercentage ); // This is an exceptional situation in which the fee is charged on a token out instead of a token in. @@ -458,8 +483,9 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { uint256[] memory normalizedWeights, uint256[] memory scalingFactors, uint256 totalSupply, + uint256 swapFeePercentage, bytes memory userData - ) private view returns (uint256, uint256[] memory) { + ) private pure returns (uint256, uint256[] memory) { (uint256[] memory amountsOut, uint256 maxBPTAmountIn) = userData.bptInForExactTokensOut(); InputHelpers.ensureInputLengthMatch(amountsOut.length, balances.length); _upscaleArray(amountsOut, scalingFactors); @@ -470,7 +496,7 @@ abstract contract BaseWeightedPool is BaseMinimalSwapInfoPool { normalizedWeights, amountsOut, totalSupply, - getSwapFeePercentage(userData, OperationType.EXIT) + swapFeePercentage ); _require(bptAmountIn <= maxBPTAmountIn, Errors.BPT_IN_MAX_AMOUNT); diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index 0ca5bc5ba6..5caf5845b9 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -427,16 +427,16 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu } } } else if (operation == OperationType.EXIT) { - WeightedPoolUserData.ExitKind kind = userData.exitKind(); - if (kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT) { - fee = userData.exactBptInForTokenOutCustomFee(); - } else { - if (kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT) { - fee = userData.bptInForExactTokensOutCustomFee(); - } + WeightedPoolUserData.ExitKind kind = userData.exitKind(); + if (kind == WeightedPoolUserData.ExitKind.EXACT_BPT_IN_FOR_ONE_TOKEN_OUT) { + fee = userData.exactBptInForTokenOutCustomFee(); + } else { + if (kind == WeightedPoolUserData.ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT) { + fee = userData.bptInForExactTokensOutCustomFee(); } + } } else if (operation == OperationType.SWAP) { - fee = userData.swapCustomFee(); + fee = userData.swapCustomFee(); } else { _revert(Errors.INVALID_OPERATION_TYPE); } From f43fb93fa51288a7ed0cb2f6da5928b4e8d55e64 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Mon, 4 Mar 2024 19:16:17 -0300 Subject: [PATCH 17/19] Fix benchmarks. --- pvt/benchmarks/misc.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pvt/benchmarks/misc.ts b/pvt/benchmarks/misc.ts index 3f4a2efadf..e03bb3a62b 100644 --- a/pvt/benchmarks/misc.ts +++ b/pvt/benchmarks/misc.ts @@ -246,6 +246,11 @@ async function deployPoolFromFactory( if (poolName == 'ManagedPool') { receipt = await (await factory.connect(args.from).create(...args.parameters, ZERO_BYTES32)).wait(); event = receipt.events?.find((e) => e.event == 'PoolCreated'); + } else if (poolName == 'WeightedPool') { + receipt = await ( + await factory.connect(args.from).create(name, symbol, ...args.parameters, ZERO_ADDRESS, false, ZERO_BYTES32) + ).wait(); + event = receipt.events?.find((e) => e.event == 'PoolCreated'); } else { receipt = await ( await factory.connect(args.from).create(name, symbol, ...args.parameters, ZERO_ADDRESS, ZERO_BYTES32) From 00310a4d0604591537d89d4a48455e3e1420dab7 Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Mon, 4 Mar 2024 19:32:37 -0300 Subject: [PATCH 18/19] Fix stable tests. --- pkg/pool-stable/test/ComposableStablePoolFactory.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts b/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts index 7b3a7cf093..6e4a7b3518 100644 --- a/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts +++ b/pkg/pool-stable/test/ComposableStablePoolFactory.test.ts @@ -133,7 +133,7 @@ describe('ComposableStablePoolFactory', function () { }); it('sets swap fee', async () => { - expect(await pool.getSwapFeePercentage()).to.equal(POOL_SWAP_FEE_PERCENTAGE); + expect(await pool['getSwapFeePercentage()']()).to.equal(POOL_SWAP_FEE_PERCENTAGE); }); it('sets the owner ', async () => { From 8c5eb7e0ef2e11a790238e4e41c4ce9cfd2320da Mon Sep 17 00:00:00 2001 From: Juan Ignacio Ubeira Date: Mon, 4 Mar 2024 19:33:05 -0300 Subject: [PATCH 19/19] Update pkg/pool-weighted/contracts/WeightedPool.sol Co-authored-by: EndymionJkb --- pkg/pool-weighted/contracts/WeightedPool.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/pool-weighted/contracts/WeightedPool.sol b/pkg/pool-weighted/contracts/WeightedPool.sol index 5caf5845b9..f953c4d5e0 100644 --- a/pkg/pool-weighted/contracts/WeightedPool.sol +++ b/pkg/pool-weighted/contracts/WeightedPool.sol @@ -446,7 +446,7 @@ contract WeightedPool is BaseWeightedPool, WeightedPoolProtocolFees, CustomFeeAu } function setSwapFeePercentage(uint256 swapFeePercentage) public virtual override whenNotPaused { - // here msg.sender is used as this function directlly be called by the admin + // here msg.sender is used, as this function can be called directly by the admin // not via any other contract if (isCustomFeeEnabled()) { require(solver == msg.sender, "CALLER_IS_NOT_SOLVER");