Add split receive option to TWAP decrease and TP/SL order creation FEDEV-3918#2580
Add split receive option to TWAP decrease and TP/SL order creation FEDEV-3918#2580qwinndev wants to merge 13 commits into
Conversation
Deploying gmx-interface with
|
| Latest commit: |
d155f60
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://84fc626e.gmx-interface.pages.dev |
| Branch Preview URL: | https://split-receive-twap-tpsl.gmx-interface.pages.dev |
Deploying gmx-interface-home with
|
| Latest commit: |
d155f60
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://55c15e69.gmx-interface-home.pages.dev |
| Branch Preview URL: | https://split-receive-twap-tpsl.gmx-interface-home.pages.dev |
…-tpsl # Conflicts: # src/components/OrdersModal/AddTPSLModal.tsx # src/domain/synthetics/sidecarOrders/__tests__/utils.spec.ts # src/domain/synthetics/sidecarOrders/utils.ts
| if (slTriggerPrice === undefined || !getIsPositionInfoLoaded(position)) { | ||
| return undefined; | ||
| } | ||
| const receiveSwapType = isReceiveSeparated ? DecreasePositionSwapType.NoSwap : undefined; |
There was a problem hiding this comment.
This choice doesn't survive the replace path. buildTpSlBatchPayloads replaces an existing full-close order via buildUpdateOrderPayload (sidecar.ts:310), and updateOrder can't change decreasePositionSwapType — it only carries size/prices/minOutput/autoCancel/validFrom. The modal defaults to 100% size, so isFullClose is almost always true, and the typical flow becomes: user has an existing full-close TP (created with the swap default), re-opens the modal, sets a new price, toggles "Receive X and Y separately" — the preview shows the split, but the submitted update keeps the old order's swap type, and execution swaps the profit anyway. The reverse holds too: an inline-created NoSwap TP edited without the toggle previews single-token receive but executes as split.
A preview contradicting the actual payload in a money modal is the bad kind of quiet. Since update can't carry the field, the replace path needs cancel+create whenever the swap type differs — the batch already supports cancelOrderParams (currently hardcoded [] here).
| triggerOrderType: OrderType, | ||
| position: PositionInfo | undefined | ||
| ): DecreasePositionSwapType | undefined { | ||
| if (triggerOrderType === OrderType.LimitDecrease && getCanSplitReceive(position)) { |
There was a problem hiding this comment.
The Jun 26 follow-up on the Linear issue asks for inline TP/SL to default to split receive — this only covers TP (LimitDecrease). An SL isn't guaranteed to execute at a loss: stop-in-profit above entry is a normal setup, and there the profit still gets force-swapped — exactly the "unexpected internal conversion" that follow-up wants to rule out. For a losing fill NoSwap is equivalent anyway (no profit to swap), so including StopLossDecrease changes nothing else.
If TP-only is a deliberate product call, let's record it on the Linear issue and in a comment here. Either way the PR description still says "Default behavior is unchanged" — worth syncing it with this change.
| swapProfitFee: fees?.swapProfitFee, | ||
| }); | ||
|
|
||
| const twapSplitReceiveSwapProfitFeeWarning = getSplitReceiveSwapProfitFeeWarning({ |
There was a problem hiding this comment.
receiveToken is hardcoded to collateral here, but the actual TWAP legs are built from selectPositionSellerReceiveToken, which can still return a token picked on the Market tab this session or the persisted defaultReceiveToken from localStorage (saved per market+direction+collateral on every successful close). So a user who once closed this position into BTC gets TWAP legs carrying a USDC→BTC swapPath, while the new receive row shows collateral amounts and this warning talks about "Receiving as USDC". Execution was the same before the PR — but TWAP didn't render a Receive row at all, so the UI couldn't contradict the payload; now it can.
Since TWAP deliberately has no receive selector and all the new UI assumes collateral, I'd pin the effective receive token to collateral for TWAP in the selector itself — that fixes the optimal-decrease pick, swapPath, batch params and this copy in one place.
Playwright Component Test ReportAll tests passed. Commit d155f60 |
Summary
Extends the split-receive option (return PnL token + collateral token separately, with no internal PnL→collateral swap) — already shipped for plain close/decrease in FEDEV-3460 — to two more flows:
AddTPSLModal)For markets where collateral and PnL tokens differ (e.g. a WBTC-backed long paying PnL in WBTC), users can now avoid the forced internal swap — and its swap-profit fee — on every scheduled fill, and see the choice up front.
This effectively restores the TWAP/TP-SL split-receive that was added and then reverted within the FEDEV-3460 PR (#2500, revert
4aa45475e5), adapted to current code.What changed
decreasePositionSwapTypeper TWAP leg (orderTransactions/utils.ts) and per TP/SL order (sidecar.ts), so the receive preference is honored on every scheduled fill automatically — settingdecreaseAmounts.decreaseSwapType = NoSwapis all that's needed.PositionSeller.tsx,positionSellerSelectors.ts): removed the twoTradeMode.Twapguards, un-gated the split toggle and auto-clear effect, and added a read-only Receive row (Option A — no token selector for TWAP).AddTPSLModal.tsx): re-added theisReceiveSeparatedstate,forceDecreaseSwapType: NoSwapamounts, split-receive availability, output preview, and toggle. Submit path unchanged.getIsHighSwapProfitFeehelper fromusePriceImpactWarningState(behavior-preserving) and use it to gate a dedicated "high swap profit fee → use split receive"AlertInfoCardin both new flows.FEDEV-3918