Skip to content

Commit

Permalink
feat: [GSW-1984] Swap Value Debounce
Browse files Browse the repository at this point in the history
  • Loading branch information
tfrg committed Dec 23, 2024
1 parent f407c78 commit 6c4e758
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 20 deletions.
7 changes: 4 additions & 3 deletions packages/web/src/hooks/swap/data/use-swap-handler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export const useSwapHandler = () => {
unwrap,
updateSwapAmount,
resetSwapAmount,
isTyping,
} = useSwap({
tokenA,
tokenB,
Expand Down Expand Up @@ -299,7 +300,7 @@ export const useSwapHandler = () => {
);
prevPriceImpact.current = BigNumber(priceImpactNum.toFixed(2));
return BigNumber(priceImpactNum.toFixed(2));
}, [estimatedRoutes, swapFee, tokenA, tokenAAmount, tokenB, tokenBAmount, tokenPrices]);
}, [estimatedRoutes, swapFee, tokenA?.path, tokenAAmount, tokenB?.path, tokenBAmount, tokenPrices]);

const priceImpactStatus: PriceImpactStatus = useMemo(() => {
if (!priceImpact) return "NONE";
Expand Down Expand Up @@ -1032,7 +1033,7 @@ export const useSwapHandler = () => {
}

if (swapState !== "SUCCESS" && estimatedAmount === null) {
if (swapState === "NO_LIQUIDITY") {
if (swapState === "NO_LIQUIDITY" || swapState === "NONE") {
if (type === "EXACT_IN") {
setTokenBAmount("");
} else {
Expand Down Expand Up @@ -1107,7 +1108,7 @@ export const useSwapHandler = () => {
executeSwap,
isSwitchNetwork,
switchNetwork,
isLoading: swapState === "LOADING",
isLoading: swapState === "LOADING" || isTyping,
setSwapValue,
tokenA,
tokenB,
Expand Down
62 changes: 45 additions & 17 deletions packages/web/src/hooks/swap/data/use-swap.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import BigNumber from "bignumber.js";

import { SwapDirectionType } from "@common/values";
import { useGnoswapContext } from "@hooks/common/use-gnoswap-context";
import { useWallet } from "@hooks/wallet/data/use-wallet";
import { TokenModel, isNativeToken } from "@models/token/token-model";
import { EstimatedRoute } from "@models/swap/swap-route-info";
import { makeDisplayTokenAmount } from "@utils/token-utils";
import BigNumber from "bignumber.js";
import { useCallback, useEffect, useMemo, useState } from "react";
import { useGetRoutes } from "@query/router";
import useDebounce from "@hooks/common/use-debounce";

interface UseSwapProps {
tokenA: TokenModel | null;
Expand All @@ -20,7 +22,16 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
const { account } = useWallet();
const { swapRouterRepository } = useGnoswapContext();
const [swapAmount, setSwapAmount] = useState<number | null>(null);
const debouncedAmount = useDebounce(swapAmount, 500);
const [estimatedLiquidityMax, setEstimatedLiquidityMax] = useState<number | null>(null);
const [isTyping, setIsTyping] = useState(false);

const debouncedSwapAmount = useMemo(() => {
if (!swapAmount || swapAmount === 0) {
return swapAmount;
}
return debouncedAmount;
}, [swapAmount, debouncedAmount]);

const shouldFetchData = useCallback(
(amount: number | null) => {
Expand All @@ -30,7 +41,7 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
},
[estimatedLiquidityMax],
);
const shouldFetch = shouldFetchData(swapAmount);
const shouldFetch = shouldFetchData(debouncedSwapAmount);

const selectedTokenPair = tokenA !== null && tokenB !== null;

Expand All @@ -49,7 +60,7 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
return false;
}, [tokenA, tokenB]);

const hasValidSwapAmount = Boolean(swapAmount && swapAmount > 0);
const hasValidSwapAmount = Boolean(debouncedSwapAmount && debouncedSwapAmount > 0);
const hasValidTokenPaths = Boolean(tokenA?.path) && Boolean(tokenB?.path);
const isDifferentTokens = !isSameToken;

Expand All @@ -64,15 +75,20 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
inputToken: tokenA,
outputToken: tokenB,
exactType: direction,
tokenAmount: direction === "EXACT_IN" ? swapAmount : swapAmount ? swapAmount * exactOutPadding : swapAmount,
tokenAmount:
direction === "EXACT_IN"
? debouncedSwapAmount
: debouncedSwapAmount
? debouncedSwapAmount * exactOutPadding
: debouncedSwapAmount,
},
{
enabled: isEnabledQuery,
},
);

const swapState: "NONE" | "LOADING" | "NO_LIQUIDITY" | "SUCCESS" = useMemo(() => {
if (!selectedTokenPair || !swapAmount) {
if (!selectedTokenPair || !debouncedSwapAmount) {
return "NONE";
}

Expand All @@ -89,10 +105,10 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
}

return "SUCCESS";
}, [swapAmount, error, estimatedSwapResult?.amount, isEstimatedSwapLoading, isSameToken, selectedTokenPair]);
}, [debouncedSwapAmount, error, estimatedSwapResult?.amount, isEstimatedSwapLoading, isSameToken, selectedTokenPair]);

const estimatedRoutes: EstimatedRoute[] | null = useMemo(() => {
if (swapState === "LOADING" || !swapAmount) {
if (swapState === "LOADING" || !debouncedSwapAmount || isTyping) {
return null;
}

Expand All @@ -101,14 +117,14 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
}

return estimatedSwapResult.estimatedRoutes;
}, [swapState, estimatedSwapResult, swapAmount]);
}, [swapState, estimatedSwapResult, debouncedSwapAmount, isTyping]);

const estimatedAmount: string | null = useMemo(() => {
if (!tokenA || !tokenB) {
return null;
}

if (!swapAmount || error) {
if (!debouncedSwapAmount || error || isTyping) {
return null;
}

Expand All @@ -120,7 +136,7 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
return direction === "EXACT_IN"
? makeDisplayTokenAmount(tokenB, amount)?.toString() || null
: makeDisplayTokenAmount(tokenA, amount)?.toString() || null;
}, [swapAmount, error, swapState, estimatedSwapResult]);
}, [debouncedSwapAmount, error, swapState, estimatedSwapResult, isTyping]);

const tokenAmountLimit = useMemo(() => {
if (estimatedAmount && !Number.isNaN(slippage)) {
Expand All @@ -137,13 +153,17 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
return 0;
}

return tokenA ? tokenAmountLimit || 0 : 0;
return tokenA ? makeDisplayTokenAmount(tokenA, tokenAmountLimit) || 0 : 0;
}
return 0;
}, [direction, estimatedAmount, slippage, tokenA]);

const updateSwapAmount = useCallback((amount: string) => {
if (!amount) return setSwapAmount(null);
if (!amount) {
setSwapAmount(null);
setIsTyping(false);
return;
}

let newAmount = 0;
if (BigNumber(amount).isZero()) {
Expand All @@ -152,8 +172,15 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
newAmount = BigNumber(amount).toNumber();

setSwapAmount(newAmount);
setIsTyping(true);
}, []);

useEffect(() => {
if (debouncedSwapAmount !== null) {
setIsTyping(false);
}
}, [debouncedSwapAmount]);

const wrap = useCallback(
async (tokenAmount: string) => {
if (!account) {
Expand Down Expand Up @@ -212,14 +239,14 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U

if (estimatedRoutes.length === 0) {
if (!estimatedLiquidityMax) {
setEstimatedLiquidityMax(swapAmount || null);
} else if (swapAmount && swapAmount < estimatedLiquidityMax) {
setEstimatedLiquidityMax(swapAmount);
setEstimatedLiquidityMax(debouncedSwapAmount || null);
} else if (debouncedSwapAmount && debouncedSwapAmount < estimatedLiquidityMax) {
setEstimatedLiquidityMax(debouncedSwapAmount);
}
} else {
setEstimatedLiquidityMax(null);
}
}, [estimatedRoutes, swapAmount, estimatedLiquidityMax]);
}, [estimatedRoutes, debouncedSwapAmount, estimatedLiquidityMax]);

/**
* Reset estimatedLiquidityMax to null after specified delay
Expand Down Expand Up @@ -247,6 +274,7 @@ export const useSwap = ({ tokenA, tokenB, direction, slippage, swapFee = 15 }: U
unwrap,
updateSwapAmount,
isEstimatedSwapLoading,
isTyping,
resetSwapAmount: () => setSwapAmount(0),
};
};

0 comments on commit 6c4e758

Please sign in to comment.