From 337a35fd2404dfeba45ff77ba9d65182b7c02f00 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 6 Jan 2026 20:20:19 +0530 Subject: [PATCH 1/3] max button fixed on buy --- src/apps/key-wallet/utils/blockchain.ts | 2 +- src/apps/pulse/components/App/HomeScreen.tsx | 23 +++- src/apps/pulse/components/Buy/Buy.tsx | 122 +++++++++++++++--- src/apps/pulse/components/Buy/PreviewBuy.tsx | 6 + .../pulse/components/Buy/tests/Buy.test.tsx | 52 +++++++- src/apps/pulse/hooks/useRelayBuy.ts | 46 +++++-- src/apps/pulse/utils/utils.tsx | 12 +- 7 files changed, 220 insertions(+), 43 deletions(-) diff --git a/src/apps/key-wallet/utils/blockchain.ts b/src/apps/key-wallet/utils/blockchain.ts index d9341baa..9fee661d 100644 --- a/src/apps/key-wallet/utils/blockchain.ts +++ b/src/apps/key-wallet/utils/blockchain.ts @@ -308,7 +308,7 @@ export const formatBalance = ( export const formatUsdValue = (value: number): string => { if (value === 0) return '$0.00'; if (value < 0.01) return '<$0.01'; - return `$${value.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; + return `$${value.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; }; export const shortenAddress = (address: string, chars: number = 4): string => { diff --git a/src/apps/pulse/components/App/HomeScreen.tsx b/src/apps/pulse/components/App/HomeScreen.tsx index 3acbc058..aac0688e 100644 --- a/src/apps/pulse/components/App/HomeScreen.tsx +++ b/src/apps/pulse/components/App/HomeScreen.tsx @@ -130,7 +130,7 @@ export default function HomeScreen(props: HomeScreenProps) { const [maxStableCoinBalance, setMaxStableCoinBalance] = useState<{ chainId: number; balance: number; - price?: number; + tokenAmount: number; }>(); const [transactionData, setTransactionData] = useState<{ sellToken: SelectedToken | null; @@ -168,6 +168,8 @@ export default function HomeScreen(props: HomeScreenProps) { const [tokenAmount, setTokenAmount] = useState(''); const [isRefreshingHome, setIsRefreshingHome] = useState(false); const [usdAmount, setUsdAmount] = useState(''); + const [isMaxSelected, setIsMaxSelected] = useState(false); + const [maxTokenAmount, setMaxTokenAmount] = useState(); const [dispensableAssets, setDispensableAssets] = useState< DispensableAsset[] >([]); @@ -394,6 +396,7 @@ export default function HomeScreen(props: HomeScreenProps) { } const stableBalance = getStableCurrencyBalanceOnEachChain(walletPortfolioData); + console.log('Stable balances on each chain:', stableBalance); const maxStableBalance = Math.max( ...Object.values(stableBalance).map((s) => s.balance) ); @@ -402,7 +405,12 @@ export default function HomeScreen(props: HomeScreenProps) { (key) => stableBalance[Number(key)].balance === maxStableBalance ) || '1' ); - + console.log( + 'Max stable coin balance:', + maxStableBalance, + 'on chainId:', + chainIdOfMaxStableBalance + ); // Set USDC price from the chain with max stable balance const usdcPriceForMaxChain = stableBalance[chainIdOfMaxStableBalance]?.price; @@ -413,6 +421,7 @@ export default function HomeScreen(props: HomeScreenProps) { setMaxStableCoinBalance({ chainId: chainIdOfMaxStableBalance, balance: maxStableBalance, + tokenAmount: stableBalance[chainIdOfMaxStableBalance]?.tokenAmount ?? 0, }); }, [portfolioTokens, walletPortfolioData]); @@ -1205,6 +1214,8 @@ export default function HomeScreen(props: HomeScreenProps) { userPortfolio={portfolioTokens} gasTankBalance={gasTankBalance} usdcPrice={usdcPrice} + isMaxSelected={isMaxSelected} + maxTokenAmount={maxTokenAmount} /> ); @@ -1361,7 +1372,11 @@ export default function HomeScreen(props: HomeScreenProps) { payingTokens={payingTokens} portfolioTokens={portfolioTokens} maxStableCoinBalance={ - maxStableCoinBalance ?? { chainId: 1, balance: 2 } + maxStableCoinBalance ?? { + chainId: 1, + balance: 2, + tokenAmount: 0, + } } customBuyAmounts={[...customBuyAmounts, 'MAX']} setPreviewBuy={setPreviewBuy} @@ -1374,6 +1389,8 @@ export default function HomeScreen(props: HomeScreenProps) { setChains={setChains} usdcPrice={usdcPrice} isRefreshing={isRefreshingHome} + setIsMaxSelected={setIsMaxSelected} + setMaxTokenAmount={setMaxTokenAmount} /> ) : ( >; @@ -84,6 +85,10 @@ interface BuyProps { setChains: Dispatch>; usdcPrice?: number; // For Relay Buy: USDC price from portfolio (passed from HomeScreen) isRefreshing?: boolean; + isMaxSelected?: boolean; // Whether MAX was selected + maxTokenAmount?: number; // Balance amount when MAX is selected + setIsMaxSelected?: Dispatch>; // Update parent MAX selected state + setMaxTokenAmount?: Dispatch>; // Update parent max token amount state } export default function Buy(props: BuyProps) { @@ -105,6 +110,10 @@ export default function Buy(props: BuyProps) { customBuyAmounts, usdcPrice, isRefreshing = false, + isMaxSelected = false, + maxTokenAmount, + setIsMaxSelected: setParentIsMaxSelected, + setMaxTokenAmount: setParentMaxTokenAmount, } = props; const [usdAmount, setUsdAmount] = useState(''); const [debouncedUsdAmount, setDebouncedUsdAmount] = useState(''); @@ -268,6 +277,8 @@ export default function Buy(props: BuyProps) { if (!input || !Number.isNaN(parseFloat(input))) { setInputPlaceholder('0.00'); setUsdAmount(input); + setParentIsMaxSelected?.(false); // Reset MAX flag when user manually types + setParentMaxTokenAmount?.(undefined); setBelowMinimumAmount(false); setNoEnoughLiquidity(false); setInsufficientWalletBalance(false); @@ -293,7 +304,56 @@ export default function Buy(props: BuyProps) { useEffect(() => { const timer = setTimeout(() => { - if (usdAmount && !Number.isNaN(parseFloat(usdAmount))) { + // Handle MAX case - use maxTokenAmount directly + if (isMaxSelected && maxTokenAmount && maxTokenAmount > 0) { + const amount = maxTokenAmount; + + if (amount < 2) { + setBelowMinimumAmount(true); + setNoEnoughLiquidity(false); + setInsufficientWalletBalance(false); + return; + } + + setBelowMinimumAmount(false); + setNoEnoughLiquidity(false); + setInsufficientWalletBalance(false); + // Pass the balance as a string for dispens able assets calculation + setDebouncedUsdAmount(maxTokenAmount.toString()); + const [dAssets, pChains, pTokens] = getDispensableAssets( + maxTokenAmount.toString(), + walletPortfolioData?.result.data, + maxStableCoinBalance.chainId + ); + + // For MAX selection, skip validation errors and let getBestOffer handle the full amount + if ( + pChains.length === 0 || + dAssets.length === 0 || + pTokens.length === 0 + ) { + if (!isMaxSelected) { + // Only show error for non-MAX selections + setNoEnoughLiquidity(true); + return; + } + // For MAX: proceed without dispensable assets validation + // getBestOffer will handle the full balance + setParentUsdAmount(maxTokenAmount.toString()); + return; + } + + // Always update payingTokens to ensure correct USD amounts are passed to PreviewBuy + setDispensableAssets(dAssets); + setPermittedChains(pChains); + setPayingTokens(pTokens); + setParentDispensableAssets(dAssets); + setParentUsdAmount(maxTokenAmount.toString()); + } else if ( + usdAmount && + usdAmount !== 'MAX' && + !Number.isNaN(parseFloat(usdAmount)) + ) { const amount = parseFloat(usdAmount); if (amount < 2) { @@ -335,6 +395,8 @@ export default function Buy(props: BuyProps) { }, [ sumOfStableBalance, usdAmount, + isMaxSelected, + maxTokenAmount, setPayingTokens, walletPortfolioData?.result.data, dispensableAssets.length, @@ -350,14 +412,19 @@ export default function Buy(props: BuyProps) { ) { setIsLoading(true); try { - // For Relay Buy with EXACT_INPUT, we pass the USD amount directly - // The quote will tell us how many tokens we'll receive + // For Relay Buy with EXACT_INPUT, we pass the USDC amount directly + // When MAX is selected, use maxTokenAmount to pass the balance directly + // Otherwise use the debouncedUsdAmount as USD amount that will be converted to USDC const offer = await getBestOffer({ fromAmount: debouncedUsdAmount, toTokenAddress: token.address, toChainId: token.chainId, fromChainId: maxStableCoinBalance.chainId, usdcPrice, + maxTokenAmount: + isMaxSelected && maxTokenAmount + ? maxTokenAmount.toString() + : undefined, }); setBuyOffer(offer); @@ -377,7 +444,10 @@ export default function Buy(props: BuyProps) { { operation: 'fetch_relay_buy_offer', buyToken: token.symbol, - amount: debouncedUsdAmount, + amount: + isMaxSelected && maxTokenAmount + ? maxTokenAmount.toString() + : debouncedUsdAmount, toChainId: token.chainId, fromChainId: maxStableCoinBalance.chainId, }, @@ -394,6 +464,7 @@ export default function Buy(props: BuyProps) { debouncedUsdAmount, token, isRelayInitialized, + isMaxSelected, getBestOffer, maxStableCoinBalance.chainId, usdcPrice, @@ -744,16 +815,22 @@ export default function Buy(props: BuyProps) {
- setInputPlaceholder('')} - data-testid="pulse-buy-amount-input" - /> + {isMaxSelected ? ( +
+ {maxStableCoinBalance.balance.toFixed(2)} +
+ ) : ( + setInputPlaceholder('')} + data-testid="pulse-buy-amount-input" + /> + )} USD @@ -860,9 +937,24 @@ export default function Buy(props: BuyProps) { onClick={() => { if (!isDisabled) { if (isMax) { - setUsdAmount(sumOfStableBalance.toFixed(2)); + // Use full balance for MAX display + const fullBalance = maxStableCoinBalance.tokenAmount; + const balanceStr = fullBalance.toString(); + setUsdAmount(balanceStr); // Store full balance for display + + // For API calls, calculate amount after 1% platform fee + const maxAmount = fullBalance * 0.99; + // Proper rounding: round down to be conservative with fee calculation + const roundedAmount = Math.floor(maxAmount * 100) / 100; + + // Update parent state for PreviewBuy + setParentIsMaxSelected?.(true); + setParentMaxTokenAmount?.(roundedAmount); } else { setUsdAmount(item); + // Reset parent state + setParentIsMaxSelected?.(false); + setParentMaxTokenAmount?.(undefined); } } }} diff --git a/src/apps/pulse/components/Buy/PreviewBuy.tsx b/src/apps/pulse/components/Buy/PreviewBuy.tsx index 41eb0a52..f24f10a9 100644 --- a/src/apps/pulse/components/Buy/PreviewBuy.tsx +++ b/src/apps/pulse/components/Buy/PreviewBuy.tsx @@ -69,6 +69,8 @@ interface PreviewBuyProps { userPortfolio?: Token[]; // For Relay Buy: user's token portfolio gasTankBalance?: number; // For Relay Buy: gas tank balance to validate transaction usdcPrice?: number; // For Relay Buy: USDC price in USD (e.g., 0.9998) + isMaxSelected?: boolean; // For Relay Buy: whether MAX was selected + maxTokenAmount?: number; // For Relay Buy: actual balance amount when MAX is selected } export default function PreviewBuy(props: PreviewBuyProps) { @@ -87,6 +89,8 @@ export default function PreviewBuy(props: PreviewBuyProps) { userPortfolio, gasTankBalance = 0, usdcPrice, + isMaxSelected = false, + maxTokenAmount, } = props; const [isLoading, setIsLoading] = useState(false); @@ -615,12 +619,14 @@ export default function PreviewBuy(props: PreviewBuyProps) { try { // For Relay Buy with EXACT_INPUT, we pass the USD amount directly // The quote will tell us how many tokens we'll receive + // When MAX is selected, use maxTokenAmount to pass the balance directly const newOffer = await getBestOffer({ fromAmount: usdAmount, toTokenAddress: buyToken.address, toChainId: buyToken.chainId, fromChainId, usdcPrice, + maxTokenAmount: isMaxSelected && maxTokenAmount ? maxTokenAmount.toString() : undefined, }); onBuyOfferUpdate(newOffer); diff --git a/src/apps/pulse/components/Buy/tests/Buy.test.tsx b/src/apps/pulse/components/Buy/tests/Buy.test.tsx index f5a19cc7..d305bf57 100644 --- a/src/apps/pulse/components/Buy/tests/Buy.test.tsx +++ b/src/apps/pulse/components/Buy/tests/Buy.test.tsx @@ -3,6 +3,7 @@ import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import renderer from 'react-test-renderer'; import { vi } from 'vitest'; +import React from 'react'; // hooks import useTransactionKit from '../../../../../hooks/useTransactionKit'; @@ -268,6 +269,7 @@ const mockProps = { maxStableCoinBalance: { chainId: 1, balance: 10050, + tokenAmount: 10050, }, customBuyAmounts: ['10', '20', '50', '100', 'MAX'], setPreviewBuy: vi.fn(), @@ -278,6 +280,10 @@ const mockProps = { setBuyToken: vi.fn(), chains: MobulaChainNames.All, setChains: vi.fn(), + isMaxSelected: false, + maxTokenAmount: undefined, + setIsMaxSelected: vi.fn(), + setMaxTokenAmount: vi.fn(), }; const defaultMocks = () => { @@ -322,10 +328,40 @@ const defaultMocks = () => { mockGetDispensableAssets.mockReturnValue([[], [], []]); }; -const renderWithProviders = (props = {}) => { +// Wrapper component for tests that need to manage MAX state +const BuyWithState = (props: any) => { + const [isMaxSelected, setIsMaxSelected] = React.useState(false); + const [maxTokenAmount, setMaxTokenAmount] = React.useState< + number | undefined + >(); + + return ( + + ); +}; + +const renderWithProviders = ( + additionalProps: Record = {}, + useStateWrapper = false +) => { + if (useStateWrapper) { + return render( + + + + ); + } + return render( - + ); }; @@ -395,12 +431,13 @@ describe('', () => { }); it('MAX button', () => { - renderWithProviders(); + renderWithProviders({}, true); // Use state wrapper const maxButton = screen.getByText('MAX'); fireEvent.click(maxButton); - expect(screen.getByDisplayValue('10050.00')).toBeInTheDocument(); + // After clicking MAX, the balance should be displayed as text instead of input + expect(screen.getByText('10050.00')).toBeInTheDocument(); }); it('token selector click', () => { @@ -672,6 +709,7 @@ describe('', () => { maxStableCoinBalance: { chainId: 1, balance: 1, // Less than $2 + tokenAmount: 1, }, }); @@ -963,13 +1001,13 @@ describe('', () => { }); it('handles MAX button with Relay Buy', () => { - renderWithProviders(); + renderWithProviders({}, true); // Use state wrapper const maxButton = screen.getByText('MAX'); fireEvent.click(maxButton); - // Should set to max stable coin balance - expect(screen.getByDisplayValue('10050.00')).toBeInTheDocument(); + // Should set to max stable coin balance - displayed as text, not input + expect(screen.getByText('10050.00')).toBeInTheDocument(); }); it('shows minimum amount warning with Relay Buy', async () => { diff --git a/src/apps/pulse/hooks/useRelayBuy.ts b/src/apps/pulse/hooks/useRelayBuy.ts index ed5d6c99..74639e13 100644 --- a/src/apps/pulse/hooks/useRelayBuy.ts +++ b/src/apps/pulse/hooks/useRelayBuy.ts @@ -42,6 +42,7 @@ interface BuyParams { fromChainId: number; slippage?: number; usdcPrice?: number; // USDC price in USD (e.g., 0.9998), defaults to 1.0 if not provided + maxTokenAmount?: string; // Optional: Use this amount directly instead of converting from USD (e.g., for MAX selections) } export default function useRelayBuy() { @@ -131,6 +132,7 @@ export default function useRelayBuy() { fromChainId, slippage = 0.03, usdcPrice = 1.0, + maxTokenAmount, }: BuyParams): Promise => { if (!isInitialized) { setError('Unable to get quote. Please try again.'); @@ -162,26 +164,39 @@ export default function useRelayBuy() { /** * Step 2: Convert USD amount to USDC amount using actual USDC price - * fromAmount is in USD, we need to convert to USDC amount + * If maxTokenAmount is provided, use it directly (for MAX selections) + * Otherwise, fromAmount is in USD, we need to convert to USDC amount * Then convert to USDC's smallest unit (6 decimals) * Example: $10 USD / $0.9998 USDC price = 10.002 USDC = 10002000 in wei */ let fromAmountInWei: bigint; try { - const usdAmount = parseFloat(fromAmount); - if (Number.isNaN(usdAmount) || usdAmount <= 0) { - throw new Error('Invalid amount'); - } + if (maxTokenAmount) { + // Use maxTokenAmount directly (e.g., for MAX selections) + console.log('tokenAmount: ', maxTokenAmount); + if (Number.isNaN(maxTokenAmount)) { + throw new Error('Invalid maxTokenAmount'); + } + + // Convert to wei using USDC decimals (e.g., 6 on Ethereum, 18 on BSC) + fromAmountInWei = parseUnits(maxTokenAmount, usdcDecimals); + } else { + // Convert USD to USDC amount using actual USDC price + const usdAmount = parseFloat(fromAmount); + if (Number.isNaN(usdAmount) || usdAmount <= 0) { + throw new Error('Invalid amount'); + } - // Convert USD to USDC amount using actual USDC price - // If USDC price is $0.9998, then $10 USD = 10 / 0.9998 = 10.002 USDC - const usdcAmount = usdAmount / usdcPrice; + // Convert USD to USDC amount using actual USDC price + // If USDC price is $0.9998, then $10 USD = 10 / 0.9998 = 10.002 USDC + const usdcAmount = usdAmount / usdcPrice; - // Convert to wei using USDC decimals (e.g., 6 on Ethereum, 18 on BSC) - fromAmountInWei = parseUnits( - usdcAmount.toFixed(usdcDecimals), - usdcDecimals - ); + // Convert to wei using USDC decimals (e.g., 6 on Ethereum, 18 on BSC) + fromAmountInWei = parseUnits( + usdcAmount.toFixed(usdcDecimals), + usdcDecimals + ); + } } catch (parseError) { console.error('Failed to parse fromAmount:', parseError); setError('Invalid amount. Please try again.'); @@ -334,6 +349,11 @@ export default function useRelayBuy() { // Formula: totalUsdc = usdcForSwap / 0.99 const totalUsdcNeeded = (usdcNeededForSwap * BigInt(100)) / BigInt(99); const usdcFeeAmount = totalUsdcNeeded - usdcNeededForSwap; // 1% fee + console.log( + 'Total USDC needed (including fee): ', + totalUsdcNeeded.toString() + ); + console.log('USDC fee amount (1%): ', usdcFeeAmount.toString()); // Debug: Log fee calculation for troubleshooting transactionDebugLog('Fee calculation:', { diff --git a/src/apps/pulse/utils/utils.tsx b/src/apps/pulse/utils/utils.tsx index af9c1ef5..d8ef3c4b 100644 --- a/src/apps/pulse/utils/utils.tsx +++ b/src/apps/pulse/utils/utils.tsx @@ -217,17 +217,20 @@ export const canCloseTransaction = ( // Helper function to calculate stable currency balance export const getStableCurrencyBalanceOnEachChain = ( walletPortfolioData: WalletPortfolioMobulaResponse -): { [chainId: number]: { balance: number; price?: number } } => { +): { + [chainId: number]: { balance: number; price?: number; tokenAmount?: number }; +} => { // get the list of chainIds from STABLE_CURRENCIES const chainIds = Array.from( new Set(STABLE_CURRENCIES.map((currency) => currency.chainId)) ); // create a map to hold the balance for each chainId - const balanceMap: { [chainId: number]: { balance: number; price?: number } } = - {}; + const balanceMap: { + [chainId: number]: { balance: number; price?: number; tokenAmount: number }; + } = {}; chainIds.forEach((chainId) => { - balanceMap[chainId] = { balance: 0, price: undefined }; + balanceMap[chainId] = { balance: 0, price: undefined, tokenAmount: 0 }; }); // calculate the balance for each chainId walletPortfolioData?.result.data.assets @@ -255,6 +258,7 @@ export const getStableCurrencyBalanceOnEachChain = ( balanceMap[chainId] = { balance: price * balance, price: asset.price ? asset.price : undefined, + tokenAmount: balance, }; }); }); From 7fdc96ab3231b651fb094c046745d914d69dabec Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 6 Jan 2026 20:31:06 +0530 Subject: [PATCH 2/3] fixed lint issues --- src/apps/pulse/components/App/HomeScreen.tsx | 7 ------- src/apps/pulse/components/Buy/Buy.tsx | 1 + src/apps/pulse/components/Buy/PreviewBuy.tsx | 7 ++++++- src/apps/pulse/hooks/useRelayBuy.ts | 6 ------ 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/apps/pulse/components/App/HomeScreen.tsx b/src/apps/pulse/components/App/HomeScreen.tsx index aac0688e..046bba43 100644 --- a/src/apps/pulse/components/App/HomeScreen.tsx +++ b/src/apps/pulse/components/App/HomeScreen.tsx @@ -396,7 +396,6 @@ export default function HomeScreen(props: HomeScreenProps) { } const stableBalance = getStableCurrencyBalanceOnEachChain(walletPortfolioData); - console.log('Stable balances on each chain:', stableBalance); const maxStableBalance = Math.max( ...Object.values(stableBalance).map((s) => s.balance) ); @@ -405,12 +404,6 @@ export default function HomeScreen(props: HomeScreenProps) { (key) => stableBalance[Number(key)].balance === maxStableBalance ) || '1' ); - console.log( - 'Max stable coin balance:', - maxStableBalance, - 'on chainId:', - chainIdOfMaxStableBalance - ); // Set USDC price from the chain with max stable balance const usdcPriceForMaxChain = stableBalance[chainIdOfMaxStableBalance]?.price; diff --git a/src/apps/pulse/components/Buy/Buy.tsx b/src/apps/pulse/components/Buy/Buy.tsx index d9685fe6..04486081 100644 --- a/src/apps/pulse/components/Buy/Buy.tsx +++ b/src/apps/pulse/components/Buy/Buy.tsx @@ -465,6 +465,7 @@ export default function Buy(props: BuyProps) { token, isRelayInitialized, isMaxSelected, + maxTokenAmount, getBestOffer, maxStableCoinBalance.chainId, usdcPrice, diff --git a/src/apps/pulse/components/Buy/PreviewBuy.tsx b/src/apps/pulse/components/Buy/PreviewBuy.tsx index f24f10a9..34847694 100644 --- a/src/apps/pulse/components/Buy/PreviewBuy.tsx +++ b/src/apps/pulse/components/Buy/PreviewBuy.tsx @@ -626,7 +626,10 @@ export default function PreviewBuy(props: PreviewBuyProps) { toChainId: buyToken.chainId, fromChainId, usdcPrice, - maxTokenAmount: isMaxSelected && maxTokenAmount ? maxTokenAmount.toString() : undefined, + maxTokenAmount: + isMaxSelected && maxTokenAmount + ? maxTokenAmount.toString() + : undefined, }); onBuyOfferUpdate(newOffer); @@ -709,6 +712,8 @@ export default function PreviewBuy(props: PreviewBuyProps) { setExpressIntentResponse, clearError, isRelayInitialized, + isMaxSelected, + maxTokenAmount, onBuyOfferUpdate, getBestOffer, fromChainId, diff --git a/src/apps/pulse/hooks/useRelayBuy.ts b/src/apps/pulse/hooks/useRelayBuy.ts index 74639e13..844aedd6 100644 --- a/src/apps/pulse/hooks/useRelayBuy.ts +++ b/src/apps/pulse/hooks/useRelayBuy.ts @@ -173,7 +173,6 @@ export default function useRelayBuy() { try { if (maxTokenAmount) { // Use maxTokenAmount directly (e.g., for MAX selections) - console.log('tokenAmount: ', maxTokenAmount); if (Number.isNaN(maxTokenAmount)) { throw new Error('Invalid maxTokenAmount'); } @@ -349,11 +348,6 @@ export default function useRelayBuy() { // Formula: totalUsdc = usdcForSwap / 0.99 const totalUsdcNeeded = (usdcNeededForSwap * BigInt(100)) / BigInt(99); const usdcFeeAmount = totalUsdcNeeded - usdcNeededForSwap; // 1% fee - console.log( - 'Total USDC needed (including fee): ', - totalUsdcNeeded.toString() - ); - console.log('USDC fee amount (1%): ', usdcFeeAmount.toString()); // Debug: Log fee calculation for troubleshooting transactionDebugLog('Fee calculation:', { From a092f67bed692682d988e6378c1f8c5521e4655d Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 6 Jan 2026 20:37:20 +0530 Subject: [PATCH 3/3] changed as per code rabbit feedback --- src/apps/pulse/hooks/useRelayBuy.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/apps/pulse/hooks/useRelayBuy.ts b/src/apps/pulse/hooks/useRelayBuy.ts index 844aedd6..cc0aeb2b 100644 --- a/src/apps/pulse/hooks/useRelayBuy.ts +++ b/src/apps/pulse/hooks/useRelayBuy.ts @@ -173,8 +173,12 @@ export default function useRelayBuy() { try { if (maxTokenAmount) { // Use maxTokenAmount directly (e.g., for MAX selections) - if (Number.isNaN(maxTokenAmount)) { - throw new Error('Invalid maxTokenAmount'); + // Validate that maxTokenAmount is a valid number string + const numeric = Number(maxTokenAmount); + if (Number.isNaN(numeric) || numeric <= 0) { + throw new Error( + 'Invalid maxTokenAmount: must be a positive number' + ); } // Convert to wei using USDC decimals (e.g., 6 on Ethereum, 18 on BSC)