Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3f7b9db
feat: wip proof of concept of quick convert flow
Matt561 Dec 16, 2025
63907f6
feat: wip: refactored musd max convert flow to be part of redesigned …
Matt561 Dec 16, 2025
0d738c6
feat: wip eod
Matt561 Dec 17, 2025
1452b5c
feat: add configurable quick convert amount
Matt561 Dec 19, 2025
031783d
feat: refactored separate useMusdConversion and useMusdMaxConversion …
Matt561 Dec 19, 2025
c76947f
feat: removed loading spinner from quick convert list item asset icon
Matt561 Dec 19, 2025
9c106e2
chore: post-rebase cleanup
Matt561 Jan 16, 2026
6b5c29e
feat: added mUSD conversion global flag guard to the quick convert se…
Matt561 Jan 16, 2026
2f7622a
wip: quick convert eod
Matt561 Jan 16, 2026
9c6c0d3
feat: cleanup
Matt561 Jan 22, 2026
1108c3d
temp: before moving away
Matt561 Jan 23, 2026
c5fff9e
feat: fixed broken import in useMusdConversion
Matt561 Feb 6, 2026
566608e
feat: removed old usages of outputChainId + added intent-based mUSD c…
Matt561 Feb 6, 2026
4609d99
feat: removed maxValueMode usage in quick convert flow
Matt561 Feb 6, 2026
a68c8c4
feat: cleanup pass on MusdQuickConvertView
Matt561 Feb 6, 2026
83bf55d
feat: first pass on max convert bottomsheet
Matt561 Feb 6, 2026
7a68d25
feat: added generic variant-based routing for confirmations
Matt561 Feb 9, 2026
c1485a4
feat: simplified variant-based routing
Matt561 Feb 9, 2026
6dc0365
feat: partial cleanup before moving to debugging duplicate pendingApp…
Matt561 Feb 9, 2026
893cc2e
feat: refactored useMusdBalance to support fiat balances and aggregat…
Matt561 Feb 10, 2026
8a30278
feat: wip before moving to fixing progressive rollout util
Matt561 Feb 11, 2026
35883df
feat: added horizontal network list when user has mUSD on multiple ne…
Matt561 Feb 11, 2026
3fd94ec
feat: cleanup
Matt561 Feb 11, 2026
411ab79
cleaned up mUSD conversion status monitoring + added temporary error …
Matt561 Feb 12, 2026
bf123ec
feat: updated useMusdConversion.initiateMaxConversion to use updated …
Matt561 Feb 13, 2026
d5c557f
feat: fix heading typo in MusdBalancesByNetworkBottomSheet
Matt561 Feb 13, 2026
88adf8e
feat: cleanup
Matt561 Feb 13, 2026
05ac837
fix: fixed quick convert error state persisting
Matt561 Feb 13, 2026
f063bee
fix: fixed fullscreen default loading spinner rendering after confirm…
Matt561 Feb 13, 2026
b99bb4b
Merge branch 'main' into feat/musd-150-quick-convert-poc
Matt561 Feb 13, 2026
e163037
feat: update existing failing tests
Matt561 Feb 13, 2026
632f163
Merge branch 'main' into feat/musd-150-quick-convert-poc
Matt561 Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .js.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ export MM_POOLED_STAKING_ENABLED="true"
export MM_POOLED_STAKING_SERVICE_INTERRUPTION_BANNER_ENABLED="true"
# mUSD
export MM_MUSD_CONVERSION_FLOW_ENABLED="false"
export MM_MUSD_QUICK_CONVERT_ENABLED="false"
# See app/components/UI/Earn/docs/wildcard-token-list.md for more information.
export MM_MUSD_CONVERTIBLE_TOKENS_BLOCKLIST=''
export MM_MUSD_CONVERTIBLE_TOKENS_ALLOWLIST=''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ const mockConversionToken = {
describe('EarnMusdConversionEducationView', () => {
const mockDispatch = jest.fn();
const mockInitiateConversion = jest.fn();
const mockInitiateMaxConversion = jest.fn();
const mockClearError = jest.fn();
const mockGoToAggregator = jest.fn();
const mockGetPreferredPaymentToken = jest.fn();
const mockGetChainIdForBuyFlow = jest.fn();
Expand Down Expand Up @@ -168,7 +170,9 @@ describe('EarnMusdConversionEducationView', () => {
});
mockUseParams.mockReturnValue(mockRouteParams);
mockUseMusdConversion.mockReturnValue({
initiateConversion: mockInitiateConversion,
initiateMaxConversion: mockInitiateMaxConversion,
initiateCustomConversion: mockInitiateConversion,
clearError: mockClearError,
error: null,
hasSeenConversionEducationScreen: false,
});
Expand Down Expand Up @@ -281,7 +285,7 @@ describe('EarnMusdConversionEducationView', () => {
);
});

// Should call initiateConversion directly, not deeplink logic
// Should call initiateCustomConversion directly, not deeplink logic
await waitFor(() => {
expect(mockInitiateConversion).toHaveBeenCalledWith({
preferredPaymentToken: {
Expand Down Expand Up @@ -591,7 +595,7 @@ describe('EarnMusdConversionEducationView', () => {
callOrder.push('dispatch');
});
mockInitiateConversion.mockImplementation(async () => {
callOrder.push('initiateConversion');
callOrder.push('initiateCustomConversion');
});

const { getByTestId } = renderWithProvider(
Expand All @@ -608,13 +612,13 @@ describe('EarnMusdConversionEducationView', () => {
});

await waitFor(() => {
expect(callOrder).toEqual(['dispatch', 'initiateConversion']);
expect(callOrder).toEqual(['dispatch', 'initiateCustomConversion']);
});
});
});

describe('conversion initiation', () => {
it('calls initiateConversion with correct params when preferredPaymentToken provided', async () => {
it('calls initiateCustomConversion with correct params when preferredPaymentToken provided', async () => {
const { getByTestId } = renderWithProvider(
<EarnMusdConversionEducationView />,
{ state: {} },
Expand Down Expand Up @@ -852,7 +856,7 @@ describe('EarnMusdConversionEducationView', () => {
});

describe('error handling', () => {
it('logs error when initiateConversion throws error', async () => {
it('logs error when initiateCustomConversion throws error', async () => {
const testError = new Error('Conversion failed');
mockInitiateConversion.mockRejectedValue(testError);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ interface EarnMusdConversionEducationViewRouteParams {
const EarnMusdConversionEducationView = () => {
const dispatch = useDispatch();

const { initiateConversion } = useMusdConversion();
const { initiateCustomConversion } = useMusdConversion();
const { goToBuy } = useRampNavigation();

const { preferredPaymentToken, isDeeplink } =
Expand Down Expand Up @@ -243,7 +243,7 @@ const EarnMusdConversionEducationView = () => {
}

if (deeplinkState.action === 'convert') {
await initiateConversion({
await initiateCustomConversion({
preferredPaymentToken: deeplinkState.paymentToken,
skipEducationCheck: true,
});
Expand All @@ -253,7 +253,7 @@ const EarnMusdConversionEducationView = () => {

// Proceed to conversion flow if we have the required params (normal flow)
if (!isDeeplink && preferredPaymentToken) {
await initiateConversion({
await initiateCustomConversion({
preferredPaymentToken,
skipEducationCheck: true,
});
Expand All @@ -272,7 +272,7 @@ const EarnMusdConversionEducationView = () => {
}
}, [
dispatch,
initiateConversion,
initiateCustomConversion,
preferredPaymentToken,
submitContinuePressedEvent,
deeplinkState,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { StyleSheet } from 'react-native';
import { Theme } from '../../../../../util/theme/models';

const styleSheet = (params: { theme: Theme }) => {
const { theme } = params;
const { colors } = theme;

return StyleSheet.create({
container: {
flex: 1,
padding: 16,
},
listContainer: {
flex: 1,
},
headerTextContainer: {
gap: 8,
},
balanceCardHeader: {
paddingTop: 16,
paddingBottom: 8,
},
headerContainer: {
paddingBottom: 16,
},
emptyContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
loadingContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
listHeaderContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
noFeesTag: {
backgroundColor: colors.background.muted,
paddingHorizontal: 6,
borderRadius: 4,
},
termsApply: {
textDecorationLine: 'underline',
},
});
};

export default styleSheet;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Test IDs for the MusdQuickConvertView screen.
*/
// TODO: Consider centralizing these test IDs in a separate file later.
export const MusdQuickConvertViewTestIds = {
CONTAINER: 'musd-quick-convert-view-container',
TOKEN_LIST: 'musd-quick-convert-view-token-list',
EMPTY_STATE: 'musd-quick-convert-view-empty-state',
LOADING: 'musd-quick-convert-view-loading',
HEADER: 'musd-quick-convert-view-header',
} as const;

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { StyleSheet } from 'react-native';
import { Theme } from '../../../../../../../util/theme/models';

const styleSheet = (_params: { theme: Theme }) =>
StyleSheet.create({
container: {
width: '100%',
justifyContent: 'space-between',
flexDirection: 'row',
},
containerPressed: {
opacity: 0.7,
},
left: {
flexDirection: 'row',
gap: 16,
},
right: {
alignItems: 'flex-end',
},
networkRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 2,
},
tokenIconContainer: {
width: 32,
height: 32,
position: 'relative',
},
tokenIcon: {
width: 32,
height: 32,
},
});

export default styleSheet;
Loading
Loading