* @notice Callback function that is called when an order on GMX is executed successfully.
* This function handles the post-execution logic based on the type of order that was executed.
* @dev This callback function must never be reverted. It should wrap revertible external calls with `try-catch`.
* @param requestKey The request key of the executed order.
* @param positionKey The position key.
* @param orderResultData Data from the order execution.
*/
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;
} else {
_updateState(false, orderResultData.isLong);
}
} else if (orderResultData.orderType == Order.OrderType.MarketDecrease) {
uint256 sizeInUsd = vaultReader.getPositionSizeInUsd(curPositionKey);
if (sizeInUsd == 0) {
delete curPositionKey;
}
if (flow == FLOW.WITHDRAW) {
nextAction.selector = NextActionSelector.FINALIZE;
uint256 prevCollateralBalance = collateralToken.balanceOf(address(this)) - orderResultData.outputAmount;
nextAction.data = abi.encode(prevCollateralBalance, sizeInUsd == 0, false);
} else {
_updateState(true, false);
}
} else if (orderResultData.orderType == Order.OrderType.MarketSwap) {
uint256 outputAmount = orderResultData.outputAmount;
if (swapProgressData.isCollateralToIndex) {
emit GmxSwap(
address(collateralToken),
swapProgressData.remaining,
indexToken,
outputAmount,
true
);
} else {
emit GmxSwap(
indexToken,
swapProgressData.remaining,
address(collateralToken),
outputAmount,
false
);
}
if (flow == FLOW.DEPOSIT) {
_mint(counter, outputAmount + swapProgressData.swapped, false, prices);
_finalize(hex'');
} else if (flow == FLOW.WITHDRAW) {
_handleReturn(outputAmount + swapProgressData.swapped, false, false);
} else {
if (orderResultData.outputToken == indexToken) {
_updateState(false, true);
} else {
_updateState(true, false);
}
}
}
emit GmxPositionCallbackCalled(requestKey, true);
if (flow == FLOW.SIGNAL_CHANGE) {
emit GmxPositionUpdated(
positionKey,
market,
orderResultData.orderType == Order.OrderType.MarketIncrease,
orderResultData.isLong,
orderResultData.sizeDeltaUsd,
prices.indexTokenPrice.min
);
}
}
This is incorrect because a negative price impact means the execution price is worse, effectively decreasing the value of the collateral. This should be reflected in the shares minted, the user should get less value for their deposit, not more.
Depositors receive more shares than they should when the price impact is unfavorable (negative), which is unfair and inconsistent with the intended vault mechanics.