Skip to content

Commit efdc35f

Browse files
authored
feat(bridge): add solana chain support and improve bridge state management (#14713)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** The PR focuses on: 1. Improving error handling and state management in the bridge feature 2. Adding support for Solana chain destination addresses 3. Simplifying the code by removing unnecessary state and effects 4. Improving the user experience with better keypad and layout handling ## Changes ### Bridge View Component Changes - Simplified state management by removing `isWaitingForInitialQuote` and related effects - Improved error handling logic - Added new state `isNoQuotesAvailable` to better handle quote availability - Refactored keypad display logic - Improved layout and styling for dynamic content ### Bridge Quote Request Hook Changes - Removed try-catch block in `useBridgeQuoteRequest` for cleaner error propagation - Added support for Solana chain destination addresses - Added `destWalletAddress` parameter that uses: - `destAddress` for Solana chains - `walletAddress` for other chains ### Bridge Quote Data Hook Changes - Added `isNoQuotesAvailable` state to better track quote availability - Updated tests to reflect new state handling - Improved error state management ## **Related issues** Fixes: [MMS-1914](https://consensyssoftware.atlassian.net/browse/MMS-1914) Fixes: [MMS-1915](https://consensyssoftware.atlassian.net/browse/MMS-1915) ## **Manual testing steps** 1. Open Bridge and verify the layout spacing and padding look correct 2. Test keypad behavior: - Tap input field, verify keypad appears - Enter valid amount, verify keypad behavior - Clear input, verify keypad state 3. Test Solana quote fetching: - Select Solana as source chain, enter amount, check quote - Select any chain → Solana, enter amount, check quote 4. Test error handling: - Enter invalid amounts ## **Screenshots/Recordings** https://github.com/user-attachments/assets/349010b4-6734-44f4-9fda-6d8e5ea4a8c4 ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. [MMS-1914]: https://consensyssoftware.atlassian.net/browse/MMS-1914?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ [MMS-1915]: https://consensyssoftware.atlassian.net/browse/MMS-1915?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent d4815a3 commit efdc35f

File tree

9 files changed

+1853
-116
lines changed

9 files changed

+1853
-116
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717

1818
### Added
1919

20+
- feat(bridge): add solana chain support and improve bridge state management ([#14713](https://github.com/MetaMask/metamask-mobile/pull/14713))
2021
- feat(bridge): add error handling and input management for bridge quotes ([#14693](https://github.com/MetaMask/metamask-mobile/pull/14693))
2122
- feat(multi-srp): enable multi-srp in main and beta ([#14558](https://github.com/MetaMask/metamask-mobile/pull/14558))
2223
- feat(ramp): Update ramp data flow to fetch cryptos before payment methods ([#14437](https://github.com/MetaMask/metamask-mobile/pull/14437))

app/components/UI/Bridge/Views/BridgeView/BridgeView.styles.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export const createStyles = (params: { theme: Theme }) => {
1818
width: '100%',
1919
paddingHorizontal: 16,
2020
paddingBottom: 24,
21-
2221
gap: 12,
2322
alignItems: 'center',
2423
justifyContent: 'center',
@@ -59,7 +58,6 @@ export const createStyles = (params: { theme: Theme }) => {
5958
},
6059
quoteContainer: {
6160
paddingHorizontal: 24,
62-
paddingVertical: 24,
6361
},
6462
keypadContainer: {
6563
flex: 1,
@@ -77,16 +75,18 @@ export const createStyles = (params: { theme: Theme }) => {
7775
},
7876
dynamicContent: {
7977
flex: 1,
80-
},
81-
dynamicContentWithKeypad: {
82-
justifyContent: 'flex-start',
83-
},
84-
dynamicContentWithoutKeypad: {
78+
paddingBottom: 12,
8579
justifyContent: 'flex-start',
8680
},
8781
keypadContainerWithDestinationPicker: {
8882
justifyContent: 'center',
8983
paddingVertical: 12,
9084
},
85+
dynamicContentWithDestinationPickerAndQuoteCard: {
86+
justifyContent: 'flex-start',
87+
},
88+
dynamicContentWithOnlyQuoteCard: {
89+
justifyContent: 'space-around',
90+
},
9191
});
9292
};

app/components/UI/Bridge/Views/BridgeView/BridgeView.test.tsx

+25-21
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { Hex } from '@metamask/utils';
99
import BridgeView from '.';
1010
import { createBridgeTestState } from '../../testUtils';
1111
import { initialState } from '../../_mocks_/initialState';
12+
import { RequestStatus, type QuoteResponse } from '@metamask/bridge-controller';
13+
import mockQuotes from '../../_mocks_/mock-quotes-sol-sol.json';
1214

1315
// TODO remove this mock once we have a real implementation
1416
jest.mock('../../../../../selectors/confirmTransaction');
@@ -72,23 +74,21 @@ jest.mock('../../hooks/useLatestBalance', () => ({
7274
}));
7375

7476
describe('BridgeView', () => {
75-
const mockChainId = '0x1' as Hex;
76-
const optimismChainId = '0xa' as Hex;
7777
const token2Address = '0x0000000000000000000000000000000000000002' as Hex;
7878

7979
beforeEach(() => {
8080
jest.clearAllMocks();
8181
});
8282

8383
it('renders', async () => {
84-
const { getByText } = renderScreen(
84+
const { toJSON } = renderScreen(
8585
BridgeView,
8686
{
8787
name: Routes.BRIDGE.ROOT,
8888
},
8989
{ state: initialState },
9090
);
91-
expect(getByText('Select amount')).toBeDefined();
91+
expect(toJSON()).toMatchSnapshot();
9292
});
9393

9494
it('should open BridgeTokenSelector when clicking source token', async () => {
@@ -275,6 +275,8 @@ describe('BridgeView', () => {
275275
quoteRequest: {
276276
insufficientBal: true,
277277
},
278+
quotesLoadingStatus: RequestStatus.FETCHED,
279+
quotes: [mockQuotes[0] as unknown as QuoteResponse],
278280
},
279281
});
280282

@@ -295,6 +297,8 @@ describe('BridgeView', () => {
295297
quoteRequest: {
296298
insufficientBal: false,
297299
},
300+
quotesLoadingStatus: RequestStatus.FETCHED,
301+
quotes: [mockQuotes[0] as unknown as QuoteResponse],
298302
},
299303
bridgeReducerOverrides: {
300304
sourceAmount: '1.0', // Less than balance of 2.0 ETH
@@ -314,28 +318,26 @@ describe('BridgeView', () => {
314318
});
315319

316320
it('should handle Continue button press', async () => {
321+
const testState = createBridgeTestState({
322+
bridgeControllerOverrides: {
323+
quoteRequest: {
324+
insufficientBal: false,
325+
},
326+
quotesLoadingStatus: RequestStatus.FETCHED,
327+
quotes: [mockQuotes[0] as unknown as QuoteResponse],
328+
},
329+
bridgeReducerOverrides: {
330+
sourceAmount: '1.0', // Less than balance of 2.0 ETH
331+
},
332+
});
333+
317334
const { getByText } = renderScreen(
318335
BridgeView,
319336
{
320337
name: Routes.BRIDGE.ROOT,
321338
},
322339
{
323-
state: {
324-
...initialState,
325-
bridge: {
326-
...initialState.bridge,
327-
sourceAmount: '1.0',
328-
destToken: {
329-
address: token2Address,
330-
symbol: 'TOKEN2',
331-
decimals: 18,
332-
image: 'https://token2.com/logo.png',
333-
chainId: optimismChainId,
334-
},
335-
selectedDestChainId: optimismChainId,
336-
selectedSourceChainIds: [mockChainId, optimismChainId],
337-
},
338-
},
340+
state: testState,
339341
},
340342
);
341343

@@ -352,6 +354,8 @@ describe('BridgeView', () => {
352354
quoteRequest: {
353355
insufficientBal: false,
354356
},
357+
quotesLoadingStatus: RequestStatus.FETCHED,
358+
quotes: [mockQuotes[0] as unknown as QuoteResponse],
355359
},
356360
bridgeReducerOverrides: {
357361
sourceAmount: '1.0', // Less than balance of 2.0 ETH
@@ -372,4 +376,4 @@ describe('BridgeView', () => {
372376
// TODO: Add expectations once Terms navigation is implemented
373377
});
374378
});
375-
});
379+
});

0 commit comments

Comments
 (0)