Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowed Slippage for limit swaps #1451

Open
wants to merge 5 commits into
base: release-53
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/src/configs/factors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export const HIGH_PRICE_IMPACT_BPS = 80; // 0.8%
export const HIGH_POSITION_IMPACT_BPS = 50; // 0.5%
export const HIGH_COLLATERAL_IMPACT_BPS = 500; // 5%
export const HIGH_SWAP_IMPACT_BPS = 50; // 0.5%
export const DEFAULT_ACCEPABLE_PRICE_IMPACT_BUFFER = 30; // 0.3%
export const DEFAULT_ACCEPTABLE_PRICE_IMPACT_BUFFER = 30; // 0.3%
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.AcceptablePriceImpactInputRow-handle {
.AcceptablePriceImpactInputRow-handle,
.AllowedSwapSlippageInputRow-handle {
z-index: 1;
cursor: pointer;
position: relative;
Expand All @@ -17,6 +18,6 @@
}
}

.AcceptablePriceImpactInputRow-na {
.AcceptablePriceImpactInputRow-na .AllowedSwapSlippageInputRow-na {
line-height: 2.3rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import ExchangeInfoRow from "components/Exchange/ExchangeInfoRow";
import PercentageInput from "components/PercentageInput/PercentageInput";

import { bigMath } from "lib/bigmath";

import "./AcceptablePriceImpactInputRow.scss";

type Props = {
Expand Down Expand Up @@ -82,8 +83,8 @@ function AcceptablePriceImpactInputRowImpl({
priceImpactFeeBps >= 0 ? (
<p>
<Trans>
The current Price Impact is {formatPercentage(priceImpactFeeBps, { signed: true })}. Consider using -0.30%
Acceptable Price Impact so the order is more likely to be processed.
The current price impact is {formatPercentage(priceImpactFeeBps, { signed: true })}. Consider using -0.30%
acceptable price impact so the order is more likely to be processed.
</Trans>
<br />
<br />
Expand All @@ -92,7 +93,7 @@ function AcceptablePriceImpactInputRowImpl({
) : (
<p>
<Trans>
The Current Price Impact is {formatPercentage(priceImpactFeeBps, { signed: true })}. Consider adding a buffer
The current price impact is {formatPercentage(priceImpactFeeBps, { signed: true })}. Consider adding a buffer
of 0.30% to it so the order is more likely to be processed.
</Trans>
<br />
Expand All @@ -104,7 +105,7 @@ function AcceptablePriceImpactInputRowImpl({
const highValueWarningText = (
<p>
<Trans>
You have set a high Acceptable Price Impact. The current Price Impact is{" "}
You have set a high acceptable price impact. The current price impact is{" "}
{formatPercentage(priceImpactFeeBps, { signed: true })}.
</Trans>
<br />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { Trans, t } from "@lingui/macro";
import { memo, useCallback, useMemo } from "react";

import { HIGH_ALLOWED_SWAP_SLIPPAGE_BPS } from "config/factors";
import { formatPercentage } from "lib/numbers";

import ExchangeInfoRow from "components/Exchange/ExchangeInfoRow";
import PercentageInput from "components/PercentageInput/PercentageInput";

import "../AcceptablePriceImpactInputRow/AcceptablePriceImpactInputRow.scss";

type Props = {
allowedSwapSlippageBps?: bigint;
recommendedAllowedSwapSlippageBps?: bigint;
initialSwapImpactFeeBps?: bigint;
setAllowedSwapSlippageBps: (value: bigint) => void;
totalSwapImpactBps: bigint;
notAvailable?: boolean;
Copy link
Collaborator

@divhead divhead Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not critial, but, probably rename it to “disabled”? would be a more familiar name

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this inherited from AcceptableSwapImpact component, and I think naming is ok cuz it will render N/A, it's differs from just disabled state

className?: string;
};

const EMPTY_SUGGESTIONS: number[] = [];

function AllowedSwapSlippageInputRowImpl({
allowedSwapSlippageBps,
recommendedAllowedSwapSlippageBps = allowedSwapSlippageBps,
initialSwapImpactFeeBps = allowedSwapSlippageBps,
setAllowedSwapSlippageBps,
notAvailable = false,
totalSwapImpactBps,
className,
}: Props) {
const setValue = useCallback(
(value: number | undefined) => {
setAllowedSwapSlippageBps(BigInt(value ?? 0));
},
[setAllowedSwapSlippageBps]
);

const recommendedValue =
recommendedAllowedSwapSlippageBps !== undefined ? Number(recommendedAllowedSwapSlippageBps) : undefined;
const initialValue = initialSwapImpactFeeBps !== undefined ? Number(initialSwapImpactFeeBps) : undefined;
const value = allowedSwapSlippageBps !== undefined ? Number(allowedSwapSlippageBps) : undefined;

const highValue = useMemo(() => {
if (recommendedValue === undefined) {
return undefined;
}

return HIGH_ALLOWED_SWAP_SLIPPAGE_BPS + recommendedValue;
}, [recommendedValue]);

const handleRecommendedValueClick = useCallback(() => {
setValue(recommendedValue);
}, [recommendedValue, setValue]);

if (notAvailable || recommendedValue === undefined || initialValue === undefined) {
return (
<ExchangeInfoRow label={t`Allowed Slippage`}>
<span className="AllowedSwapSlippageInputRow-na">{t`NA`}</span>
</ExchangeInfoRow>
);
}

const recommendedHandle = (
<Trans>
<span className="AllowedSwapSlippageInputRow-handle" onClick={handleRecommendedValueClick}>
Set Recommended Impact: {formatPercentage(BigInt(recommendedValue) * -1n, { signed: true })}
</span>
.
</Trans>
);

const lowValueWarningText = (
<p>
<Trans>
The current swap impact including fees is {formatPercentage(totalSwapImpactBps, { signed: true })}. Consider
adding a buffer of 1% to it so the order is more likely to be processed
</Trans>
<br />
<br />
{recommendedHandle}
</p>
);

const highValueWarningText = (
<p>
<Trans>
You have set a high allowed slippage. The current swap impact including fees is{" "}
{formatPercentage(totalSwapImpactBps, { signed: true })}.
</Trans>
<br />
<br />
{recommendedHandle}
</p>
);

return (
<ExchangeInfoRow className={className} label={t`Allowed Slippage`}>
<PercentageInput
onChange={setValue}
defaultValue={initialValue}
value={value}
highValue={highValue}
highValueCheckStrategy="gt"
lowValue={recommendedValue}
suggestions={EMPTY_SUGGESTIONS}
highValueWarningText={highValueWarningText}
lowValueWarningText={lowValueWarningText}
negativeSign
tooltipPosition="bottom-end"
/>
</ExchangeInfoRow>
);
}

export const AllowedSwapSlippageInputRow = memo(
AllowedSwapSlippageInputRowImpl
) as typeof AllowedSwapSlippageInputRowImpl;
42 changes: 34 additions & 8 deletions src/components/Synthetics/TradeBox/TradeBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import {
selectTradeboxNextPositionValues,
selectTradeboxSelectedPosition,
selectTradeboxSelectedPositionKey,
selectTradeboxSetDefaultAllowedSwapSlippageBps,
selectTradeboxSetSelectedAllowedSwapSlippageBps,
selectTradeboxState,
selectTradeboxSwapAmounts,
selectTradeboxToTokenAmount,
Expand Down Expand Up @@ -113,7 +115,7 @@ import { useRequiredActions } from "./hooks/useRequiredActions";
import { useTPSLSummaryExecutionFee } from "./hooks/useTPSLSummaryExecutionFee";
import { useTradeboxButtonState } from "./hooks/useTradeButtonState";
import { useTradeboxWarningsRows } from "./hooks/useTradeWarningsRows";
import { useTradeboxAvailablePriceImpactValues } from "./hooks/useTradeboxAvailablePriceImpactValues";
import { useTradeboxAcceptablePriceImpactValues } from "./hooks/useTradeboxAcceptablePriceImpactValues";
import { useTradeboxTPSLReset } from "./hooks/useTradeboxTPSLReset";
import { useTradeboxTransactions } from "./hooks/useTradeboxTransactions";
import { useTriggerOrdersConsent } from "./hooks/useTriggerOrdersConsent";
Expand Down Expand Up @@ -178,6 +180,9 @@ export function TradeBox(p: Props) {
const localizedTradeTypeLabels = useLocalizedMap(tradeTypeLabels);

const avaialbleTokenOptions = useSelector(selectTradeboxAvailableTokensOptions);
const setDefaultAllowedSwapSlippageBps = useSelector(selectTradeboxSetDefaultAllowedSwapSlippageBps);
const setSelectedAllowedSwapSlippageBps = useSelector(selectTradeboxSetSelectedAllowedSwapSlippageBps);

const chartHeaderInfo = useSelector(selectChartHeaderInfo);
const formRef = useRef<HTMLFormElement>(null);
const isCursorInside = useCursorInside(formRef);
Expand Down Expand Up @@ -305,24 +310,44 @@ export function TradeBox(p: Props) {
const setIsHighSwapImpactAcceptedRef = useLatest(priceImpactWarningState.setIsHighSwapImpactAccepted);

const setFromTokenInputValue = useCallback(
(value: string, shouldResetPriceImpactWarning: boolean) => {
(value: string, resetPriceImpactAndSwapSlippage?: boolean) => {
setFromTokenInputValueRaw(value);
if (shouldResetPriceImpactWarning) {

if (resetPriceImpactAndSwapSlippage) {
setIsHighPositionImpactAcceptedRef.current(false);
setIsHighSwapImpactAcceptedRef.current(false);

setDefaultAllowedSwapSlippageBps(undefined);
setSelectedAllowedSwapSlippageBps(undefined);
}
},
[setFromTokenInputValueRaw, setIsHighPositionImpactAcceptedRef, setIsHighSwapImpactAcceptedRef]
[
setFromTokenInputValueRaw,
setIsHighPositionImpactAcceptedRef,
setIsHighSwapImpactAcceptedRef,
setDefaultAllowedSwapSlippageBps,
setSelectedAllowedSwapSlippageBps,
]
);
const setToTokenInputValue = useCallback(
(value: string, shouldResetPriceImpactWarning: boolean) => {
(value: string, shouldPriceImpactAndSwapSlippage: boolean) => {
setToTokenInputValueRaw(value);
if (shouldResetPriceImpactWarning) {

if (shouldPriceImpactAndSwapSlippage) {
setIsHighPositionImpactAcceptedRef.current(false);
setIsHighSwapImpactAcceptedRef.current(false);

setDefaultAllowedSwapSlippageBps(undefined);
setSelectedAllowedSwapSlippageBps(undefined);
}
},
[setToTokenInputValueRaw, setIsHighPositionImpactAcceptedRef, setIsHighSwapImpactAcceptedRef]
[
setToTokenInputValueRaw,
setIsHighPositionImpactAcceptedRef,
setIsHighSwapImpactAcceptedRef,
setDefaultAllowedSwapSlippageBps,
setSelectedAllowedSwapSlippageBps,
]
);

const userReferralInfo = useUserReferralInfo();
Expand Down Expand Up @@ -668,7 +693,7 @@ export function TradeBox(p: Props) {
const { requiredActions } = useRequiredActions();
const subaccount = useSubaccount(summaryExecutionFee?.feeTokenAmount ?? null, requiredActions);

useTradeboxAvailablePriceImpactValues();
useTradeboxAcceptablePriceImpactValues();
useTradeboxTPSLReset(setTriggerConsent);

const prevIsISwap = usePrevious(isSwap);
Expand Down Expand Up @@ -904,6 +929,7 @@ export function TradeBox(p: Props) {
if (swapPathStats) {
// eslint-disable-next-line no-console
console.log("Swap Path", {
steps: swapPathStats.swapSteps,
path: swapPathStats.swapPath.map((marketAddress) => marketsInfoData?.[marketAddress]?.name).join(" -> "),
priceImpact: swapPathStats.swapSteps.map((step) => formatDeltaUsd(step.priceImpactDeltaUsd)).join(" -> "),
usdOut: swapPathStats.swapSteps.map((step) => formatUsd(step.usdOut)).join(" -> "),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,25 @@ import { ValueTransition } from "components/ValueTransition/ValueTransition";
import {
selectTradeboxAdvancedOptions,
selectTradeboxDecreasePositionAmounts,
selectTradeboxDefaultAllowedSwapSlippageBps,
selectTradeboxDefaultTriggerAcceptablePriceImpactBps,
selectTradeboxFees,
selectTradeboxIncreasePositionAmounts,
selectTradeboxIsLeverageEnabled,
selectTradeboxKeepLeverage,
selectTradeboxLeverage,
selectTradeboxNextPositionValues,
selectTradeboxSelectedAllowedSwapSlippageBps,
selectTradeboxSelectedPosition,
selectTradeboxSelectedTriggerAcceptablePriceImpactBps,
selectTradeboxSetAdvancedOptions,
selectTradeboxSetKeepLeverage,
selectTradeboxSetSelectedAcceptablePriceImpactBps,
selectTradeboxSetSelectedAllowedSwapSlippageBps,
selectTradeboxTotalSwapImpactBps,
selectTradeboxTradeFlags,
selectTradeboxTriggerPrice,
selectTradeboxTriggerRatioInputValue,
} from "context/SyntheticsStateContext/selectors/tradeboxSelectors";
import { selectTradeboxCollateralSpreadInfo } from "context/SyntheticsStateContext/selectors/tradeboxSelectors/selectTradeboxCollateralSpreadInfo";
import { selectTradeboxLiquidityInfo } from "context/SyntheticsStateContext/selectors/tradeboxSelectors/selectTradeboxLiquidityInfo";
Expand All @@ -35,28 +40,47 @@ import { AvailableLiquidityRow } from "./AvailableLiquidityRow";
import { CollateralSpreadRow } from "./CollateralSpreadRow";
import { EntryPriceRow } from "./EntryPriceRow";
import { SwapSpreadRow } from "./SwapSpreadRow";
import { useTradeboxAllowedSwapSlippageValues } from "../hooks/useTradeboxAllowedSwapSlippageValues";
import { AllowedSwapSlippageInputRow } from "components/Synthetics/AllowedSwapSlippageInputRowImpl/AllowedSwapSlippageInputRowImpl";

export function AdvancedDisplayRows() {
const tradeFlags = useSelector(selectTradeboxTradeFlags);
const increaseAmounts = useSelector(selectTradeboxIncreasePositionAmounts);
const decreaseAmounts = useSelector(selectTradeboxDecreasePositionAmounts);
const limitPrice = useSelector(selectTradeboxTriggerPrice);
const triggerRatioInputValue = useSelector(selectTradeboxTriggerRatioInputValue);
const totalSwapImpactBps = useSelector(selectTradeboxTotalSwapImpactBps);

const setSelectedTriggerAcceptablePriceImpactBps = useSelector(selectTradeboxSetSelectedAcceptablePriceImpactBps);
const selectedTriggerAcceptablePriceImpactBps = useSelector(selectTradeboxSelectedTriggerAcceptablePriceImpactBps);
const defaultTriggerAcceptablePriceImpactBps = useSelector(selectTradeboxDefaultTriggerAcceptablePriceImpactBps);

const defaultAllowedSwapSlippageBps = useSelector(selectTradeboxDefaultAllowedSwapSlippageBps);
const selectedAllowedSwapSlippageBps = useSelector(selectTradeboxSelectedAllowedSwapSlippageBps);
const setSelectedAllowedSwapSlippageBps = useSelector(selectTradeboxSetSelectedAllowedSwapSlippageBps);

useTradeboxAllowedSwapSlippageValues();

const fees = useSelector(selectTradeboxFees);

const { isMarket, isLimit, isTrigger, isSwap } = tradeFlags;

const isInputDisabled = useMemo(() => {
const isPriceImpactInputDisabled = useMemo(() => {
if (isLimit && increaseAmounts) {
return limitPrice === undefined || limitPrice === 0n;
}

return decreaseAmounts && decreaseAmounts.triggerOrderType === OrderType.StopLossDecrease;
}, [decreaseAmounts, increaseAmounts, isLimit, limitPrice]);

const isSwapImpactInputDisabled = useMemo(() => {
if (isLimit && isSwap) {
return !triggerRatioInputValue;
}

return true;
}, [isLimit, isSwap, triggerRatioInputValue]);

return (
<>
<SwapSpreadRow />
Expand All @@ -67,7 +91,7 @@ export function AdvancedDisplayRows() {
<AcceptablePriceImpactInputRow
className="!mb-0 mt-8"
notAvailable={
isInputDisabled ||
isPriceImpactInputDisabled ||
defaultTriggerAcceptablePriceImpactBps === undefined ||
selectedTriggerAcceptablePriceImpactBps === undefined
}
Expand All @@ -77,6 +101,20 @@ export function AdvancedDisplayRows() {
setAcceptablePriceImpactBps={setSelectedTriggerAcceptablePriceImpactBps}
/>
)}
{isLimit && isSwap && (
<AllowedSwapSlippageInputRow
className="!mb-0 mt-8"
notAvailable={
isSwapImpactInputDisabled ||
defaultAllowedSwapSlippageBps === undefined ||
selectedAllowedSwapSlippageBps === undefined
}
totalSwapImpactBps={totalSwapImpactBps}
allowedSwapSlippageBps={selectedAllowedSwapSlippageBps}
recommendedAllowedSwapSlippageBps={defaultAllowedSwapSlippageBps}
setAllowedSwapSlippageBps={setSelectedAllowedSwapSlippageBps}
/>
)}
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useSelector } from "context/SyntheticsStateContext/utils";
import { bigMath } from "lib/bigmath";
import { useTradeboxChanges } from "./useTradeboxChanges";

export function useTradeboxAvailablePriceImpactValues() {
export function useTradeboxAcceptablePriceImpactValues() {
const increaseAmounts = useSelector(selectTradeboxIncreasePositionAmounts);
const decreaseAmounts = useSelector(selectTradeboxDecreasePositionAmounts);
const defaultTriggerAcceptablePriceImpactBps = useSelector(selectTradeboxDefaultTriggerAcceptablePriceImpactBps);
Expand Down
Loading