From 32f1519738a3f2ee86ddbe2a274e1c811c768d2a Mon Sep 17 00:00:00 2001 From: thal0x Date: Tue, 26 Dec 2023 07:10:24 -0600 Subject: [PATCH 1/7] display warning on high price impact --- chain-registry | 2 +- src/components/AssetInput.tsx | 64 ++++++++++------------ src/components/PriceImpactWarning.tsx | 59 ++++++++++++++++++++ src/components/SwapWidget/SwapDetails.tsx | 35 +++++++++++- src/components/SwapWidget/SwapWidget.tsx | 15 +++++ src/components/SwapWidget/useSwapWidget.ts | 14 +++++ src/components/TransactionDialog/index.tsx | 33 ++++++++++- src/context/disclosures.ts | 1 + src/utils/utils.ts | 15 +++++ 9 files changed, 199 insertions(+), 39 deletions(-) create mode 100644 src/components/PriceImpactWarning.tsx diff --git a/chain-registry b/chain-registry index c444c7a4..b539099a 160000 --- a/chain-registry +++ b/chain-registry @@ -1 +1 @@ -Subproject commit c444c7a48d8b0dc76b4f1e086b944d160326d2dd +Subproject commit b539099ada02a25033be7fcdb868f5321296fd26 diff --git a/src/components/AssetInput.tsx b/src/components/AssetInput.tsx index ba67ccf1..97e6cdfc 100644 --- a/src/components/AssetInput.tsx +++ b/src/components/AssetInput.tsx @@ -2,7 +2,7 @@ import { PencilSquareIcon } from "@heroicons/react/20/solid"; import { BigNumber } from "bignumber.js"; import { clsx } from "clsx"; import { ethers } from "ethers"; -import { FC, Fragment, useEffect, useMemo, useState } from "react"; +import { FC, Fragment, useMemo, useState } from "react"; import { Chain } from "@/api/queries"; import { AssetWithMetadata, useAssets } from "@/context/assets"; @@ -10,16 +10,17 @@ import { disclosure } from "@/context/disclosures"; import { useSettingsStore } from "@/context/settings"; import Toast from "@/elements/Toast"; import { useAccount } from "@/hooks/useAccount"; -import { getFee, useBalancesByChain } from "@/utils/utils"; +import { formatUSD, getFee, useBalancesByChain } from "@/utils/utils"; import AssetSelect from "./AssetSelect"; import ChainSelect from "./ChainSelect"; import { ClientOnly } from "./ClientOnly"; import { SimpleTooltip } from "./SimpleTooltip"; -import { UsdDiff, UsdValue, useUsdDiffReset } from "./UsdValue"; interface Props { amount: string; + amountUSD?: string; + diffPercentage?: number; onAmountChange?: (amount: string) => void; asset?: AssetWithMetadata; onAssetChange?: (asset: AssetWithMetadata) => void; @@ -33,6 +34,8 @@ interface Props { const AssetInput: FC = ({ amount, + amountUSD, + diffPercentage = 0, onAmountChange, asset, onAssetChange, @@ -93,14 +96,14 @@ const AssetInput: FC = ({ const { slippage } = useSettingsStore(); - const reset = useUsdDiffReset(); - useEffect(() => { - const parsed = parseFloat(amount); + // const reset = useUsdDiffReset(); + // useEffect(() => { + // const parsed = parseFloat(amount); - // hotfix side effect to prevent negative amounts - if (parsed < 0) onAmountChange?.("0.0"); - if (parsed == 0) reset(); - }, [amount, onAmountChange, reset]); + // // hotfix side effect to prevent negative amounts + // if (parsed < 0) onAmountChange?.("0.0"); + // if (parsed == 0) reset(); + // }, [amount, onAmountChange, reset]); return ( @@ -188,33 +191,22 @@ const AssetInput: FC = ({ }} />
- {asset && parseFloat(amount) > 0 && ( -
- -
- )} - {context === "dest" && ( - - {({ isLoading, percentage }) => ( -
0 ? "text-green-500" : "text-red-500", - )} - > - ({percentage.toFixed(2)}%) -
+

+ {amountUSD ? formatUSD(amountUSD) : null} +

+ {amountUSD !== undefined && context === "dest" ? ( +

= 0 ? "text-green-500" : "text-red-500", )} - - )} + > + {new Intl.NumberFormat("en-US", { + style: "percent", + maximumFractionDigits: 2, + }).format(diffPercentage)} +

+ ) : null}
{showBalance && address && selectedAssetBalance && asset && (
diff --git a/src/components/PriceImpactWarning.tsx b/src/components/PriceImpactWarning.tsx new file mode 100644 index 00000000..4503a39e --- /dev/null +++ b/src/components/PriceImpactWarning.tsx @@ -0,0 +1,59 @@ +import { useDisclosureKey } from "@/context/disclosures"; + +interface Props { + onGoBack: () => void; +} + +export const PriceImpactWarning = ({ onGoBack }: Props) => { + const [isOpen, control] = useDisclosureKey("priceImpactWarning"); + + if (!isOpen) return null; + + return ( +
+
+
+
+
+ + + +
+

+ Price Impact Warning +

+

+ This route has a high price impact. Do you want to continue? +

+
+
+ + +
+
+
+
+ ); +}; diff --git a/src/components/SwapWidget/SwapDetails.tsx b/src/components/SwapWidget/SwapDetails.tsx index 6120748a..44b04ef1 100644 --- a/src/components/SwapWidget/SwapDetails.tsx +++ b/src/components/SwapWidget/SwapDetails.tsx @@ -2,7 +2,7 @@ import { ChevronDownIcon, PencilSquareIcon } from "@heroicons/react/20/solid"; import * as Collapsible from "@radix-ui/react-collapsible"; import { RouteResponse } from "@skip-router/core"; import { clsx } from "clsx"; -import { useMemo } from "react"; +import { Fragment, useEffect, useMemo } from "react"; import { disclosure, useDisclosureKey } from "@/context/disclosures"; import { useSettingsStore } from "@/context/settings"; @@ -15,6 +15,8 @@ import { FormValues } from "./useSwapWidget"; type Props = FormValues & { amountOut: string; route: RouteResponse; + priceImpactPercent: number; + priceImpactThresholdReached: boolean; }; export const SwapDetails = ({ @@ -25,6 +27,8 @@ export const SwapDetails = ({ destinationChain, destinationAsset, route, + priceImpactPercent, + priceImpactThresholdReached, }: Props) => { const [open, control] = useDisclosureKey("swapDetailsCollapsible"); @@ -43,6 +47,12 @@ export const SwapDetails = ({ return +feeAmount / Math.pow(10, 18); }, [axelarTransferOperation]); + useEffect(() => { + if (priceImpactThresholdReached) { + control.open(); + } + }, [control, priceImpactThresholdReached]); + if (!(sourceChain && sourceAsset && destinationChain && destinationAsset)) { return null; } @@ -110,6 +120,29 @@ export const SwapDetails = ({ "[&_dd]:text-end [&_dd]:tabular-nums", )} > + {priceImpactPercent ? ( + +
+ + Price Impact + +
+
+ {new Intl.NumberFormat("en-US", { + style: "percent", + maximumFractionDigits: 2, + }).format(priceImpactPercent)} +
+
+ ) : null}
Max Slippage{" "} diff --git a/src/components/SwapWidget/SwapWidget.tsx b/src/components/SwapWidget/SwapWidget.tsx index 009546e2..7140b427 100644 --- a/src/components/SwapWidget/SwapWidget.tsx +++ b/src/components/SwapWidget/SwapWidget.tsx @@ -47,9 +47,18 @@ export const SwapWidget: FC = () => { onSourceAssetChange, onDestinationChainChange, onDestinationAssetChange, + swapPriceImpactPercent, + priceImpactThresholdReached, routeError, } = useSwapWidget(); + let usdDiffPercent = 0.0; + if (route?.usdAmountIn && route?.usdAmountOut) { + usdDiffPercent = + (parseFloat(route.usdAmountOut) - parseFloat(route.usdAmountIn)) / + parseFloat(route.usdAmountIn); + } + const { address, isWalletConnected: isSourceWalletConnected, @@ -114,6 +123,7 @@ export const SwapWidget: FC = () => {
{
{ destinationChain={destinationChain} destinationAsset={destinationAsset} route={route} + priceImpactPercent={swapPriceImpactPercent ?? 0} + priceImpactThresholdReached={priceImpactThresholdReached} /> )} {routeLoading && } @@ -251,6 +265,7 @@ export const SwapWidget: FC = () => { route={route} transactionCount={numberOfTransactions} insufficientBalance={insufficientBalance} + priceImpactThresholdReached={priceImpactThresholdReached} /> {insufficientBalance && (

diff --git a/src/components/SwapWidget/useSwapWidget.ts b/src/components/SwapWidget/useSwapWidget.ts index 83696c8b..f46d92e2 100644 --- a/src/components/SwapWidget/useSwapWidget.ts +++ b/src/components/SwapWidget/useSwapWidget.ts @@ -13,6 +13,8 @@ import { useBalancesByChain } from "@/utils/utils"; export const LAST_SOURCE_CHAIN_KEY = "IBC_DOT_FUN_LAST_SOURCE_CHAIN"; +export const PRICE_IMPACT_THRESHOLD = 0.01; + export function useSwapWidget() { const { onSourceChainChange, @@ -174,6 +176,16 @@ export function useSwapWidget() { } }, [currentEvmChain, sourceChain, switchNetwork]); + const swapPriceImpactPercent = useMemo(() => { + if (!routeResponse?.swapPriceImpactPercent) return undefined; + return parseFloat(routeResponse.swapPriceImpactPercent) / 100; + }, [routeResponse]); + + const priceImpactThresholdReached = useMemo(() => { + if (!swapPriceImpactPercent) return false; + return swapPriceImpactPercent > PRICE_IMPACT_THRESHOLD; + }, [swapPriceImpactPercent]); + return { amountIn, amountOut, @@ -193,6 +205,8 @@ export function useSwapWidget() { onDestinationAssetChange, noRouteFound: routeQueryIsError, routeError: errorMessage, + swapPriceImpactPercent, + priceImpactThresholdReached, }; } diff --git a/src/components/TransactionDialog/index.tsx b/src/components/TransactionDialog/index.tsx index f0d7147d..5308b68d 100644 --- a/src/components/TransactionDialog/index.tsx +++ b/src/components/TransactionDialog/index.tsx @@ -1,6 +1,9 @@ import { RouteResponse } from "@skip-router/core"; -import { FC, Fragment, useState } from "react"; +import { FC, Fragment, useEffect, useState } from "react"; +import { useDisclosureKey } from "@/context/disclosures"; + +import { PriceImpactWarning } from "../PriceImpactWarning"; import TransactionDialogContent from "./TransactionDialogContent"; export type ActionType = "NONE" | "TRANSFER" | "SWAP"; @@ -10,6 +13,7 @@ interface Props { route?: RouteResponse; transactionCount: number; insufficientBalance?: boolean; + priceImpactThresholdReached?: boolean; } const TransactionDialog: FC = ({ @@ -17,9 +21,35 @@ const TransactionDialog: FC = ({ route, insufficientBalance, transactionCount, + priceImpactThresholdReached, }) => { + const [hasDisplayedWarning, setHasDisplayedWarning] = useState(false); const [isOpen, setIsOpen] = useState(false); + const [, control] = useDisclosureKey("priceImpactWarning"); + + useEffect(() => { + if (!isOpen) { + setHasDisplayedWarning(false); + return; + } + + if (hasDisplayedWarning) { + return; + } + + if (priceImpactThresholdReached) { + control.open(); + setHasDisplayedWarning(true); + } + }, [ + control, + setHasDisplayedWarning, + isOpen, + hasDisplayedWarning, + priceImpactThresholdReached, + ]); + return (

@@ -43,6 +73,7 @@ const TransactionDialog: FC = ({
)}
+ setIsOpen(false)} /> ); }; diff --git a/src/context/disclosures.ts b/src/context/disclosures.ts index c91d912a..03cefe8a 100644 --- a/src/context/disclosures.ts +++ b/src/context/disclosures.ts @@ -4,6 +4,7 @@ const defaultValues = { historyDialog: false, settingsDialog: false, swapDetailsCollapsible: false, + priceImpactWarning: false, // TODO: port dialogs to new system // assetSelect: false, diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 2f4ffece..0c1878be 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -428,3 +428,18 @@ async function getEvmChainBalances( export const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + +const { format } = new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + maximumFractionDigits: 6, +}); + +export function formatUSD(amount: string | number) { + const amountNumber = typeof amount === "string" ? parseFloat(amount) : amount; + return format(amountNumber); +} + +// export { +// formatUSD: format, +// } From 4c8aba272bb6a477cdda5067d2d6f69997b4f693 Mon Sep 17 00:00:00 2001 From: thal0x Date: Tue, 26 Dec 2023 07:14:02 -0600 Subject: [PATCH 2/7] remove dead code --- src/components/AssetInput.tsx | 9 --------- src/utils/utils.ts | 4 ---- 2 files changed, 13 deletions(-) diff --git a/src/components/AssetInput.tsx b/src/components/AssetInput.tsx index 97e6cdfc..cc042630 100644 --- a/src/components/AssetInput.tsx +++ b/src/components/AssetInput.tsx @@ -96,15 +96,6 @@ const AssetInput: FC = ({ const { slippage } = useSettingsStore(); - // const reset = useUsdDiffReset(); - // useEffect(() => { - // const parsed = parseFloat(amount); - - // // hotfix side effect to prevent negative amounts - // if (parsed < 0) onAmountChange?.("0.0"); - // if (parsed == 0) reset(); - // }, [amount, onAmountChange, reset]); - return (
diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 0c1878be..cad12ddf 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -439,7 +439,3 @@ export function formatUSD(amount: string | number) { const amountNumber = typeof amount === "string" ? parseFloat(amount) : amount; return format(amountNumber); } - -// export { -// formatUSD: format, -// } From 5ed78b9ac317885c0bc6f5013c25efc660b3f214 Mon Sep 17 00:00:00 2001 From: thal0x Date: Tue, 26 Dec 2023 07:17:39 -0600 Subject: [PATCH 3/7] remove dead code --- src/components/SwapWidget/SwapWidget.tsx | 7 +++++-- src/components/TransactionDialog/index.tsx | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/SwapWidget/SwapWidget.tsx b/src/components/SwapWidget/SwapWidget.tsx index 7140b427..70ccf702 100644 --- a/src/components/SwapWidget/SwapWidget.tsx +++ b/src/components/SwapWidget/SwapWidget.tsx @@ -23,7 +23,7 @@ import TransactionDialog from "../TransactionDialog"; import { UsdDiff } from "../UsdValue"; import { useWalletModal, WalletModal } from "../WalletModal"; import { SwapDetails } from "./SwapDetails"; -import { useSwapWidget } from "./useSwapWidget"; +import { PRICE_IMPACT_THRESHOLD, useSwapWidget } from "./useSwapWidget"; export const SwapWidget: FC = () => { const { openWalletModal } = useWalletModal(); @@ -265,7 +265,10 @@ export const SwapWidget: FC = () => { route={route} transactionCount={numberOfTransactions} insufficientBalance={insufficientBalance} - priceImpactThresholdReached={priceImpactThresholdReached} + shouldShowPriceImpactWarning={ + priceImpactThresholdReached || + Math.abs(usdDiffPercent * 100) > PRICE_IMPACT_THRESHOLD + } /> {insufficientBalance && (

diff --git a/src/components/TransactionDialog/index.tsx b/src/components/TransactionDialog/index.tsx index 5308b68d..c478dffe 100644 --- a/src/components/TransactionDialog/index.tsx +++ b/src/components/TransactionDialog/index.tsx @@ -13,7 +13,7 @@ interface Props { route?: RouteResponse; transactionCount: number; insufficientBalance?: boolean; - priceImpactThresholdReached?: boolean; + shouldShowPriceImpactWarning?: boolean; } const TransactionDialog: FC = ({ @@ -21,7 +21,7 @@ const TransactionDialog: FC = ({ route, insufficientBalance, transactionCount, - priceImpactThresholdReached, + shouldShowPriceImpactWarning, }) => { const [hasDisplayedWarning, setHasDisplayedWarning] = useState(false); const [isOpen, setIsOpen] = useState(false); @@ -38,7 +38,7 @@ const TransactionDialog: FC = ({ return; } - if (priceImpactThresholdReached) { + if (shouldShowPriceImpactWarning) { control.open(); setHasDisplayedWarning(true); } @@ -47,7 +47,7 @@ const TransactionDialog: FC = ({ setHasDisplayedWarning, isOpen, hasDisplayedWarning, - priceImpactThresholdReached, + shouldShowPriceImpactWarning, ]); return ( From 63817113e4864cbd3ad4aad9bc5be59807d2578c Mon Sep 17 00:00:00 2001 From: thal0x Date: Tue, 26 Dec 2023 08:50:43 -0600 Subject: [PATCH 4/7] show more info --- src/components/PriceImpactWarning.tsx | 10 +++- src/components/SwapWidget/SwapWidget.tsx | 2 + src/components/SwapWidget/useSwapWidget.ts | 68 +++++++++++++++++++++- src/components/TransactionDialog/index.tsx | 7 ++- 4 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/components/PriceImpactWarning.tsx b/src/components/PriceImpactWarning.tsx index 4503a39e..c9776d75 100644 --- a/src/components/PriceImpactWarning.tsx +++ b/src/components/PriceImpactWarning.tsx @@ -2,9 +2,13 @@ import { useDisclosureKey } from "@/context/disclosures"; interface Props { onGoBack: () => void; + warningMessage?: string; } -export const PriceImpactWarning = ({ onGoBack }: Props) => { +export const PriceImpactWarning = ({ + onGoBack, + warningMessage = "", +}: Props) => { const [isOpen, control] = useDisclosureKey("priceImpactWarning"); if (!isOpen) return null; @@ -31,8 +35,8 @@ export const PriceImpactWarning = ({ onGoBack }: Props) => {

Price Impact Warning

-

- This route has a high price impact. Do you want to continue? +

+ {warningMessage} Do you want to continue?

diff --git a/src/components/SwapWidget/SwapWidget.tsx b/src/components/SwapWidget/SwapWidget.tsx index 70ccf702..f1ef3f7e 100644 --- a/src/components/SwapWidget/SwapWidget.tsx +++ b/src/components/SwapWidget/SwapWidget.tsx @@ -50,6 +50,7 @@ export const SwapWidget: FC = () => { swapPriceImpactPercent, priceImpactThresholdReached, routeError, + routeWarning, } = useSwapWidget(); let usdDiffPercent = 0.0; @@ -269,6 +270,7 @@ export const SwapWidget: FC = () => { priceImpactThresholdReached || Math.abs(usdDiffPercent * 100) > PRICE_IMPACT_THRESHOLD } + routeWarning={routeWarning} /> {insufficientBalance && (

diff --git a/src/components/SwapWidget/useSwapWidget.ts b/src/components/SwapWidget/useSwapWidget.ts index f46d92e2..d2bf4374 100644 --- a/src/components/SwapWidget/useSwapWidget.ts +++ b/src/components/SwapWidget/useSwapWidget.ts @@ -13,7 +13,7 @@ import { useBalancesByChain } from "@/utils/utils"; export const LAST_SOURCE_CHAIN_KEY = "IBC_DOT_FUN_LAST_SOURCE_CHAIN"; -export const PRICE_IMPACT_THRESHOLD = 0.01; +export const PRICE_IMPACT_THRESHOLD = 0.1; export function useSwapWidget() { const { @@ -186,6 +186,71 @@ export function useSwapWidget() { return swapPriceImpactPercent > PRICE_IMPACT_THRESHOLD; }, [swapPriceImpactPercent]); + const usdDiffPercent = useMemo(() => { + // if (route?.usdAmountIn && route?.usdAmountOut) { + // usdDiffPercent = + // (parseFloat(route.usdAmountOut) - parseFloat(route.usdAmountIn)) / + // parseFloat(route.usdAmountIn); + // } + + if (!routeResponse) { + return undefined; + } + + if (!routeResponse.usdAmountIn || !routeResponse.usdAmountOut) { + return undefined; + } + + const usdAmountIn = parseFloat(routeResponse.usdAmountIn); + const usdAmountOut = parseFloat(routeResponse.usdAmountOut); + + return (usdAmountOut - usdAmountIn) / usdAmountIn; + }, [routeResponse]); + + console.log(usdDiffPercent); + + const routeWarning = useMemo(() => { + if (!routeResponse) { + return undefined; + } + + if ( + !routeResponse.swapPriceImpactPercent && + (!routeResponse.usdAmountIn || !routeResponse.usdAmountOut) + ) { + return "We were unable to calculate the price impact of this route."; + } + + if (usdDiffPercent && Math.abs(usdDiffPercent) > PRICE_IMPACT_THRESHOLD) { + const amountInUSD = new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(parseFloat(routeResponse.usdAmountIn ?? "0")); + + const amountOutUSD = new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(parseFloat(routeResponse.usdAmountOut ?? "0")); + + const formattedUsdDiffPercent = new Intl.NumberFormat("en-US", { + style: "percent", + maximumFractionDigits: 2, + }).format(Math.abs(usdDiffPercent)); + return `Your estimated output value (${amountOutUSD}) is ${formattedUsdDiffPercent} lower than your estimated input value (${amountInUSD}).`; + } + + if ( + swapPriceImpactPercent && + swapPriceImpactPercent > PRICE_IMPACT_THRESHOLD + ) { + const formattedPriceImpact = new Intl.NumberFormat("en-US", { + style: "percent", + maximumFractionDigits: 2, + }).format(swapPriceImpactPercent); + return `Your swap is expected to execute at a ${formattedPriceImpact} worse price than the current estimated on-chain price. It's likely there's not much liquidity available for this swap.`; + } + }, [routeResponse, swapPriceImpactPercent, usdDiffPercent]); + return { amountIn, amountOut, @@ -207,6 +272,7 @@ export function useSwapWidget() { routeError: errorMessage, swapPriceImpactPercent, priceImpactThresholdReached, + routeWarning, }; } diff --git a/src/components/TransactionDialog/index.tsx b/src/components/TransactionDialog/index.tsx index c478dffe..ef3cba6a 100644 --- a/src/components/TransactionDialog/index.tsx +++ b/src/components/TransactionDialog/index.tsx @@ -14,6 +14,7 @@ interface Props { transactionCount: number; insufficientBalance?: boolean; shouldShowPriceImpactWarning?: boolean; + routeWarning?: string; } const TransactionDialog: FC = ({ @@ -22,6 +23,7 @@ const TransactionDialog: FC = ({ insufficientBalance, transactionCount, shouldShowPriceImpactWarning, + routeWarning, }) => { const [hasDisplayedWarning, setHasDisplayedWarning] = useState(false); const [isOpen, setIsOpen] = useState(false); @@ -73,7 +75,10 @@ const TransactionDialog: FC = ({

)}
- setIsOpen(false)} /> + setIsOpen(false)} + warningMessage={routeWarning} + /> ); }; From 38d064e0bf38ef92cdc6959eab941f1869503c73 Mon Sep 17 00:00:00 2001 From: thal0x Date: Tue, 26 Dec 2023 08:51:53 -0600 Subject: [PATCH 5/7] remove dead code --- src/components/SwapWidget/useSwapWidget.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/components/SwapWidget/useSwapWidget.ts b/src/components/SwapWidget/useSwapWidget.ts index d2bf4374..11c77133 100644 --- a/src/components/SwapWidget/useSwapWidget.ts +++ b/src/components/SwapWidget/useSwapWidget.ts @@ -187,12 +187,6 @@ export function useSwapWidget() { }, [swapPriceImpactPercent]); const usdDiffPercent = useMemo(() => { - // if (route?.usdAmountIn && route?.usdAmountOut) { - // usdDiffPercent = - // (parseFloat(route.usdAmountOut) - parseFloat(route.usdAmountIn)) / - // parseFloat(route.usdAmountIn); - // } - if (!routeResponse) { return undefined; } @@ -207,8 +201,6 @@ export function useSwapWidget() { return (usdAmountOut - usdAmountIn) / usdAmountIn; }, [routeResponse]); - console.log(usdDiffPercent); - const routeWarning = useMemo(() => { if (!routeResponse) { return undefined; From c0a60d1b49efa0a1a4143e15ae03ab9047ad6e5a Mon Sep 17 00:00:00 2001 From: thal0x Date: Thu, 28 Dec 2023 17:01:46 -0600 Subject: [PATCH 6/7] address price warning feedback --- src/components/AssetInput.tsx | 4 +++- src/components/PriceImpactWarning.tsx | 16 ++++++++-------- src/components/SwapWidget/SwapWidget.tsx | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/components/AssetInput.tsx b/src/components/AssetInput.tsx index cc042630..96cc628d 100644 --- a/src/components/AssetInput.tsx +++ b/src/components/AssetInput.tsx @@ -185,7 +185,9 @@ const AssetInput: FC = ({

{amountUSD ? formatUSD(amountUSD) : null}

- {amountUSD !== undefined && context === "dest" ? ( + {amountUSD !== undefined && + diffPercentage !== 0 && + context === "dest" ? (

{ const [isOpen, control] = useDisclosureKey("priceImpactWarning"); - if (!isOpen) return null; + if (!isOpen || warningMessage === "") return null; return (

@@ -33,7 +33,7 @@ export const PriceImpactWarning = ({

- Price Impact Warning + Bad Trade Warning

{warningMessage} Do you want to continue? @@ -42,12 +42,6 @@ export const PriceImpactWarning = ({

- +
diff --git a/src/components/SwapWidget/SwapWidget.tsx b/src/components/SwapWidget/SwapWidget.tsx index f1ef3f7e..f551c21e 100644 --- a/src/components/SwapWidget/SwapWidget.tsx +++ b/src/components/SwapWidget/SwapWidget.tsx @@ -268,7 +268,7 @@ export const SwapWidget: FC = () => { insufficientBalance={insufficientBalance} shouldShowPriceImpactWarning={ priceImpactThresholdReached || - Math.abs(usdDiffPercent * 100) > PRICE_IMPACT_THRESHOLD + Math.abs(usdDiffPercent) > PRICE_IMPACT_THRESHOLD } routeWarning={routeWarning} /> From 062a055dddcb40387a42cd5c4d302d071093c86c Mon Sep 17 00:00:00 2001 From: thal0x Date: Thu, 28 Dec 2023 17:19:24 -0600 Subject: [PATCH 7/7] address price warning feedback --- src/components/PriceImpactWarning.tsx | 12 ++++++----- src/components/SwapWidget/SwapWidget.tsx | 11 +++++----- src/components/SwapWidget/useSwapWidget.ts | 24 ++++++++++++++++------ src/components/TransactionDialog/index.tsx | 9 +++++--- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/src/components/PriceImpactWarning.tsx b/src/components/PriceImpactWarning.tsx index a4649838..1e71d897 100644 --- a/src/components/PriceImpactWarning.tsx +++ b/src/components/PriceImpactWarning.tsx @@ -2,16 +2,18 @@ import { useDisclosureKey } from "@/context/disclosures"; interface Props { onGoBack: () => void; - warningMessage?: string; + message?: string; + title?: string; } export const PriceImpactWarning = ({ onGoBack, - warningMessage = "", + message = "", + title = "", }: Props) => { const [isOpen, control] = useDisclosureKey("priceImpactWarning"); - if (!isOpen || warningMessage === "") return null; + if (!isOpen || title === "") return null; return (
@@ -33,10 +35,10 @@ export const PriceImpactWarning = ({

- Bad Trade Warning + {title}

- {warningMessage} Do you want to continue? + {message} Do you want to continue?

diff --git a/src/components/SwapWidget/SwapWidget.tsx b/src/components/SwapWidget/SwapWidget.tsx index f551c21e..ba4d4302 100644 --- a/src/components/SwapWidget/SwapWidget.tsx +++ b/src/components/SwapWidget/SwapWidget.tsx @@ -23,7 +23,7 @@ import TransactionDialog from "../TransactionDialog"; import { UsdDiff } from "../UsdValue"; import { useWalletModal, WalletModal } from "../WalletModal"; import { SwapDetails } from "./SwapDetails"; -import { PRICE_IMPACT_THRESHOLD, useSwapWidget } from "./useSwapWidget"; +import { useSwapWidget } from "./useSwapWidget"; export const SwapWidget: FC = () => { const { openWalletModal } = useWalletModal(); @@ -50,7 +50,8 @@ export const SwapWidget: FC = () => { swapPriceImpactPercent, priceImpactThresholdReached, routeError, - routeWarning, + routeWarningTitle, + routeWarningMessage, } = useSwapWidget(); let usdDiffPercent = 0.0; @@ -267,10 +268,10 @@ export const SwapWidget: FC = () => { transactionCount={numberOfTransactions} insufficientBalance={insufficientBalance} shouldShowPriceImpactWarning={ - priceImpactThresholdReached || - Math.abs(usdDiffPercent) > PRICE_IMPACT_THRESHOLD + !!routeWarningTitle && !!routeWarningMessage } - routeWarning={routeWarning} + routeWarningTitle={routeWarningTitle} + routeWarningMessage={routeWarningMessage} /> {insufficientBalance && (

diff --git a/src/components/SwapWidget/useSwapWidget.ts b/src/components/SwapWidget/useSwapWidget.ts index 11c77133..d22502bb 100644 --- a/src/components/SwapWidget/useSwapWidget.ts +++ b/src/components/SwapWidget/useSwapWidget.ts @@ -201,16 +201,19 @@ export function useSwapWidget() { return (usdAmountOut - usdAmountIn) / usdAmountIn; }, [routeResponse]); - const routeWarning = useMemo(() => { + const [routeWarningTitle, routeWarningMessage] = useMemo(() => { if (!routeResponse) { - return undefined; + return [undefined, undefined]; } if ( !routeResponse.swapPriceImpactPercent && (!routeResponse.usdAmountIn || !routeResponse.usdAmountOut) ) { - return "We were unable to calculate the price impact of this route."; + return [ + "Low Information Trade", + "We were unable to calculate the price impact of this route.", + ]; } if (usdDiffPercent && Math.abs(usdDiffPercent) > PRICE_IMPACT_THRESHOLD) { @@ -228,7 +231,10 @@ export function useSwapWidget() { style: "percent", maximumFractionDigits: 2, }).format(Math.abs(usdDiffPercent)); - return `Your estimated output value (${amountOutUSD}) is ${formattedUsdDiffPercent} lower than your estimated input value (${amountInUSD}).`; + return [ + "Bad Trade Warning", + `Your estimated output value (${amountOutUSD}) is ${formattedUsdDiffPercent} lower than your estimated input value (${amountInUSD}).`, + ]; } if ( @@ -239,8 +245,13 @@ export function useSwapWidget() { style: "percent", maximumFractionDigits: 2, }).format(swapPriceImpactPercent); - return `Your swap is expected to execute at a ${formattedPriceImpact} worse price than the current estimated on-chain price. It's likely there's not much liquidity available for this swap.`; + return [ + "Bad Trade Warning", + `Your swap is expected to execute at a ${formattedPriceImpact} worse price than the current estimated on-chain price. It's likely there's not much liquidity available for this swap.`, + ]; } + + return [undefined, undefined]; }, [routeResponse, swapPriceImpactPercent, usdDiffPercent]); return { @@ -264,7 +275,8 @@ export function useSwapWidget() { routeError: errorMessage, swapPriceImpactPercent, priceImpactThresholdReached, - routeWarning, + routeWarningTitle, + routeWarningMessage, }; } diff --git a/src/components/TransactionDialog/index.tsx b/src/components/TransactionDialog/index.tsx index ef3cba6a..a0da85a0 100644 --- a/src/components/TransactionDialog/index.tsx +++ b/src/components/TransactionDialog/index.tsx @@ -14,7 +14,8 @@ interface Props { transactionCount: number; insufficientBalance?: boolean; shouldShowPriceImpactWarning?: boolean; - routeWarning?: string; + routeWarningMessage?: string; + routeWarningTitle?: string; } const TransactionDialog: FC = ({ @@ -23,7 +24,8 @@ const TransactionDialog: FC = ({ insufficientBalance, transactionCount, shouldShowPriceImpactWarning, - routeWarning, + routeWarningMessage, + routeWarningTitle, }) => { const [hasDisplayedWarning, setHasDisplayedWarning] = useState(false); const [isOpen, setIsOpen] = useState(false); @@ -77,7 +79,8 @@ const TransactionDialog: FC = ({

setIsOpen(false)} - warningMessage={routeWarning} + message={routeWarningMessage} + title={routeWarningTitle} />
);