From 5b7f6ad42981c2f5b283fbf675d5b9905627893a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 5 Sep 2022 12:05:51 -0500 Subject: [PATCH] Prevent invariant overflow (#1690) * Add check to prevent invariant overflow * Update pkg/pool-stable/contracts/ComposableStablePoolProtocolFees.sol Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- .../ComposableStablePoolProtocolFees.sol | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/pkg/pool-stable/contracts/ComposableStablePoolProtocolFees.sol b/pkg/pool-stable/contracts/ComposableStablePoolProtocolFees.sol index 49f256fa78..01cc737928 100644 --- a/pkg/pool-stable/contracts/ComposableStablePoolProtocolFees.sol +++ b/pkg/pool-stable/contracts/ComposableStablePoolProtocolFees.sol @@ -258,15 +258,32 @@ abstract contract ComposableStablePoolProtocolFees is uint256 postJoinExitInvariant = StableMath._calculateInvariant(currentAmp, balances); - uint256 protocolFeeAmount = InvariantGrowthProtocolSwapFees.calcDueProtocolFees( - postJoinExitInvariant.divDown(preJoinExitInvariant), - preJoinExitSupply, - postJoinExitSupply, - getProtocolFeePercentageCache(ProtocolFeeType.SWAP) - ); + // Compute the portion of the invariant increase due to fees + uint256 supplyGrowthRatio = postJoinExitSupply.divDown(preJoinExitSupply); + uint256 feelessInvariant = preJoinExitInvariant.mulDown(supplyGrowthRatio); + + // The postJoinExitInvariant should always be greater than the feelessInvariant (since the invariant and total + // supply move proportionally outside of fees, which the postJoinInvariant includes and the feelessInvariant + // does not). However, in the unexpected case in which due to rounding errors this is not true, we simply skip + // further computation of protocol fees. + if (postJoinExitInvariant > feelessInvariant) { + uint256 invariantDeltaFromFees = postJoinExitInvariant - feelessInvariant; + + // To convert to a percentage of pool ownership, multiply by the rate, + // then normalize against the final invariant + uint256 protocolOwnershipPercentage = Math.divDown( + Math.mul(invariantDeltaFromFees, getProtocolFeePercentageCache(ProtocolFeeType.SWAP)), + postJoinExitInvariant + ); - if (protocolFeeAmount > 0) { - _payProtocolFees(protocolFeeAmount); + if (protocolOwnershipPercentage > 0) { + uint256 protocolFeeAmount = _calculateAdjustedProtocolFeeAmount( + postJoinExitSupply, + protocolOwnershipPercentage + ); + + _payProtocolFees(protocolFeeAmount); + } } _updatePostJoinExit(currentAmp, postJoinExitInvariant);