Skip to content

Commit

Permalink
👻 Who Ya Gonna Call?: Fix referential instability in useSwap to sto…
Browse files Browse the repository at this point in the history
…p continuous rerenders and high CPU usage (#3956)

* hook and their props changes debug logs

swap changes

* fix: stabilize switchAssets

* fix: stabilize outputDifference

* feat: add useDeepMemo to use deep equal when memoizing

lodash.isEqual was another option for deep equality checks but
fast-deep-equal is lot smaller and more performant

* fix: stabilize quote

* fix: stabalize useSwapAmountInput

this one was the trigger for multiple changes
inAmountInput, outAmountInput, spotPriceQuote, sendTradeTokeninTx

* fix: stabilize totalFee

* Revert "hook and their props changes debug logs"

This reverts commit 4b42274.

* fix: coderabbit
  • Loading branch information
greg-nagy authored Nov 18, 2024
1 parent dba7d07 commit de3c0d8
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 25 deletions.
15 changes: 10 additions & 5 deletions packages/web/components/swap-tool/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ReactNode,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
Expand Down Expand Up @@ -143,11 +144,15 @@ export const SwapTool: FunctionComponent<SwapToolProps> = observer(
}
}

const outputDifference = new RatePretty(
swapState.inAmountInput?.fiatValue
?.toDec()
.sub(swapState.tokenOutFiatValue?.toDec())
.quo(swapState.inAmountInput?.fiatValue?.toDec()) ?? new Dec(0)
const outputDifference = useMemo(
() =>
new RatePretty(
swapState.inAmountInput?.fiatValue
?.toDec()
.sub(swapState.tokenOutFiatValue?.toDec())
.quo(swapState.inAmountInput?.fiatValue?.toDec()) ?? new Dec(0)
),
[swapState.inAmountInput?.fiatValue, swapState.tokenOutFiatValue]
);

const showOutputDifferenceWarning = outputDifference
Expand Down
27 changes: 27 additions & 0 deletions packages/web/hooks/use-deep-memo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import equal from "fast-deep-equal";
import { DependencyList, useRef } from "react";

/**
* A custom hook for `useMemo` that uses deep comparison on the dependencies.
*
* @param factory - A function that produces the memoized value.
* @param dependencies - The dependency array to be deeply compared.
* @returns The memoized value.
*/
export function useDeepMemo<T>(
factory: () => T,
dependencies: DependencyList
): T {
if (!Array.isArray(dependencies)) {
throw new Error("useDeepMemo expects a dependency array");
}
const dependenciesRef = useRef<DependencyList>();
const memoizedValueRef = useRef<T>();

if (!equal(dependenciesRef.current, dependencies)) {
dependenciesRef.current = dependencies;
memoizedValueRef.current = factory();
}

return memoizedValueRef.current!;
}
60 changes: 44 additions & 16 deletions packages/web/hooks/use-swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
import { useTranslation } from "~/hooks/language";
import { useOneClickTradingSession } from "~/hooks/one-click-trading";
import { mulPrice } from "~/hooks/queries/assets/use-coin-fiat-value";
import { useDeepMemo } from "~/hooks/use-deep-memo";
import { useEstimateTxFees } from "~/hooks/use-estimate-tx-fees";
import { useShowPreviewAssets } from "~/hooks/use-show-preview-assets";
import { AppRouter } from "~/server/api/root-router";
Expand Down Expand Up @@ -703,6 +704,14 @@ export function useSwap(
quoteType,
outAmountInput.fiatValue,
]);
const totalFee = useDeepMemo(
() =>
sum([
tokenInFeeAmountFiatValue,
networkFee?.gasUsdValueToPay?.toDec() ?? new Dec(0),
]),
[tokenInFeeAmountFiatValue, networkFee?.gasUsdValueToPay]
);

return {
...swapAssets,
Expand All @@ -717,10 +726,7 @@ export function useSwap(
? quote
: undefined,
inBaseOutQuoteSpotPrice,
totalFee: sum([
tokenInFeeAmountFiatValue,
networkFee?.gasUsdValueToPay?.toDec() ?? new Dec(0),
]),
totalFee,
networkFee,
isLoadingNetworkFee:
inAmountInput.isLoadingCurrentBalanceNetworkFee || isLoadingNetworkFee,
Expand Down Expand Up @@ -1087,12 +1093,21 @@ function useSwapAmountInput({
);
}, [currentBalanceNetworkFee?.gasAmount]);

return {
...inAmountInput,
const returnValue = useDeepMemo(() => {
return {
...inAmountInput,
isLoadingCurrentBalanceNetworkFee,
hasErrorWithCurrentBalanceQuote,
notEnoughBalanceForMax,
};
}, [
inAmountInput,
isLoadingCurrentBalanceNetworkFee,
hasErrorWithCurrentBalanceQuote,
notEnoughBalanceForMax,
};
]);

return returnValue;
}

/**
Expand Down Expand Up @@ -1142,7 +1157,7 @@ function useToFromDenoms({

// if using query params perform one push instead of two as the router
// doesn't handle two immediate pushes well within `useQueryParamState` hooks
const switchAssets = () => {
const switchAssets = useCallback(() => {
if (useQueryParams) {
const temp = fromDenomQueryParam;
setFromDenomQueryParam(toAssetQueryParam);
Expand All @@ -1153,7 +1168,17 @@ function useToFromDenoms({
const temp = fromAssetState;
setFromAssetState(toAssetState);
setToAssetState(temp);
};
}, [
useQueryParams,
fromDenomQueryParam,
toAssetQueryParam,
setFromDenomQueryParam,
setToAssetQueryParam,
fromAssetState,
toAssetState,
setFromAssetState,
setToAssetState,
]);

const fromAssetDenom = useQueryParams
? fromDenomQueryParamStr
Expand Down Expand Up @@ -1296,18 +1321,16 @@ function useQueryRouterBestQuote(
}
);

const quoteResult =
quoteType === "out-given-in" ? outGivenInQuote : inGivenOutQuote;
const {
data: quote,
isSuccess,
isError,
error,
} = useMemo(() => {
return quoteResult;
}, [quoteResult]);
} = useDeepMemo(() => {
return quoteType === "out-given-in" ? outGivenInQuote : inGivenOutQuote;
}, [quoteType, outGivenInQuote, inGivenOutQuote]);

const acceptedQuote = useMemo(() => {
const acceptedQuote = useDeepMemo(() => {
if (
!quote ||
!input.tokenIn ||
Expand Down Expand Up @@ -1368,8 +1391,13 @@ function useQueryRouterBestQuote(
quoteType,
]);

const quoteData = useDeepMemo(
() => (acceptedQuote ? { ...acceptedQuote, messages } : undefined),
[acceptedQuote, messages]
);

return {
data: acceptedQuote ? { ...acceptedQuote, messages } : undefined,
data: quoteData,
isLoading: !isSuccess,
errorMsg: error?.message,
numSucceeded: isSuccess ? 1 : 0,
Expand Down
1 change: 1 addition & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
"decompress": "^4.2.1",
"eventemitter3": "^4.0.7",
"fancy-canvas": "^2.1.0",
"fast-deep-equal": "^3.1.3",
"focus-trap-react": "^10.0.2",
"fuse.js": "^6.5.3",
"highcharts": "^9.1.0",
Expand Down
153 changes: 149 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4409,7 +4409,29 @@
buffer "^6.0.3"
delay "^4.4.0"

"@keplr-wallet/cosmos@0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/cosmos@0.12.12", "@keplr-wallet/cosmos@0.12.28":
"@keplr-wallet/common@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/common/-/common-0.12.12.tgz#55030d985b729eac582c0d7203190e25ea2cb3ec"
integrity sha512-AxpwmXdqs083lMvA8j0/V30oTGyobsefNaCou+lP4rCyDdYuXSEux+x2+1AGL9xB3yZfN+4jvEEKJdMwHYEHcQ==
dependencies:
"@keplr-wallet/crypto" "0.12.12"
"@keplr-wallet/types" "0.12.12"
buffer "^6.0.3"
delay "^4.4.0"
mobx "^6.1.7"

"@keplr-wallet/common@0.12.28":
version "0.12.28"
resolved "https://registry.yarnpkg.com/@keplr-wallet/common/-/common-0.12.28.tgz#1d5d985070aced31a34a6426c9ac4b775081acca"
integrity sha512-ESQorPZw8PRiUXhsrxED+E1FEWkAdc6Kwi3Az7ce204gMBQDI2j0XJtTd4uCUp+C24Em9fk0samdHzdoB4caIg==
dependencies:
"@keplr-wallet/crypto" "0.12.28"
"@keplr-wallet/types" "0.12.28"
buffer "^6.0.3"
delay "^4.4.0"
mobx "^6.1.7"

"@keplr-wallet/cosmos@0.10.24-ibc.go.v7.hot.fix":
version "0.10.24-ibc.go.v7.hot.fix"
resolved "https://registry.npmjs.org/@keplr-wallet/cosmos/-/cosmos-0.10.24-ibc.go.v7.hot.fix.tgz"
integrity sha512-/A/wHyYo5gQIW5YkAQYZadEv/12EcAuDclO0KboIb9ti4XFJW6S4VY8LnA16R7DZyBx1cnQknyDm101fUrJfJQ==
Expand All @@ -4426,6 +4448,40 @@
long "^4.0.0"
protobufjs "^6.11.2"

"@keplr-wallet/cosmos@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/cosmos/-/cosmos-0.12.12.tgz#72c0505d2327bbf2f5cb51502acaf399b88b4ae3"
integrity sha512-9TLsefUIAuDqqf1WHBt9Bk29rPlkezmLM8P1eEsXGUaHBfuqUrO+RwL3eLA3HGcgNvdy9s8e0p/4CMInH/LLLQ==
dependencies:
"@ethersproject/address" "^5.6.0"
"@keplr-wallet/common" "0.12.12"
"@keplr-wallet/crypto" "0.12.12"
"@keplr-wallet/proto-types" "0.12.12"
"@keplr-wallet/simple-fetch" "0.12.12"
"@keplr-wallet/types" "0.12.12"
"@keplr-wallet/unit" "0.12.12"
bech32 "^1.1.4"
buffer "^6.0.3"
long "^4.0.0"
protobufjs "^6.11.2"

"@keplr-wallet/cosmos@0.12.28":
version "0.12.28"
resolved "https://registry.yarnpkg.com/@keplr-wallet/cosmos/-/cosmos-0.12.28.tgz#d56e73468256e7276a66bb41f145449dbf11efa1"
integrity sha512-IuqmSBgKgIeWBA0XGQKKs28IXFeFMCrfadCbtiZccNc7qnNr5Y/Cyyk01BPC8Dd1ZyEyAByoICgrxvtGN0GGvA==
dependencies:
"@ethersproject/address" "^5.6.0"
"@keplr-wallet/common" "0.12.28"
"@keplr-wallet/crypto" "0.12.28"
"@keplr-wallet/proto-types" "0.12.28"
"@keplr-wallet/simple-fetch" "0.12.28"
"@keplr-wallet/types" "0.12.28"
"@keplr-wallet/unit" "0.12.28"
bech32 "^1.1.4"
buffer "^6.0.3"
long "^4.0.0"
protobufjs "^6.11.2"

"@keplr-wallet/crypto@0.10.24-ibc.go.v7.hot.fix":
version "0.10.24-ibc.go.v7.hot.fix"
resolved "https://registry.npmjs.org/@keplr-wallet/crypto/-/crypto-0.10.24-ibc.go.v7.hot.fix.tgz"
Expand Down Expand Up @@ -4498,14 +4554,30 @@
resolved "https://registry.npmjs.org/@keplr-wallet/popup/-/popup-0.10.24-ibc.go.v7.hot.fix.tgz"
integrity sha512-Q/teyV6vdmpH3SySGd1xrNc/mVGK/tCP5vFEG2I3Y4FDCSV1yD7vcVgUy+tN19Z8EM3goR57V2QlarSOidtdjQ==

"@keplr-wallet/proto-types@0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/proto-types@0.12.12":
"@keplr-wallet/proto-types@0.10.24-ibc.go.v7.hot.fix":
version "0.10.24-ibc.go.v7.hot.fix"
resolved "https://registry.npmjs.org/@keplr-wallet/proto-types/-/proto-types-0.10.24-ibc.go.v7.hot.fix.tgz"
integrity sha512-fLUJEtDadYJIMBzhMSZpEDTvXqk8wW68TwnUCRAcAooEQEtXPwY5gfo3hcekQEiCYtIu8XqzJ9fg01rp2Z4d3w==
dependencies:
long "^4.0.0"
protobufjs "^6.11.2"

"@keplr-wallet/proto-types@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/proto-types/-/proto-types-0.12.12.tgz#24e0530af7604a90f33a397a82fe500865c76154"
integrity sha512-iAqqNlJpxu/8j+SwOXEH2ymM4W0anfxn+eNeWuqz2c/0JxGTWeLURioxQmCtewtllfHdDHHcoQ7/S+NmXiaEgQ==
dependencies:
long "^4.0.0"
protobufjs "^6.11.2"

"@keplr-wallet/proto-types@0.12.28":
version "0.12.28"
resolved "https://registry.yarnpkg.com/@keplr-wallet/proto-types/-/proto-types-0.12.28.tgz#2fb2c37749ce7db974f01d07387e966c9b99027d"
integrity sha512-ukti/eCTltPUP64jxtk5TjtwJogyfKPqlBIT3KGUCGzBLIPeYMsffL5w5aoHsMjINzOITjYqzXyEF8LTIK/fmw==
dependencies:
long "^4.0.0"
protobufjs "^6.11.2"

"@keplr-wallet/provider-extension@^0.12.95":
version "0.12.107"
resolved "https://registry.yarnpkg.com/@keplr-wallet/provider-extension/-/provider-extension-0.12.107.tgz#98a0fb42cb0c54d4e681e60e6b1145429a6e3e23"
Expand Down Expand Up @@ -4581,12 +4653,32 @@
deepmerge "^4.2.2"
long "^4.0.0"

"@keplr-wallet/router@0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/router@0.12.12", "@keplr-wallet/router@0.12.96":
"@keplr-wallet/router@0.10.24-ibc.go.v7.hot.fix":
version "0.10.24-ibc.go.v7.hot.fix"
resolved "https://registry.npmjs.org/@keplr-wallet/router/-/router-0.10.24-ibc.go.v7.hot.fix.tgz"
integrity sha512-bt9weexlbhlh8KsOvbDrvHJ8jtUXrXgB2LX+hEAwjclHQt7PMUhx9a5z0Obd19/ive5G/1M7/ccdPIWxRBpKQw==

"@keplr-wallet/types@0.10.24-ibc.go.v7.hot.fix", "@keplr-wallet/types@0.12.107", "@keplr-wallet/types@0.12.12", "@keplr-wallet/types@0.12.96", "@keplr-wallet/types@^0.12.95":
"@keplr-wallet/router@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/router/-/router-0.12.12.tgz#92a2c006aec6945ed313575af6b0801f8e84e315"
integrity sha512-Aa1TiVRIEPaqs1t27nCNs5Kz6Ty4CLarVdfqcRWlFQL6zFq33GT46s6K9U4Lz2swVCwdmerSXaq308K/GJHTlw==

"@keplr-wallet/router@0.12.96":
version "0.12.96"
resolved "https://registry.yarnpkg.com/@keplr-wallet/router/-/router-0.12.96.tgz#6a20ed2c90ba3ed4f3fc43ed7513f72d7055482d"
integrity sha512-O8izj032ZKQIoTus96BFqem+w6NpYHU3j6NEnSaQBh6Zncj9fgjoOVs0CKK+jsuLYUsOHx2t86BxMSKESsR0Ug==

"@keplr-wallet/simple-fetch@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/simple-fetch/-/simple-fetch-0.12.12.tgz#aacc5c3f22b7ab2804b39e864725294a32f858fd"
integrity sha512-lCOsaI8upMpbusfwJqEK8VIEX77+QE8+8MJVRqoCYwjOTqKGdUH7D1ieZWh+pzvzOnVgedM3lxqdmCvdgU91qw==

"@keplr-wallet/simple-fetch@0.12.28":
version "0.12.28"
resolved "https://registry.yarnpkg.com/@keplr-wallet/simple-fetch/-/simple-fetch-0.12.28.tgz#44225df5b329c823076280df1ec9930a21b1373e"
integrity sha512-T2CiKS2B5n0ZA7CWw0CA6qIAH0XYI1siE50MP+i+V0ZniCGBeL+BMcDw64vFJUcEH+1L5X4sDAzV37fQxGwllA==

"@keplr-wallet/types@0.10.24-ibc.go.v7.hot.fix":
version "0.10.24-ibc.go.v7.hot.fix"
resolved "https://registry.npmjs.org/@keplr-wallet/types/-/types-0.10.24-ibc.go.v7.hot.fix.tgz"
integrity sha512-3KUjDMUCscYkvKnC+JsJh9+X0NHlsvBgAghP/uy2p5OGtiULqPBAjWiO+hnBbhis3ZEkzGcCROnnBOoccKd3CQ==
Expand All @@ -4597,6 +4689,41 @@
long "^4.0.0"
secretjs "^0.17.0"

"@keplr-wallet/types@0.12.107":
version "0.12.107"
resolved "https://registry.yarnpkg.com/@keplr-wallet/types/-/types-0.12.107.tgz#8d6726d86e17a79131b4b6f4f114052d6384aa58"
integrity sha512-jBpjJO+nNL8cgsJLjZYoq84n+7nXHDdztTgRMVnnomFb+Vy0FVIEI8VUl89ImmHDUImDd0562ywsvA496/0yCA==
dependencies:
long "^4.0.0"

"@keplr-wallet/types@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/types/-/types-0.12.12.tgz#f4bd9e710d5e53504f6b53330abb45bedd9c20ae"
integrity sha512-fo6b8j9EXnJukGvZorifJWEm1BPIrvaTLuu5PqaU5k1ANDasm/FL1NaUuaTBVvhRjINtvVXqYpW/rVUinA9MBA==
dependencies:
long "^4.0.0"

"@keplr-wallet/types@0.12.28":
version "0.12.28"
resolved "https://registry.yarnpkg.com/@keplr-wallet/types/-/types-0.12.28.tgz#eac3c2c9d4560856c5c403a87e67925992a04fbf"
integrity sha512-EcM9d46hYDm3AO4lf4GUbTSLRySONtTmhKb7p88q56OQOgJN3MMjRacEo2p9jX9gpPe7gRIjMUalhAfUiFpZoQ==
dependencies:
long "^4.0.0"

"@keplr-wallet/types@0.12.96":
version "0.12.96"
resolved "https://registry.yarnpkg.com/@keplr-wallet/types/-/types-0.12.96.tgz#a7735051b1f7cbcdf9b8c29010b1c3c45d195c19"
integrity sha512-tr4tPjMrJCsfRXXhhmqnpb9DqH9auJp3uuj8SvDB3pQTTaYJNxkdonLv1tYmXZZ6J9oWtk9WVEDTVgBQN/wisw==
dependencies:
long "^4.0.0"

"@keplr-wallet/types@^0.12.95":
version "0.12.156"
resolved "https://registry.yarnpkg.com/@keplr-wallet/types/-/types-0.12.156.tgz#5e9346c12065a21394fa45112ad1b7a072e0f3f3"
integrity sha512-Z/Lf6VEsl/Am3birKE8ZEVZj/x5YGSoTdFMDtq/EfcB+hcJ/ogoiZTVEBweAig/2zcu7MsZvFTVMEXu5+y3e4A==
dependencies:
long "^4.0.0"

"@keplr-wallet/unit@0.10.24-ibc.go.v7.hot.fix":
version "0.10.24-ibc.go.v7.hot.fix"
resolved "https://registry.npmjs.org/@keplr-wallet/unit/-/unit-0.10.24-ibc.go.v7.hot.fix.tgz"
Expand All @@ -4606,6 +4733,24 @@
big-integer "^1.6.48"
utility-types "^3.10.0"

"@keplr-wallet/unit@0.12.12":
version "0.12.12"
resolved "https://registry.yarnpkg.com/@keplr-wallet/unit/-/unit-0.12.12.tgz#2d7f2e38df4e09c8123dcc0784ffc4b5f4166217"
integrity sha512-fayJcfXWKUnbDZiRJHyuA9GMVS9DymjRlCzlpAJ0+xV0c4Kun/f+9FajL9OQAdPPhnJ7A3KevMI4VHZsd9Yw+A==
dependencies:
"@keplr-wallet/types" "0.12.12"
big-integer "^1.6.48"
utility-types "^3.10.0"

"@keplr-wallet/unit@0.12.28":
version "0.12.28"
resolved "https://registry.yarnpkg.com/@keplr-wallet/unit/-/unit-0.12.28.tgz#907c7fa0b49a729cda207fca14fc0a38871cc6c4"
integrity sha512-kpXigHDBJGOmhtPkv9hqsQid9zkFo7OQPeKgO2n8GUlOINIXW6kWG5LXYTi/Yg9Uiw1CQF69gFMuZCJ8IzVHlA==
dependencies:
"@keplr-wallet/types" "0.12.28"
big-integer "^1.6.48"
utility-types "^3.10.0"

"@keplr-wallet/wc-client@^0.12.95":
version "0.12.96"
resolved "https://registry.yarnpkg.com/@keplr-wallet/wc-client/-/wc-client-0.12.96.tgz#a56995172dcdc73d32b24d5a704a954062befc2a"
Expand Down

0 comments on commit de3c0d8

Please sign in to comment.