sherlock-audit / 2023-04-gmx-judging

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

stent - poolAmountAdjustment set but not unset in swapProfitToCollateralToken

sherlock-admin opened this issue · comments

stent

high

poolAmountAdjustment set but not unset in swapProfitToCollateralToken

Summary

In DecreasePositionCollateralUtils.swapProfitToCollateralToken poolAmountAdjustment is increased before the swap but only decreased if the swap fails.

Vulnerability Detail

poolAmountAdjustment is set to poolAmountDelta in DecreasePositionCollateralUtils.swapProfitToCollateralToken. If the swap fails then the value is set to 0 again, but if the swap is successful the value is left as poolAmountDelta.

poolAmountAdjustment is used to calculate the next pool amounts in SwapPriceingUtils.getNextPoolAmountsParams. Any call path involving a swap will be affected since the price impact calculation depends on SwapPricingUtils.getPriceImpactUsd(viaSwapUtils._swap`).

Impact

If the poolAmountAdjustment value is not set to 0 then it will cause the accounting to be wrong for the price impact calculation which affects fees etc that the user pays. The large poolAmountAdjustment is the more fees subsequent users could pay.

Code Snippet

            params.contracts.dataStore.setInt(Keys.poolAmountAdjustmentKey(params.market.marketToken, pnlToken), poolAmountDelta);

            try params.contracts.swapHandler.swap(
                SwapUtils.SwapParams(
                    params.contracts.dataStore,
                    params.contracts.eventEmitter,
                    params.contracts.oracle,
                    Bank(payable(params.market.marketToken)),
                    params.orderKey,
                    pnlToken, // tokenIn
                    profitAmount, // amountIn
                    swapPathMarkets, // markets
                    0, // minOutputAmount
                    params.market.marketToken, // receiver
                    params.order.uiFeeReceiver(), // uiFeeReceiver
                    false // shouldUnwrapNativeToken
                )
            ) returns (address /* tokenOut */, uint256 swapOutputAmount) {
                return (true, swapOutputAmount);
            } catch Error(string memory reason) {
                emit SwapUtils.SwapReverted(reason, "");
            } catch (bytes memory reasonBytes) {
                (string memory reason, /* bool hasRevertMessage */) = ErrorUtils.getRevertMessage(reasonBytes);
                emit SwapUtils.SwapReverted(reason, reasonBytes);
            }

            params.contracts.dataStore.setInt(Keys.poolAmountAdjustmentKey(params.market.marketToken, pnlToken), 0);

https://github.com/gmx-io/gmx-synthetics/blob/a2e331f6d0a3b59aaac5ead975b206840369a723/contracts/pricing/SwapPricingUtils.sol#L208

// contract & func: SwapUtil._swap

        int256 priceImpactUsd = SwapPricingUtils.getPriceImpactUsd(
            SwapPricingUtils.GetPriceImpactUsdParams(
                params.dataStore,
                _params.market,
                _params.tokenIn,
                cache.tokenOut,
                cache.tokenInPrice.midPrice(),
                cache.tokenOutPrice.midPrice(),
                (fees.amountAfterFees * cache.tokenInPrice.midPrice()).toInt256(),
                -(fees.amountAfterFees * cache.tokenInPrice.midPrice()).toInt256()
            )
        );

https://github.com/gmx-io/gmx-synthetics/blob/a2e331f6d0a3b59aaac5ead975b206840369a723/contracts/swap/SwapUtils.sol#LL217C16-L217C23

Tool used

Manual Review

Recommendation

Set poolAmountAdjustment to 0 for successful swaps.

Duplicate of #235