* @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 positive price impact means the execution price is better, effectively increasing the value of the collateral. This benefit should be reflected in the shares minted, the user should get more value for their deposit, not less.
Depositors receive fewer shares than they should when the price impact is beneficial (positive), which is unfair and inconsistent with the intended vault mechanics.