Skip to content

Commit bab7242

Browse files
committed
fix: render non-EVM swap/bridge rows with the redesigned Activity row
Non-EVM (e.g. Solana) swaps and bridges submitted from the device carry a local bridge-history entry, which routed them to the legacy MultichainBridgeTransactionListItem — larger typography, per-row status and timestamp — while identical remote-history rows used the redesigned compact ActivityListItemRow. Remove the legacy branch so all rows render through ActivityListItemRow, and move the tap routing into the shared press handler: cross-chain bridges keep their dedicated bridge-status screen (mirroring local EVM bridges), same-chain swaps fall through to the shared detail flows.
1 parent 3552457 commit bab7242

2 files changed

Lines changed: 80 additions & 49 deletions

File tree

app/components/Views/ActivityList/ActivityList.test.tsx

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -326,18 +326,6 @@ jest.mock('../../UI/ActivityListItemRow/ActivityListItemRow', () => ({
326326
resolveActivityListItemTitle: jest.fn(() => 'Activity title'),
327327
}));
328328

329-
jest.mock('../../UI/MultichainBridgeTransactionListItem', () => {
330-
const { Text, View } = jest.requireActual('react-native');
331-
return {
332-
__esModule: true,
333-
default: ({ transaction }: { transaction: { id: string } }) => (
334-
<View testID={`bridge-${transaction.id}`}>
335-
<Text>Bridge tx</Text>
336-
</View>
337-
),
338-
};
339-
});
340-
341329
jest.mock('../../UI/Transactions/TransactionsFooter', () => {
342330
const { Text, TouchableOpacity } = jest.requireActual('react-native');
343331
return {
@@ -382,14 +370,25 @@ jest.mock('../../UI/Bridge/hooks/useBridgeHistoryItemBySrcTxHash', () => ({
382370
useBridgeHistoryItemBySrcTxHash: jest.fn(() => ({
383371
bridgeHistoryItemsBySrcTxHash: {
384372
'0xconfirmed': { title: 'bridge-history' },
373+
// Same-chain swap (no quote → not a cross-chain bridge).
385374
solanaBridge: { title: 'solana-bridge' },
375+
// Cross-chain bridge (src and dest chains differ).
376+
solanaCross: {
377+
title: 'solana-cross-bridge',
378+
quote: { srcChainId: 'solana:mainnet', destChainId: 1 },
379+
},
386380
},
387381
})),
388382
}));
389383

390384
jest.mock('../../UI/Bridge/utils/transaction-history', () => ({
391385
getSwapBridgeTxActivityTitle: jest.fn(() => 'Bridge title'),
392386
handleUnifiedSwapsTxHistoryItemClick: jest.fn(),
387+
isBridgeTxHistoryItemBridge: jest.fn(
388+
(item: { quote?: { srcChainId?: unknown; destChainId?: unknown } }) =>
389+
item?.quote !== undefined &&
390+
item.quote.srcChainId !== item.quote.destChainId,
391+
),
393392
}));
394393

395394
jest.mock('../../../util/multichain/multichainTransactionTokenScan', () => ({
@@ -1711,7 +1710,7 @@ describe('ActivityList', () => {
17111710
});
17121711
});
17131712

1714-
it('renders non-EVM bridge rows and footer when only non-EVM chains are enabled', () => {
1713+
it('renders non-EVM swap/bridge rows through ActivityListItemRow with the bridge-history title', () => {
17151714
selectorValues.enabledEvm = [];
17161715
selectorValues.enabledNonEvm = ['solana:mainnet'];
17171716
selectorValues.nonEvmState = {
@@ -1732,11 +1731,53 @@ describe('ActivityList', () => {
17321731

17331732
render(<ActivityList chainId="solana:mainnet" />);
17341733

1735-
expect(screen.getByTestId('bridge-solanaBridge')).toBeOnTheScreen();
1734+
expect(screen.getByTestId('row-solanaBridge')).toBeOnTheScreen();
1735+
expect(screen.getByText('Bridge title')).toBeOnTheScreen();
17361736
fireEvent.press(screen.getByTestId('non-evm-footer'));
17371737
expect(mockNavigate).toHaveBeenCalledWith('Webview', {
17381738
params: { url: 'https://solana.explorer/address/sol' },
17391739
screen: 'SimpleWebview',
17401740
});
17411741
});
1742+
1743+
it('routes non-EVM cross-chain bridge taps to the unified swaps detail screen', () => {
1744+
selectorValues.enabledNonEvm = ['solana:mainnet'];
1745+
selectorValues.nonEvmState = {
1746+
transactions: [{ chain: 'solana:mainnet', id: 'solanaCross' }],
1747+
};
1748+
1749+
render(<ActivityList header={<></>} />);
1750+
1751+
fireEvent.press(screen.getByTestId('row-solanaCross'));
1752+
1753+
expect(handleUnifiedSwapsTxHistoryItemClick).toHaveBeenCalledWith({
1754+
navigation: expect.any(Object),
1755+
multiChainTx: { chain: 'solana:mainnet', id: 'solanaCross' },
1756+
bridgeTxHistoryItem: expect.objectContaining({
1757+
title: 'solana-cross-bridge',
1758+
}),
1759+
});
1760+
expect(mockNavigate).not.toHaveBeenCalled();
1761+
});
1762+
1763+
it('opens the multichain details sheet for non-EVM same-chain swaps with bridge history', () => {
1764+
selectorValues.enabledNonEvm = ['solana:mainnet'];
1765+
selectorValues.nonEvmState = {
1766+
transactions: [
1767+
{ chain: 'solana:mainnet', id: 'solanaBridge', from: [], to: [] },
1768+
],
1769+
};
1770+
1771+
render(<ActivityList header={<></>} />);
1772+
1773+
fireEvent.press(screen.getByTestId('row-solanaBridge'));
1774+
1775+
expect(handleUnifiedSwapsTxHistoryItemClick).not.toHaveBeenCalled();
1776+
expect(mockNavigate).toHaveBeenCalledWith(
1777+
Routes.MODAL.ROOT_MODAL_FLOW,
1778+
expect.objectContaining({
1779+
screen: Routes.SHEET.MULTICHAIN_TRANSACTION_DETAILS,
1780+
}),
1781+
);
1782+
});
17421783
});

app/components/Views/ActivityList/ActivityList.tsx

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ import { useBridgeHistoryItemBySrcTxHash } from '../../UI/Bridge/hooks/useBridge
7272
import {
7373
getSwapBridgeTxActivityTitle,
7474
handleUnifiedSwapsTxHistoryItemClick,
75+
isBridgeTxHistoryItemBridge,
7576
} from '../../UI/Bridge/utils/transaction-history';
76-
import MultichainBridgeTransactionListItem from '../../UI/MultichainBridgeTransactionListItem';
7777
import TransactionsFooter from '../../UI/Transactions/TransactionsFooter';
7878
// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog
7979
import MultichainTransactionsFooter from '../MultichainTransactionsView/MultichainTransactionsFooter';
@@ -82,7 +82,6 @@ import { getAddressUrl } from '../../../core/Multichain/utils';
8282
import { CancelSpeedupModal } from '../confirmations/components/modals/cancel-speedup-modal';
8383
import styleSheet from './ActivityList.styles';
8484
import { useUnifiedTxActions } from './useUnifiedTxActions';
85-
import { TransactionDetailLocation } from '../../../core/Analytics/events/transactions';
8685
import { useTransactionAutoScroll } from './useTransactionAutoScroll';
8786
import useBlockExplorer from '../../hooks/useBlockExplorer';
8887
import { selectBridgeHistoryForAccount } from '../../../selectors/bridgeStatusController';
@@ -172,7 +171,6 @@ interface ActivityListProps {
172171
header?: React.ReactElement;
173172
tabLabel?: string;
174173
chainId?: string; // used by non-EVM list items for explorer links
175-
location?: TransactionDetailLocation;
176174
/**
177175
* Shared value updated on the UI thread with the list's vertical scroll
178176
* offset, for driving scroll-linked animations in the parent.
@@ -190,15 +188,7 @@ export interface ActivityListHandle {
190188

191189
const ActivityList = forwardRef<ActivityListHandle, ActivityListProps>(
192190
(
193-
{
194-
header,
195-
chainId,
196-
location,
197-
scrollY,
198-
typeFilter,
199-
networkFilter,
200-
subFilterKinds,
201-
},
191+
{ header, chainId, scrollY, typeFilter, networkFilter, subFilterKinds },
202192
ref,
203193
) => {
204194
const navigation = useNavigation();
@@ -818,6 +808,27 @@ const ActivityList = forwardRef<ActivityListHandle, ActivityListProps>(
818808
const { raw } = item;
819809
if (!raw) return;
820810

811+
// Non-EVM swaps/bridges submitted from this device carry a
812+
// bridge-history entry. Cross-chain bridges keep their dedicated
813+
// bridge-status screen, mirroring hasDedicatedDetailScreen for local
814+
// EVM bridges; same-chain swaps fall through to the shared detail flows.
815+
if (raw.type === 'keyringTransaction') {
816+
const keyringBridgeHistoryItem = getBridgeHistoryItemByHash(
817+
item.hash,
818+
);
819+
if (
820+
keyringBridgeHistoryItem &&
821+
isBridgeTxHistoryItemBridge(keyringBridgeHistoryItem)
822+
) {
823+
handleUnifiedSwapsTxHistoryItemClick({
824+
navigation,
825+
multiChainTx: raw.data,
826+
bridgeTxHistoryItem: keyringBridgeHistoryItem,
827+
});
828+
return;
829+
}
830+
}
831+
821832
if (isTransactionsRedesignEnabled) {
822833
const detailsRoute = getActivityDetailsRoute(item);
823834
if (detailsRoute) {
@@ -1219,30 +1230,9 @@ const ActivityList = forwardRef<ActivityListHandle, ActivityListProps>(
12191230
}
12201231

12211232
const { item } = groupedItem;
1222-
const raw = item.raw;
1223-
1224-
// Non-EVM bridge transactions: route to MultichainBridgeTransactionListItem.
1225-
if (raw?.type === 'keyringTransaction') {
1226-
const srcTxHash = raw.data.id;
1227-
const bridgeHistoryItem = getBridgeHistoryItemByHash(srcTxHash);
1228-
if (bridgeHistoryItem) {
1229-
return (
1230-
<MultichainBridgeTransactionListItem
1231-
transaction={raw.data}
1232-
bridgeHistoryItem={bridgeHistoryItem}
1233-
navigation={navigation}
1234-
index={index}
1235-
location={location}
1236-
showDestinationPerspective={
1237-
!configuredNonEVMChainIds.includes(raw.data.chain)
1238-
}
1239-
/>
1240-
);
1241-
}
1242-
}
12431233

1244-
// All other items (API EVM confirmed, completed local EVM, non-EVM non-bridge):
1245-
// render from the shared ActivityListItem shape.
1234+
// All items (API EVM confirmed, completed local EVM, non-EVM) render from
1235+
// the shared ActivityListItem shape.
12461236
//
12471237
// Preserve the legacy Activity title for swap/bridge rows (e.g.
12481238
// "Swap ETH to USDC", "Bridge to Optimism") by deriving it from bridge

0 commit comments

Comments
 (0)