Description
The _createIncreasePosition function contains an incorrect calculation of sizeDelta, which does not account for token decimals correctly. Additionally, this issue prevents users from depositing into an open position.
Incorrect sizeDelta Calculation
The formula used in _createIncreasePosition is:
uint256 sizeDelta = prices.shortTokenPrice.max * amountIn * leverage / BASIS_POINTS_DIVISOR;
If the short token is USDC (6 decimals):
amountIn is in 1e6
shortTokenPrice.max is 1e8
With leverage of 2x (20,000 basis points), the resulting sizeDelta is incorrectly scaled to 1e14 instead of 1e8 (USD units).
The incorrect sizeDelta leads to an invalid fee calculation in afterOrderExecution, causing a revert due to excessive fee deduction.
function _createIncreasePosition(
bool _isLong,
uint256 acceptablePrice,
MarketPrices memory prices
) internal {
uint256 amountIn;
if (flow == FLOW.DEPOSIT) {
amountIn = depositInfo[counter].amount;
flowData = vaultReader.getPositionSizeInTokens(curPositionKey);
} else {
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[](0),
isLong: _isLong,
sizeDeltaUsd: sizeDelta,
initialCollateralDeltaAmount: 0,
amountIn: amountIn,
callbackGasLimit: callbackGasLimit,
acceptablePrice: acceptablePrice,
minOutputAmount: 0
});
_gmxLock = true;
gmxProxy.createOrder(orderType, orderData);
}
Users Cannot Deposit into an Open Position
The incorrect sizeDelta affects afterOrderExecution, where feeAmount is miscalculated:
function afterOrderExecution(
bytes32 requestKey,
bytes32 positionKey,
IGmxProxy.OrderResultData memory orderResultData,
MarketPrices memory prices
) external nonReentrant {
if (msg.sender != address(gmxProxy)) {
revert Error.InvalidCall();
}
_gmxLock = false;
if (orderResultData.isSettle) {
nextAction.selector = NextActionSelector.WITHDRAW_ACTION;
emit GmxPositionCallbackCalled(requestKey, true);
return;
}
if (orderResultData.orderType == Order.OrderType.MarketIncrease) {
curPositionKey = positionKey;
if (flow == FLOW.DEPOSIT) {
uint256 amount = depositInfo[counter].amount;
@=> uint256 feeAmount = vaultReader.getPositionFeeUsd(market, orderResultData.sizeDeltaUsd, false) / prices.shortTokenPrice.min;
uint256 prevSizeInTokens = flowData;
int256 priceImpact = vaultReader.getPriceImpactInCollateral(curPositionKey, orderResultData.sizeDeltaUsd, prevSizeInTokens, prices);
uint256 increased;
if (priceImpact > 0) {
@=> increased = amount - feeAmount - uint256(priceImpact) - 1;
} else {
increased = amount - feeAmount + uint256(-priceImpact) - 1;
}
_mint(counter, increased, false, prices);
nextAction.selector = NextActionSelector.FINALIZE;
uint256 feeAmount = vaultReader.getPositionFeeUsd(market, orderResultData.sizeDeltaUsd, false) / prices.shortTokenPrice.min;
12000e30/1e8 = 12000e22
function getPositionFeeUsd(address market, uint256 sizeDeltaUsd, bool forPositiveImpact) external view returns (uint256 positionFeeAmount) {
uint256 positionFeeFactor = dataStore.getUint(keccak256(abi.encode(
POSITION_FEE_FACTOR,
market,
forPositiveImpact
)));
positionFeeAmount = sizeDeltaUsd * positionFeeFactor / PRECISION;
}
}
Because sizeDeltaUsd is too large, the feeAmount becomes excessively high, leading to a transaction revert when subtracting amount - feeAmount.
As a result, deposits into an open position fail due to incorrect calculations and fee deductions.
Impact
No one will be able to deposit in the position also.
Transaction Failures: Increasing positions fails due to incorrect sizeDelta.
Excessive Fees: If not reverted, the system may overcharge users.
Operational Disruption: Prevents proper leverage trading.
Users Cannot Deposit in an Open Position
Deposits Fail: Users cannot add collateral to an active position.
Trading Restriction: Prevents users from increasing exposure after opening a position.
Platform Inefficiency: Reduces flexibility and usability of the trading system.
Recommendation
A proper recommendation can't be suggested but modify the sizeDelta calculation or the feeAmount calculation so it does not revert.