From b858af0df5b424c6723e373b68f1b23acac6b433 Mon Sep 17 00:00:00 2001 From: nonseodion Date: Wed, 28 Jan 2026 20:39:34 +0100 Subject: [PATCH 1/6] updated rates type --- src/contexts/RatesContext.ts | 4 ++-- src/hooks/useRates.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/contexts/RatesContext.ts b/src/contexts/RatesContext.ts index b0104fe..d77af0c 100644 --- a/src/contexts/RatesContext.ts +++ b/src/contexts/RatesContext.ts @@ -3,8 +3,8 @@ import { createContext } from "react" export type Rates = { data: { rates: { - BUSDNGN: { rate: number; key: string } - BUSDUSD: { rate: number; key: string } + USDTNGN: number + USDTUSD: number } time: number } diff --git a/src/hooks/useRates.ts b/src/hooks/useRates.ts index 9074efe..7d0f244 100644 --- a/src/hooks/useRates.ts +++ b/src/hooks/useRates.ts @@ -30,7 +30,7 @@ export function useGetRates(): RateValues { return { data, - ngn: data?.data.rates.BUSDNGN.rate, + ngn: data?.data.rates.USDTNGN, usd: 1, } } From 138882c836a6fd42838a8aa8a08f569dfd272b45 Mon Sep 17 00:00:00 2001 From: nonseodion Date: Wed, 28 Jan 2026 22:32:33 +0100 Subject: [PATCH 2/6] updated min BNB amount --- src/utils/constants/exchange.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/constants/exchange.ts b/src/utils/constants/exchange.ts index 7188e86..336e9be 100644 --- a/src/utils/constants/exchange.ts +++ b/src/utils/constants/exchange.ts @@ -88,8 +88,8 @@ export const pinnedTokens: { [key in ChainId]: [ERC20Token, string][] } = { export const BIG_INT_TEN = JSBI.BigInt(10) export const BIG_INT_ZERO = JSBI.BigInt(0) -// used to ensure the user doesn't send so much BNB so they end up with <.01 -export const MIN_BNB: JSBI = JSBI.exponentiate(BIG_INT_TEN, JSBI.BigInt(16)) // .01 BNB +// used to ensure the user doesn't send so much BNB so they end up with <.0000000000001 +export const MIN_BNB: JSBI = JSBI.exponentiate(BIG_INT_TEN, JSBI.BigInt(5)) // .0000000000001 BNB export const BIPS_BASE = JSBI.BigInt(10000) export const BETTER_TRADE_LESS_HOPS_THRESHOLD = new Percent( From f87d3323aa6fc51e5528d93b2e20fbe1395df089 Mon Sep 17 00:00:00 2001 From: nonseodion Date: Wed, 28 Jan 2026 22:41:57 +0100 Subject: [PATCH 3/6] set default rates --- src/state/exchange/atoms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/state/exchange/atoms.ts b/src/state/exchange/atoms.ts index cfb8e2a..02e3da8 100644 --- a/src/state/exchange/atoms.ts +++ b/src/state/exchange/atoms.ts @@ -33,7 +33,7 @@ export const exchangeAtom = atom({ dollarRate: 1, preferredFiat: supportedFiat.usd, - dollarRates: { usd: 1, ngn: 745 }, + dollarRates: { usd: 1, ngn: 1470 }, bankAccount: undefined, txHash: "0x", From 82ad29cebe782f5b50e7b86a943a17e9e36819c9 Mon Sep 17 00:00:00 2001 From: nonseodion Date: Wed, 28 Jan 2026 22:42:29 +0100 Subject: [PATCH 4/6] fixed rerendering issue --- src/hooks/interfaces/useConverterInferface.ts | 153 ++++++++++++++---- 1 file changed, 126 insertions(+), 27 deletions(-) diff --git a/src/hooks/interfaces/useConverterInferface.ts b/src/hooks/interfaces/useConverterInferface.ts index e75fcee..bd35ca8 100644 --- a/src/hooks/interfaces/useConverterInferface.ts +++ b/src/hooks/interfaces/useConverterInferface.ts @@ -9,7 +9,7 @@ import { TradeType, } from "@pancakeswap/sdk" import { useChainId, useNetwork } from "wagmi" -import { useCallback, useEffect, useMemo, useState } from "react" +import { useCallback, useEffect, useMemo, useRef, useState } from "react" import { useAtom } from "jotai" import { parseUnits } from "ethers/lib/utils" import useTokens from "../../state/tokens/hooks" @@ -100,6 +100,83 @@ const useConverterInterface = (): ReturnTypes => { const [sellAmount, setSellAmount] = useState< CurrencyAmount | undefined >() + const buyAmountRef = useRef(buyAmount) + const sellAmountRef = useRef | undefined>(sellAmount) + const buyAmountDebounceRef = useRef | null>( + null + ) + const sellAmountDebounceRef = useRef | null>( + null + ) + const DEBOUNCE_MS = 200 + + useEffect(() => { + buyAmountRef.current = buyAmount + }, [buyAmount]) + + useEffect(() => { + sellAmountRef.current = sellAmount + }, [sellAmount]) + + useEffect( + () => () => { + if (buyAmountDebounceRef.current) { + clearTimeout(buyAmountDebounceRef.current) + } + if (sellAmountDebounceRef.current) { + clearTimeout(sellAmountDebounceRef.current) + } + }, + [] + ) + + const scheduleBuyAmountUpdate = useCallback( + (nextAmount: FiatAmount | undefined) => { + if ( + nextAmount?.toExact() === buyAmountRef.current?.toExact() || + (!nextAmount && !buyAmountRef.current) + ) { + return + } + if (buyAmountDebounceRef.current) { + clearTimeout(buyAmountDebounceRef.current) + } + buyAmountDebounceRef.current = setTimeout(() => { + if ( + nextAmount?.toExact() === buyAmountRef.current?.toExact() || + (!nextAmount && !buyAmountRef.current) + ) { + return + } + setBuyAmount(nextAmount) + }, DEBOUNCE_MS) + }, + [] + ) + + const scheduleSellAmountUpdate = useCallback( + (nextAmount: CurrencyAmount | undefined) => { + if ( + nextAmount?.toExact() === sellAmountRef.current?.toExact() || + (!nextAmount && !sellAmountRef.current) + ) { + return + } + if (sellAmountDebounceRef.current) { + clearTimeout(sellAmountDebounceRef.current) + } + sellAmountDebounceRef.current = setTimeout(() => { + if ( + nextAmount?.toExact() === sellAmountRef.current?.toExact() || + (!nextAmount && !sellAmountRef.current) + ) { + return + } + setSellAmount(nextAmount) + }, DEBOUNCE_MS) + }, + [] + ) const amountToFetchPrice = useMemo( () => (sellAmount ? [sellAmount] : undefined), @@ -164,10 +241,10 @@ const useConverterInterface = (): ReturnTypes => { parseUnits(amount, buyToken.decimals).toString() ) - setBuyAmount(newAmount) + scheduleBuyAmountUpdate(newAmount) } }, - [buyToken] + [buyToken, scheduleBuyAmountUpdate] ) // validate and format inputted sellAmount before updating state @@ -185,10 +262,10 @@ const useConverterInterface = (): ReturnTypes => { parseUnits(amount, sellToken.decimals).toString() ) - setSellAmount(newAmount) + scheduleSellAmountUpdate(newAmount) } }, - [sellToken] + [sellToken, scheduleSellAmountUpdate] ) // get the fiat equivalent of the sellAmount @@ -227,21 +304,24 @@ const useConverterInterface = (): ReturnTypes => { exchangeRate = useMemo(() => { if (buyAmount && sellAmount) { if (sellAmount.equalTo(0)) return undefined + const numerator = buyAmount + .toDollarAmount( + dollarRates[ + preferredFiat.fiat.symbol.toLowerCase() === "usd" ? "ngn" : "usd" + ] * 100 + ) + .multiply(sellAmount.decimalScale) + .multiply(100) + .divide(buyAmount.decimalScale) + .toFixed(0) + const denominator = sellAmount + .multiply(sellAmount.decimalScale) + .divide(buyAmount.decimalScale) + .toFixed(0) + return new Fraction( - buyAmount - .toDollarAmount( - dollarRates[ - preferredFiat.fiat.symbol.toLowerCase() === "usd" ? "ngn" : "usd" - ] * 100 - ) - .multiply(sellAmount.decimalScale) - .multiply(100) - .divide(buyAmount.decimalScale) - .toFixed(0), - sellAmount - .multiply(sellAmount.decimalScale) - .divide(buyAmount.decimalScale) - .toFixed(0) + numerator === "0" ? 1 : numerator, + denominator === "0" ? 1 : denominator ) } @@ -281,19 +361,32 @@ const useConverterInterface = (): ReturnTypes => { const NGNAmount = amountOut ? stableCoinAmountToFiat(amountOut, dollarRates.ngn, NGN) : undefined - setBuyAmount(NGNAmount) + if ( + NGNAmount?.toExact() === buyAmount?.toExact() || + (!NGNAmount && !buyAmount) + ) { + return + } + scheduleBuyAmountUpdate(NGNAmount) })() } else if ( (!sellAmount || sellAmount.toExact() === "0") && independentField === "sell" ) { - setBuyAmount(undefined) + scheduleBuyAmountUpdate(undefined) } else if (independentField !== "sell" && typedValue === "") { - setSellAmount(undefined) + scheduleSellAmountUpdate(undefined) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [sellAmount, tradeIn?.outputAmount, dollarRates.ngn]) + }, [ + sellAmount, + tradeIn?.outputAmount, + dollarRates.ngn, + scheduleBuyAmountUpdate, + scheduleSellAmountUpdate, + typedValue, + ]) // update sellAmount when buyAmount changes useEffect(() => { @@ -313,19 +406,25 @@ const useConverterInterface = (): ReturnTypes => { dollarRates.ngn ) : tradeOut?.inputAmount ?? undefined - setSellAmount(amountIn) + scheduleSellAmountUpdate(amountIn) })() } else if ( (!buyAmount || buyAmount.toExact() === "0") && independentField === "buy" ) { - setSellAmount(undefined) + scheduleSellAmountUpdate(undefined) } else if (independentField !== "buy" && typedValue === "") { - setBuyAmount(undefined) + scheduleBuyAmountUpdate(undefined) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [buyAmount, tradeOut?.inputAmount]) + }, [ + buyAmount, + tradeOut?.inputAmount, + scheduleBuyAmountUpdate, + scheduleSellAmountUpdate, + typedValue, + ]) return { sellAmount, From 043475ad2a8dfe30c004ebef91378ab503e054a8 Mon Sep 17 00:00:00 2001 From: nonseodion Date: Wed, 28 Jan 2026 23:49:24 +0100 Subject: [PATCH 5/6] fetched token rates only when listener available --- src/hooks/useRates.ts | 31 ++++++++++++------------------- src/services/socket.setup.ts | 11 +++++++++-- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/hooks/useRates.ts b/src/hooks/useRates.ts index 7d0f244..2060eeb 100644 --- a/src/hooks/useRates.ts +++ b/src/hooks/useRates.ts @@ -1,32 +1,25 @@ -import { - Dispatch, - useContext, - SetStateAction, - useCallback, - useEffect, - useState, -} from "react" +import { useContext, useCallback, useEffect, useState } from "react" import { rateSocket } from "../services/socket.setup" import RateContext, { RateValues, Rates } from "../contexts/RatesContext" export function useGetRates(): RateValues { const [data, setRates] = useState() - const listener = useCallback( - (cb: Dispatch>, _rates?: Rates) => - _rates && cb(_rates), - [] - ) + const handleRates = useCallback((rates?: Rates) => { + if (rates) { + setRates(rates) + } + }, []) - // eslint-disable-next-line arrow-body-style useEffect(() => { - rateSocket.on("rates", (__rates) => { - listener(setRates, __rates) - }) + rateSocket.on("rates", handleRates) + if (!rateSocket.connected) { + rateSocket.connect() + } return () => { - rateSocket.off("rates", listener) + rateSocket.off("rates", handleRates) } - }, [listener]) + }, [handleRates]) return { data, diff --git a/src/services/socket.setup.ts b/src/services/socket.setup.ts index ea7b6ce..6d04ce6 100644 --- a/src/services/socket.setup.ts +++ b/src/services/socket.setup.ts @@ -1,4 +1,11 @@ import { io } from "socket.io-client" -export const rateSocket = io(`${process.env.REACT_APP_BACKEND_URL}/rates`) -export const txSocket = io(`${process.env.REACT_APP_BACKEND_URL}/transactions`) +export const rateSocket = io(`${process.env.REACT_APP_BACKEND_URL}/rates`, { + autoConnect: false, +}) +export const txSocket = io( + `${process.env.REACT_APP_BACKEND_URL}/transactions`, + { + autoConnect: true, + } +) From bffeec4d9f395d3017b7a1c073e1855f8bdae7d1 Mon Sep 17 00:00:00 2001 From: nonseodion Date: Wed, 28 Jan 2026 23:50:03 +0100 Subject: [PATCH 6/6] added USDC and USDT tokens --- src/utils/constants/tokens/97.ts | 4 +- .../constants/tokens/defaultTokenInfo.ts | 107 +++--------------- 2 files changed, 19 insertions(+), 92 deletions(-) diff --git a/src/utils/constants/tokens/97.ts b/src/utils/constants/tokens/97.ts index 166d12b..23ace68 100644 --- a/src/utils/constants/tokens/97.ts +++ b/src/utils/constants/tokens/97.ts @@ -50,14 +50,14 @@ export const bscTestnetTokens = { ), usdc: new ERC20Token( ChainId.BSC_TESTNET, - "0xCA8eB2dec4Fe3a5abbFDc017dE48E461A936623D", + "0x64544969ed7EBf5f083679233325356EbE738930", 18, "USDC", "Binance-Peg USD Coin" ), usdt: new ERC20Token( ChainId.BSC_TESTNET, - "0x0fB5D7c73FA349A90392f873a4FA1eCf6a3d0a96", + "0x337610d27c682E347C9cD60BD4b3b107C9d34dDd", 18, "USDT", "Tether USD" diff --git a/src/utils/constants/tokens/defaultTokenInfo.ts b/src/utils/constants/tokens/defaultTokenInfo.ts index 5138dba..bab5213 100644 --- a/src/utils/constants/tokens/defaultTokenInfo.ts +++ b/src/utils/constants/tokens/defaultTokenInfo.ts @@ -7,14 +7,6 @@ export const defaultTokenInfo = [ decimals: 18, logoURI: "https://tokens.pancakeswap.finance/images/symbol/bnb.png", }, - { - name: "BUSD Token", - symbol: "BUSD", - address: "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56", - chainId: 56, - decimals: 18, - logoURI: "https://tokens.pancakeswap.finance/images/symbol/busd.png", - }, { name: "Ethereum Token", symbol: "ETH", @@ -24,14 +16,6 @@ export const defaultTokenInfo = [ logoURI: "https://pancakeswap.finance/images/tokens/0x2170Ed0880ac9A755fd29B2688956BD959F933F8.png", }, - { - name: "BTCB Token", - symbol: "BTCB", - address: "0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c", - chainId: 56, - decimals: 18, - logoURI: "https://tokens.pancakeswap.finance/images/symbol/wbtc.png", - }, { name: "Tether USD", symbol: "USDT", @@ -41,93 +25,36 @@ export const defaultTokenInfo = [ logoURI: "https://tokens.pancakeswap.finance/images/symbol/usdt.png", }, { - name: "PancakeSwap Token", - symbol: "CAKE", - address: "0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82", - chainId: 56, - decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82.png", - }, - { - name: "Venus", - symbol: "XVS", - address: "0xcF6BB5389c92Bdda8a3747Ddb454cB7a64626C63", - chainId: 56, - decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0xcF6BB5389c92Bdda8a3747Ddb454cB7a64626C63.png", - }, - { - name: "VAI Stablecoin", - symbol: "VAI", - address: "0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7", - chainId: 56, - decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0x4BD17003473389A42DAF6a0a729f6Fdb328BbBd7.png", - }, - { - name: "Alpaca", - symbol: "ALPACA", - address: "0x8F0528cE5eF7B51152A59745bEfDD91D97091d2F", - chainId: 56, - decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0x8F0528cE5eF7B51152A59745bEfDD91D97091d2F.png", - }, - { - name: "Belt", - symbol: "BELT", - address: "0xE0e514c71282b6f4e823703a39374Cf58dc3eA4f", - chainId: 56, - decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0xE0e514c71282b6f4e823703a39374Cf58dc3eA4f.png", - }, - { - name: "TokoCrypto", - symbol: "TKO", - address: "0x9f589e3eabe42ebC94A44727b3f3531C0c877809", - chainId: 56, - decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0x9f589e3eabe42ebC94A44727b3f3531C0c877809.png", - }, - { - name: "Nerve Finance", - symbol: "NRV", - address: "0x42F6f551ae042cBe50C739158b4f0CAC0Edb9096", + name: "USD Coin", + symbol: "USDC", + address: "0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d", chainId: 56, decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0x42F6f551ae042cBe50C739158b4f0CAC0Edb9096.png", + logoURI: "https://tokens.pancakeswap.finance/images/symbol/usdc.png", }, { - name: "Ellipsis", - symbol: "EPS", - address: "0xA7f552078dcC247C2684336020c03648500C6d9F", - chainId: 56, + name: "BUSD Token", + symbol: "BUSD", + address: "0xaB1a4d4f1D656d2450692D237fdD6C7f9146e814", + chainId: 97, decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0xA7f552078dcC247C2684336020c03648500C6d9F.png", + logoURI: "https://tokens.pancakeswap.finance/images/symbol/busd.png", }, { - name: "PancakeSwap Token", - symbol: "CAKE", - address: "0xFa60D973F7642B748046464e165A65B7323b0DEE", + name: "USD Coin", + symbol: "USDC", + address: "0x64544969ed7EBf5f083679233325356EbE738930", chainId: 97, decimals: 18, - logoURI: - "https://pancakeswap.finance/images/tokens/0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82.png", + logoURI: "https://tokens.pancakeswap.finance/images/symbol/usdc.png", }, { - name: "BUSD Token", - symbol: "BUSD", - address: "0xaB1a4d4f1D656d2450692D237fdD6C7f9146e814", + name: "Tether USD", + symbol: "USDT", + address: "0x337610d27c682E347C9cD60BD4b3b107C9d34dDd", chainId: 97, decimals: 18, - logoURI: "https://tokens.pancakeswap.finance/images/symbol/busd.png", + logoURI: "https://tokens.pancakeswap.finance/images/symbol/usdt.png", }, { name: "BUSD Token",