diff --git a/apps/web/src/features/Swap/state/send/hooks.test.tsx b/apps/web/src/features/Swap/state/send/hooks.test.tsx index fb89aaeccff..eb0f4a8ab63 100644 --- a/apps/web/src/features/Swap/state/send/hooks.test.tsx +++ b/apps/web/src/features/Swap/state/send/hooks.test.tsx @@ -7,11 +7,8 @@ import type { Mock } from 'vitest' import { useDerivedSendInfo } from '~/features/Swap/state/send/hooks' import { SendState } from '~/features/Swap/state/send/SendContext' -vi.mock('@web3-react/core', () => ({ - useWeb3React: () => ({ - chainId: 1, - provider: {}, - }), +vi.mock('~/hooks/useEthersProvider', () => ({ + useEthersProvider: () => ({}), })) vi.mock('~/hooks/useAccount', () => ({ useAccount: () => '0xYourAccountAddress', @@ -48,8 +45,9 @@ vi.mock('~/hooks/useUSDTokenUpdater', () => ({ vi.mock('~/lib/hooks/useCurrencyBalance', () => ({ useCurrencyBalances: () => [undefined, undefined], })) +const mockUseCreateTransferTransaction = vi.fn(() => undefined) vi.mock('~/utils/transfer', () => ({ - useCreateTransferTransaction: () => undefined, + useCreateTransferTransaction: (...args: unknown[]) => mockUseCreateTransferTransaction(...args), })) vi.mock('uniswap/src/features/ens/api', () => ({ useENSName: vi.fn(), @@ -275,4 +273,43 @@ describe('useDerivedSendInfo', () => { expect(info.recipientData).toEqual(validatedRecipientData) }) + + + it('uses inputCurrency.chainId for transfer when it differs from ambient wallet chain', () => { + const mockCurrency = { + chainId: 10, + isNative: false, + isToken: true, + address: '0xabcdef1234567890abcdef1234567890abcdef12', + decimals: 18, + symbol: 'TEST', + name: 'Test Token', + equals: () => false, + wrapped: undefined, + } as unknown as Currency + + const mockSendState: SendState = { + ...defaultSendState, + inputCurrency: mockCurrency, + } + + renderHook(() => useDerivedSendInfo(mockSendState)) + + expect(mockUseCreateTransferTransaction).toHaveBeenCalledWith( + expect.objectContaining({ chainId: 10 }), + ) + }) + + it('falls back to multichain chainId when no inputCurrency is set', () => { + const mockSendState: SendState = { + ...defaultSendState, + inputCurrency: undefined, + } + + renderHook(() => useDerivedSendInfo(mockSendState)) + + expect(mockUseCreateTransferTransaction).toHaveBeenCalledWith( + expect.objectContaining({ chainId: 1 }), + ) + }) }) diff --git a/apps/web/src/features/Swap/state/send/hooks.tsx b/apps/web/src/features/Swap/state/send/hooks.tsx index aafd409284e..b4b67124349 100644 --- a/apps/web/src/features/Swap/state/send/hooks.tsx +++ b/apps/web/src/features/Swap/state/send/hooks.tsx @@ -1,7 +1,7 @@ import { TransactionRequest } from '@ethersproject/abstract-provider' import { Currency, CurrencyAmount } from '@uniswap/sdk-core' import type { GasFeeResult } from '@universe/api' -import { useWeb3React } from '@web3-react/core' +import { useEthersProvider } from '~/hooks/useEthersProvider' import { useMemo } from 'react' import { nativeOnChain } from 'uniswap/src/constants/tokens' import { useUnitagsAddressQuery } from 'uniswap/src/data/apiClients/unitagsApi/useUnitagsAddressQuery' @@ -46,9 +46,12 @@ export type SendInfo = { export function useDerivedSendInfo(state: SendState): SendInfo { const account = useAccount() - const { provider } = useWeb3React() - const { chainId } = useMultichainContext() const { exactAmountToken, exactAmountFiat, inputInFiat, inputCurrency, recipient, validatedRecipientData } = state + const { chainId: multichainChainId } = useMultichainContext() + // Use the selected asset's chain for all send operations to prevent + // cross-chain mismatch when the wallet is on a different network. + const chainId = inputCurrency?.chainId ?? multichainChainId + const provider = useEthersProvider({ chainId }) // If we have validatedRecipientData, skip custom lookups // Otherwise, use raw `recipient` input from the user.