Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0a0e35e
feat: add swap/bridge to ARC mainnet (#31413)
maxime-oe Jun 11, 2026
aa0a93f
Cherry-picking commits from main to release/7.81.1-ota for PR #31718 …
runway-github[bot] Jun 15, 2026
f6344a4
Bump OTA version to 7.81.0
weitingsun Jun 15, 2026
f237bc3
[skip ci] Bump version number to 5485
metamaskbot Jun 15, 2026
9315676
fix(card): solve conflicts
Brunonascdev Jun 12, 2026
27b8c38
Merge branch 'release/7.81.1-ota' into cherry-pick-7-81-1-7b0e275
tommasini Jun 15, 2026
fce1747
Cherry-picking commits from cherry-pick-7-81-1-7b0e275 to release/7.8…
tommasini Jun 15, 2026
bef2a15
[skip ci] Bump version number to 5489
metamaskbot Jun 15, 2026
f2741e2
Cherry-picking commits from main to release/7.81.1-ota for PR #31413 …
tommasini Jun 15, 2026
2a5240a
[skip ci] Bump version number to 5491
metamaskbot Jun 15, 2026
2b023c1
Cherry-picking commits from cherry-pick-7-81-1-1e03645 to release/7.8…
runway-github[bot] Jun 15, 2026
4ec7a07
[skip ci] Bump version number to 5494
metamaskbot Jun 15, 2026
c79c209
release: release-changelog/7.81.1 (#31738)
metamaskbotv2[bot] Jun 16, 2026
2146bfa
[skip ci] Bump version number to 5497
metamaskbot Jun 16, 2026
37d319e
revert build number bump
tommasini Jun 16, 2026
f6f85cf
Cherry-picking commits from main to release/7.81.1-ota for PR #31555 …
runway-github[bot] Jun 16, 2026
81266f1
Cherry-picking commits from main to release/7.81.1-ota for PR #31505 …
runway-github[bot] Jun 16, 2026
6e015fc
Cherry-picking commits from main to release/7.81.1-ota for PR #31721 …
runway-github[bot] Jun 16, 2026
86b3e62
Cherry-picking commits from main to release/7.81.1-ota for PR #31648 …
runway-github[bot] Jun 16, 2026
0b1e479
Merge branch 'stable' into release/7.81.1-ota
tommasini Jun 16, 2026
3f13d20
fix changelog
tommasini Jun 16, 2026
b95589a
release: 7.81.1 (OTA) (#31737)
tommasini Jun 16, 2026
30d9191
Merge origin/main into stable-main-7.81.0
metamaskbot Jun 16, 2026
94d0c18
fix: black overlay after closing txn modal (#31828)
Jwhiles Jun 17, 2026
11b01d6
chore: sync stable to main for version 7.81.0 (#31860)
metamaskbotv2[bot] Jun 17, 2026
379e331
chore: update QuickBuy typography to match Figma spec (#31877)
zone-live Jun 17, 2026
0802423
test: replace real trader names with mock names in unit tests (#31880)
xavier-brochard Jun 17, 2026
1da21b9
ci: download only necessary build artifacts for E2E (#31781)
jvbriones Jun 17, 2026
d3d0e30
feat: emit predict_deposit_and_order metrics for PWAT deposit-and-ord…
dan437 Jun 17, 2026
6bc9641
feat(ramp): headless deposit analytics tagging foundation (TRAM-3623)…
saustrie-consensys Jun 17, 2026
22b04c3
feat(predict): add Popular Today home section (#31789)
ghgoodreau Jun 17, 2026
d5c66ec
feat: MUSD-1003 replaced hardcoded 4% fallback apy with -% empty stat…
Matt561 Jun 17, 2026
8a5b8d5
feat: Bitcoin wallet standard (#27071)
NikosFotiadis Jun 17, 2026
eca8274
fix: stop inflating leaderboard ROI by 100× - TSA-727 (#31890)
joaosantos15 Jun 17, 2026
f0d798a
feat: add max support for selected source tokens (#31682)
jpuri Jun 17, 2026
baa6952
fix(money): show Send flow instead of stuck pending tx for Between ac…
Kureev Jun 17, 2026
9cb7012
fix(money): standardise Send to Perps and Predict toasts (MUSD-969) (…
Kureev Jun 17, 2026
ac19bbf
fix(card): refine Money Account <> Card linkage states for unauthenti…
Brunonascdev Jun 17, 2026
7ce2208
feat(rewards): add priority support entry point to VIP referee page (…
VGR-GIT Jun 17, 2026
dcdf748
test: fixed performance tests failing because of a new check (#31887)
javiergarciavera Jun 17, 2026
f960d7e
feat(ramp): headless RAMPS_TRANSACTION_FAILED (TRAM-3623 AC5) (3/3) (…
saustrie-consensys Jun 17, 2026
e93681b
fix: money account default selection should not work on MM Pay confir…
jpuri Jun 17, 2026
3de2515
fix: change feature flag structure to make it more generic (#31879)
jpuri Jun 17, 2026
f6ab691
feat: adding additional MM Pay metrics properties (#31886)
jpuri Jun 17, 2026
199eefc
refactor: remove `AddNewAccount` UI and snap account creation routing…
ccharly Jun 17, 2026
ede6eb1
feat(card): unblock Money Account linking and fix Card route animatio…
Brunonascdev Jun 17, 2026
0335626
perf: stabilize PerpsProgressBar withdrawalProgress selector fallback…
aganglada Jun 17, 2026
835dcdc
fix(ramps): unify RampsTransaction schema for V2 buys (#31207)
roz0n Jun 17, 2026
517b56a
feat: Enhance PredictMarketRowItem with endAccessory prop and remove …
PatrykLucka Jun 17, 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
4 changes: 2 additions & 2 deletions .github/workflows/performance-test-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ jobs:
SELECTED_SENTRY_DSN=""
SENTRY_ENVIRONMENT="github-actions-performance-e2e"
FEATURE_FLAGS_ENV="${{ inputs.feature_flags_environment }}"
BROWSERSTACK_GEO_LOCATION="${BROWSERSTACK_GEO_LOCATION:-ES}"
BROWSERSTACK_GEO_LOCATION="${BROWSERSTACK_GEO_LOCATION:-SE}"

if [[ "$FEATURE_FLAGS_ENV" != "rc" && "$FEATURE_FLAGS_ENV" != "exp" && "$FEATURE_FLAGS_ENV" != "test" && "$FEATURE_FLAGS_ENV" != "dev" && "$FEATURE_FLAGS_ENV" != "prod" ]]; then
echo "❌ Invalid feature_flags_environment '$FEATURE_FLAGS_ENV'. Expected rc, exp, test, dev, or prod."
Expand Down Expand Up @@ -258,7 +258,7 @@ jobs:
echo "QA App Version: ${{ inputs.app_version }}"
echo "BrowserStack Build Name: $BROWSERSTACK_BUILD_NAME"
echo "BrowserStack Local: $BROWSERSTACK_LOCAL"
echo "BrowserStack Geo Location: ${BROWSERSTACK_GEO_LOCATION:-ES}"
echo "BrowserStack Geo Location: ${BROWSERSTACK_GEO_LOCATION:-SE}"
if [ -n "$GREP_TAGS" ]; then
echo "Grep filter: $GREP_TAGS"
fi
Expand Down
28 changes: 22 additions & 6 deletions .github/workflows/run-e2e-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,16 +197,30 @@ jobs:
mkdir -p ${{ steps.determine-target-paths.outputs.apk-target-path }}
mkdir -p ${{ steps.determine-target-paths.outputs.test-apk-target-path }}

- name: Download Android build artifacts (Namespace)
- name: Download Android app APK (Namespace)
if: ${{ inputs.platform == 'android' && inputs.runner_provider == 'namespace' }}
uses: namespace-actions/download-artifact@7cbad919e4b0e09f17e9d6311a444ff002992b5b # v2.0.1
with:
path: artifacts/
- name: Download Android build artifacts (current)
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release.apk
path: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release.apk
- name: Download Android test APK (Namespace)
if: ${{ inputs.platform == 'android' && inputs.runner_provider == 'namespace' }}
uses: namespace-actions/download-artifact@7cbad919e4b0e09f17e9d6311a444ff002992b5b # v2.0.1
with:
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release-androidTest.apk
path: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release-androidTest.apk
- name: Download Android app APK (current)
if: ${{ inputs.platform == 'android' && inputs.runner_provider != 'namespace' }}
uses: actions/download-artifact@v4
with:
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release.apk
path: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release.apk
- name: Download Android test APK (current)
if: ${{ inputs.platform == 'android' && inputs.runner_provider != 'namespace' }}
uses: actions/download-artifact@v4
with:
path: artifacts/
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release-androidTest.apk
path: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-release-androidTest.apk

- name: Move Android artifacts to expected locations
if: ${{ inputs.platform == 'android' }}
Expand All @@ -229,12 +243,14 @@ jobs:
if: ${{ inputs.platform == 'ios' && inputs.runner_provider == 'namespace' }}
uses: namespace-actions/download-artifact@7cbad919e4b0e09f17e9d6311a444ff002992b5b # v2.0.1
with:
path: artifacts/
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-MetaMask.app
path: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-MetaMask.app
- name: Download iOS build artifacts (current)
if: ${{ inputs.platform == 'ios' && inputs.runner_provider != 'namespace' }}
uses: actions/download-artifact@v4
with:
path: artifacts/
name: ${{ inputs.build_type }}-${{ inputs.metamask_environment }}-MetaMask.app
path: artifacts/${{ inputs.build_type }}-${{ inputs.metamask_environment }}-MetaMask.app

# actions/upload-artifact strips execute permissions from the ZIP.
# Also fixes any residual case mismatch as a safety net.
Expand Down
25 changes: 18 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [7.81.1]

### Added

- Adds Swap/Bridge feature to ARC mainnet. (#31413)

### Fixed

- Fixed the MetaMask Card section on the Money screen so the "Link card" option and funding token placeholders are only shown when the card spending token is enabled in the card feature configuration. (#31611)
- Removed the trailing slash from the Arc explorer URL defined in app/util/networks/customNetworks.tsx so now the URL is correctly generated. (#31718)
- Fixed Arc native token support, included patches for MetaMask/core#9006 and MetaMask/core#9007 (#31662)

## [7.81.0]

### Added
Expand Down Expand Up @@ -84,8 +96,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added a new Positions screen for Predict users to view active positions and history (#30718)
- Track explore conversions in swaps (#30720)


### Changed

- Updated the Sei native token icon to Sei's maroon token mark. (#31038)
- Updated the Sei network and token logo to Sei's new brand mark. (#30892)
- Improve crypto movers section in explore (#30809)
Expand Down Expand Up @@ -368,10 +380,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [7.78.1]

### Fixed

- Fixed a crash caused by CloseEvent dispatch on WebSocket failing instanceof validation (#30612)

### Added

- Updated the onboarding interest questionnaire layout to a two-column grid with refreshed option labels. (#30753)
Expand Down Expand Up @@ -469,6 +477,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fixed a crash caused by CloseEvent dispatch on WebSocket failing instanceof validation (#30612)
- Fixed the "Add mUSD" option in the Money account "Add money" sheet so it opens the deposit flow with mUSD pre-selected, and (#30741)
corrected the in-progress / success / failed toast copy for both the
Convert and Add flows.
Expand Down Expand Up @@ -12078,8 +12087,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#957](https://github.com/MetaMask/metamask-mobile/pull/957): fix timeouts (#957)
- [#954](https://github.com/MetaMask/metamask-mobile/pull/954): Bugfix: onboarding navigation (#954)

[Unreleased]: https://github.com/MetaMask/metamask-mobile/compare/v7.81.0...HEAD
[7.81.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.79.1...v7.81.0
[Unreleased]: https://github.com/MetaMask/metamask-mobile/compare/v7.81.1...HEAD
[7.81.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.81.0...v7.81.1
[7.81.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.80.0...v7.81.0
[7.80.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.79.1...v7.80.0
[7.79.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.79.0...v7.79.1
[7.79.0]: https://github.com/MetaMask/metamask-mobile/compare/v7.78.1...v7.79.0
[7.78.1]: https://github.com/MetaMask/metamask-mobile/compare/v7.78.0...v7.78.1
Expand Down
8 changes: 0 additions & 8 deletions app/components/Nav/App/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -940,10 +940,6 @@ describe('App', () => {
expect(Routes.SHEET.SUCCESS_ERROR_SHEET).toBeDefined();
});

it('has add account route defined', () => {
expect(Routes.SHEET.ADD_ACCOUNT).toBeDefined();
});

it('has experience enhancer route defined', () => {
expect(Routes.SHEET.EXPERIENCE_ENHANCER).toBeDefined();
});
Expand Down Expand Up @@ -1183,10 +1179,6 @@ describe('App', () => {
expect(Routes.SHEET.ADDRESS_SELECTOR).toBeDefined();
});

it('has add account route defined', () => {
expect(Routes.SHEET.ADD_ACCOUNT).toBeDefined();
});

it('has account actions route defined', () => {
expect(Routes.SHEET.ACCOUNT_ACTIONS).toBeDefined();
});
Expand Down
5 changes: 0 additions & 5 deletions app/components/Nav/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ import SeedphraseModal from '../../UI/SeedphraseModal';
import SkipAccountSecurityModal from '../../UI/SkipAccountSecurityModal';
import SuccessErrorSheet from '../../Views/SuccessErrorSheet';
import ConfirmTurnOnBackupAndSyncModal from '../../UI/Identity/ConfirmTurnOnBackupAndSyncModal/ConfirmTurnOnBackupAndSyncModal';
import AddNewAccountBottomSheet from '../../Views/AddNewAccount/AddNewAccountBottomSheet';
import EligibilityFailedModal from '../../UI/Ramp/components/EligibilityFailedModal';
import RampUnsupportedModal from '../../UI/Ramp/components/RampUnsupportedModal';
import RampsBootstrap from '../../UI/Ramp/RampsBootstrap';
Expand Down Expand Up @@ -521,10 +520,6 @@ const RootModalFlow = (props: RootModalFlowProps) => (
name={Routes.SHEET.ADDRESS_SELECTOR}
component={AddressSelector}
/>
<Stack.Screen
name={Routes.SHEET.ADD_ACCOUNT}
component={AddNewAccountBottomSheet}
/>
<Stack.Screen name={Routes.SHEET.SDK_LOADING} component={SDKLoadingModal} />
<Stack.Screen
name={Routes.SHEET.SDK_FEEDBACK}
Expand Down
5 changes: 4 additions & 1 deletion app/components/Nav/Main/MainNavigator.js
Original file line number Diff line number Diff line change
Expand Up @@ -1421,7 +1421,10 @@ const MainNavigator = () => {
<NativeStack.Screen
name={Routes.CARD.ROOT}
component={CardRoutes}
options={fullScreenModalSlideFromBottomNativeOptions}
options={({ route }) => ({
...fullScreenModalSlideFromBottomNativeOptions,
animation: route.params?.animation ?? 'slide_from_right',
})}
/>
<NativeStack.Screen
name={Routes.RAMP.MODALS.PROCESSING_INFO}
Expand Down
9 changes: 4 additions & 5 deletions app/components/UI/Card/Views/CardHome/CardHome.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6318,9 +6318,6 @@ describe('CardHome Component', () => {

render();

expect(
screen.getByTestId(CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_TOP),
).toBeOnTheScreen();
expect(
screen.getByTestId(CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_BOTTOM),
).toBeOnTheScreen();
Expand All @@ -6339,7 +6336,9 @@ describe('CardHome Component', () => {
render();

expect(
screen.queryByTestId(CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_TOP),
screen.queryByTestId(
CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_BOTTOM,
),
).not.toBeOnTheScreen();
expect(
screen.queryByText(strings('money.metamask_card.link_title')),
Expand All @@ -6353,7 +6352,7 @@ describe('CardHome Component', () => {
render();

expect(
screen.getByTestId(CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_TOP),
screen.getByTestId(CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_BOTTOM),
).toBeOnTheScreen();
});

Expand Down
1 change: 0 additions & 1 deletion app/components/UI/Card/Views/CardHome/CardHome.testIds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,5 @@ export const CardHomeSelectors = {
FREEZE_CARD_TOGGLE: 'freeze-card-toggle',
VIEW_PIN_BUTTON: 'view-pin-button',
CARD_WALLET_ADDRESS: 'card-wallet-address',
LINK_MONEY_ACCOUNT_DIVIDER_TOP: 'link-money-account-divider-top',
LINK_MONEY_ACCOUNT_DIVIDER_BOTTOM: 'link-money-account-divider-bottom',
};
6 changes: 1 addition & 5 deletions app/components/UI/Card/Views/CardHome/CardHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,7 @@ const CardHome = () => {

{canLinkMoneyAccount && (
<>
<Box
twClassName="h-px bg-border-muted mt-4"
testID={CardHomeSelectors.LINK_MONEY_ACCOUNT_DIVIDER_TOP}
/>
<Box twClassName="mb-6 mt-4">
<Box twClassName="mb-6 mt-7">
<MoneyMetaMaskCard
mode="link"
hideCardImage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ describe('SpendingLimit Component', () => {
limitType: 'full' as const,
customLimit: '',
isLoading: false,
isUiInteractionLocked: false,
setSelectedToken: mockSetSelectedToken,
handleAccountSelect: mockHandleAccountSelect,
handleOtherSelect: mockHandleOtherSelect,
Expand Down Expand Up @@ -769,10 +770,11 @@ describe('SpendingLimit Component', () => {
);
});

it('blocks navigation when isLoading is true', () => {
it('blocks navigation when UI interaction is locked', () => {
mockUseSpendingLimit.mockReturnValue({
...getDefaultUseSpendingLimitMock(),
isLoading: true,
isUiInteractionLocked: true,
});

render();
Expand All @@ -785,6 +787,42 @@ describe('SpendingLimit Component', () => {
expect(mockEvent.preventDefault).toHaveBeenCalled();
});

it('allows navigation when Money Account linkage is processing outside onboarding', () => {
mockUseSpendingLimit.mockReturnValue({
...getDefaultUseSpendingLimitMock(),
isLoading: true,
isMoneyAccountSource: true,
isUiInteractionLocked: false,
});

render();

const mockEvent = { preventDefault: jest.fn() };
const beforeRemoveCallback = mockAddListener.mock.calls[0][1];

beforeRemoveCallback(mockEvent);

expect(mockEvent.preventDefault).not.toHaveBeenCalled();
});

it('blocks navigation when Money Account linkage is processing during onboarding', () => {
mockUseSpendingLimit.mockReturnValue({
...getDefaultUseSpendingLimitMock(),
isLoading: true,
isMoneyAccountSource: true,
isUiInteractionLocked: true,
});

render({ params: { flow: 'onboarding' } });

const mockEvent = { preventDefault: jest.fn() };
const beforeRemoveCallback = mockAddListener.mock.calls[0][1];

beforeRemoveCallback(mockEvent);

expect(mockEvent.preventDefault).toHaveBeenCalled();
});

it('allows navigation when isLoading is false', () => {
render();

Expand Down Expand Up @@ -853,12 +891,28 @@ describe('SpendingLimit Component', () => {
...getDefaultUseSpendingLimitMock(),
isLoading: true,
isMoneyAccountSource: true,
isUiInteractionLocked: false,
});

render();

expect(screen.queryByTestId('button-loading-indicator')).toBeNull();
});

it('disables cancel when Money Account linkage is processing outside onboarding', () => {
mockUseSpendingLimit.mockReturnValue({
...getDefaultUseSpendingLimitMock(),
isLoading: true,
isMoneyAccountSource: true,
isUiInteractionLocked: false,
});

render();

const cancelButton = screen.getByText('Cancel');

expect(cancelButton).toBeDisabled();
});
});

describe('Onboarding Flow', () => {
Expand Down
9 changes: 5 additions & 4 deletions app/components/UI/Card/Views/SpendingLimit/SpendingLimit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ const SpendingLimit: React.FC<SpendingLimitProps> = ({ route }) => {
limitType,
customLimit,
isLoading,
isUiInteractionLocked,
handleAccountSelect,
handleOtherSelect,
handleLimitSelect,
Expand All @@ -129,14 +130,14 @@ const SpendingLimit: React.FC<SpendingLimitProps> = ({ route }) => {
routeParams: route?.params as Record<string, unknown> | undefined,
});

const isLoadingRef = useRef(isLoading);
const isUiInteractionLockedRef = useRef(isUiInteractionLocked);
useEffect(() => {
isLoadingRef.current = isLoading;
}, [isLoading]);
isUiInteractionLockedRef.current = isUiInteractionLocked;
}, [isUiInteractionLocked]);

useEffect(() => {
const unsubscribe = navigation.addListener('beforeRemove', (e) => {
if (!isLoadingRef.current) return;
if (!isUiInteractionLockedRef.current) return;
e.preventDefault();
});
return unsubscribe;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@metamask/design-system-react-native';
import { CardMessageBoxType, CardMessageBoxVariant } from '../../types';
import { strings } from '../../../../../../locales/i18n';
import { FLAT_BANNER_ALERT_STYLE } from '../../../shared/flatBannerAlertStyle';

interface CardMessageBoxProps {
messageType: CardMessageBoxType;
Expand Down Expand Up @@ -84,6 +85,7 @@ const CardMessageBox = ({
severity={SEVERITY_MAP[config.variant]}
title={config.title}
description={config.description}
style={FLAT_BANNER_ALERT_STYLE}
testID="card-message-box"
>
{(onConfirm || onDismiss) && (
Expand Down
Loading
Loading