DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Lack of Slippage Protection in GMX Order Execution

Summary

The system executes GMX orders without proper slippage protection, which exposes the protocol to high price slippage, potentially leading to unexpected losses for users.

Vulnerability Details

Vulnerable Code in _createIncreasePosition

function _createIncreasePosition(
bool _isLong,
uint256 acceptablePrice,
MarketPrices memory prices
) internal {
uint256 amountIn = collateralToken.balanceOf(address(this));
Order.OrderType orderType = Order.OrderType.MarketIncrease;
collateralToken.safeTransfer(address(gmxProxy), amountIn);
uint256 sizeDelta = prices.shortTokenPrice.max * amountIn * leverage / BASIS_POINTS_DIVISOR;
IGmxProxy.OrderData memory orderData = IGmxProxy.OrderData({
market: market,
indexToken: indexToken,
initialCollateralToken: address(collateralToken),
swapPath: new address isLong: _isLong,
sizeDeltaUsd: sizeDelta,
initialCollateralDeltaAmount: 0,
amountIn: amountIn,
callbackGasLimit: callbackGasLimit,
acceptablePrice: acceptablePrice, // Acceptable price is not properly adjusted
minOutputAmount: 0 // No slippage protection applied
});
_gmxLock = true;
gmxProxy.createOrder(orderType, orderData);
}
  • minOutputAmount is set to 0, meaning the order will execute at any price, even if it's highly unfavorable.

  • No explicit slippage tolerance is set, meaning users could receive much worse execution prices than intended.

PoC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import "../src/GmxProxy.sol";
import "../src/PerpetualVault.sol";
import "../src/interfaces/IGmxProxy.sol";
import "../src/interfaces/IPerpetualVault.sol";
import "../src/interfaces/IVaultReader.sol";
import "../src/libraries/StructData.sol";
import "../src/libraries/gmx/MarketUtils.sol";
contract SlippageProtectionTest is Test {
GmxProxy gmxProxy;
PerpetualVault vault;
address user = address(0x123);
address attacker = address(0x456);
IERC20 public collateralToken;
IERC20 public indexToken;
function setUp() public {
// Deploy Mock GMX Proxy
gmxProxy = new GmxProxy(
address(this),
address(this),
address(this),
address(this),
address(this),
address(this),
address(this),
address(this),
address(this)
);
// Deploy Vault
vault = new PerpetualVault(
address(this),
address(this),
address(this),
address(gmxProxy),
address(this),
100 * 1e18, // min deposit
10000 * 1e18, // max deposit
10 * 1e18 // leverage
);
// Assign mock tokens
collateralToken = IERC20(address(new MockERC20("USDC", "USDC", 6)));
indexToken = IERC20(address(new MockERC20("ETH", "ETH", 18)));
// Mint tokens to user
deal(address(collateralToken), user, 1000 * 1e6);
}
function testLackOfSlippageProtection() public {
vm.startPrank(user);
// Approve and deposit USDC into Vault
collateralToken.approve(address(vault), 1000 * 1e6);
vault.deposit(1000 * 1e6);
// Simulate price of index token dropping by 20%
uint256 oldPrice = 2000 * 1e18;
uint256 newPrice = 1600 * 1e18;
MarketPrices memory prices = MarketPrices({
indexTokenPrice: PriceProps({ min: oldPrice, max: oldPrice }),
longTokenPrice: PriceProps({ min: oldPrice, max: oldPrice }),
shortTokenPrice: PriceProps({ min: oldPrice, max: oldPrice })
});
// Open position with no slippage protection
vault.run(true, true, prices, new bytes // Now force the price to change (Simulating Oracle Manipulation or Market Movement)
prices.indexTokenPrice = PriceProps({ min: newPrice, max: newPrice });
// Process next action without slippage protection
vault.runNextAction(prices, new bytes );
// Expect user to receive much worse execution price
uint256 expectedLoss = (2000 - 1600) * 1e18 / oldPrice;
console.log("User lost:", expectedLoss);
vm.stopPrank();
}
}

Impact

  • Users may suffer large unexpected losses due to price slippage.

  • Market manipulators could force bad execution prices for orders placed through this contract.

  • The protocol's reputation could be damaged if users experience consistent losses due to poor trade execution.

Tools Used

Manual review, Foundry

Recommendations

  • Implement a dynamic slippage protection mechanism based on market volatility.

  • Set minOutputAmount dynamically based on expected execution price and a reasonable slippage threshold.

  • Allow users to specify acceptable slippage percentages when interacting with the vault.

Updates

Lead Judging Commences

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_gmx_increase/decrease_no_slippage

acceptablePrice does that job for increase/decrease positions. https://github.com/gmx-io/gmx-synthetics/blob/caf3dd8b51ad9ad27b0a399f668e3016fd2c14df/contracts/order/BaseOrderUtils.sol#L276C49-L276C66

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.