Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [13.11.1]

### Fixed

- Fixes a crash when updating Flask (#38382)

## [13.11.0]

### Added
Expand Down Expand Up @@ -1328,7 +1334,8 @@ authorized by the user.` error until the user fully revoked dapp
- This changelog was split off with 12.22.0
- All older changes can be found in [docs/CHANGELOG_older.md](https://github.com/MetaMask/metamask-extension/blob/main/docs/CHANGELOG_older.md)

[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v13.11.0...HEAD
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v13.11.1...HEAD
[13.11.1]: https://github.com/MetaMask/metamask-extension/compare/v13.11.0...v13.11.1
[13.11.0]: https://github.com/MetaMask/metamask-extension/compare/v13.10.4...v13.11.0
[13.10.4]: https://github.com/MetaMask/metamask-extension/compare/v13.10.3...v13.10.4
[13.10.3]: https://github.com/MetaMask/metamask-extension/compare/v13.10.2...v13.10.3
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "metamask-crx",
"version": "13.11.0",
"version": "13.11.1",
"private": true,
"repository": {
"type": "git",
Expand Down
145 changes: 79 additions & 66 deletions ui/hooks/useMultichainAccountsIntroModal.test.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import { lt as semverLt } from 'semver';
import { renderHookWithProvider } from '../../test/lib/render-helpers';
import {
useMultichainAccountsIntroModal,
BIP44_ACCOUNTS_INTRODUCTION_VERSION,
} from './useMultichainAccountsIntroModal';

// Test the core logic independently of React hooks
describe('BIP-44 Banner Logic', () => {
const BIP44_ACCOUNTS_INTRODUCTION_VERSION = '13.5.0';

// Helper function that mirrors the hook's core logic
const shouldShowBip44Banner = (
describe('useMultichainAccountsIntroModal', () => {
const renderHook = (
isUnlocked: boolean,
isMultichainAccountsEnabled: boolean,
hasShownModalBefore: boolean,
hasShownMultichainAccountsIntroModal: boolean,
lastUpdatedAt: number | null,
lastUpdatedFromVersion: string | null,
isMainRoute: boolean,
previousAppVersion: string | null,
pathname: string,
) => {
const isUpgradeFromLowerThanBip44Version = Boolean(
lastUpdatedFromVersion &&
typeof lastUpdatedFromVersion === 'string' &&
semverLt(lastUpdatedFromVersion, BIP44_ACCOUNTS_INTRODUCTION_VERSION),
);

return (
isUnlocked &&
isMultichainAccountsEnabled &&
!hasShownModalBefore &&
lastUpdatedAt !== null && // null = fresh install, timestamp = upgrade
isUpgradeFromLowerThanBip44Version &&
isMainRoute
return renderHookWithProvider(
() => useMultichainAccountsIntroModal(isUnlocked, { pathname }),
{
metamask: {
remoteFeatureFlags: {
enableMultichainAccountsState2: {
enabled: isMultichainAccountsEnabled,
featureVersion: '2',
minimumVersion: BIP44_ACCOUNTS_INTRODUCTION_VERSION,
},
},
hasShownMultichainAccountsIntroModal,
previousAppVersion,
lastUpdatedAt,
},
},
);
};

Expand All @@ -39,137 +42,147 @@ describe('BIP-44 Banner Logic', () => {
};

it('shows banner for upgrade from 13.4.0', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
baseParams.isUnlocked,
baseParams.isMultichainAccountsEnabled,
baseParams.hasShownModalBefore,
baseParams.lastUpdatedAt,
'13.4.0',
baseParams.isMainRoute,
'/',
);
expect(result).toBe(true);
expect(result.current.showMultichainIntroModal).toBe(true);
});

it('shows banner for upgrade from 13.4.0-flask.0', () => {
const { result } = renderHook(
baseParams.isUnlocked,
baseParams.isMultichainAccountsEnabled,
baseParams.hasShownModalBefore,
baseParams.lastUpdatedAt,
'13.4.0-flask.0',
'/',
);
expect(result.current.showMultichainIntroModal).toBe(true);
});

it('shows banner for upgrade from 12.0.0', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
true,
true,
false,
Date.now(),
'12.0.0',
true,
'/',
);
expect(result).toBe(true);
expect(result.current.showMultichainIntroModal).toBe(true);
});

it('shows banner for upgrade from 13.4.9 (just before threshold)', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
true,
true,
false,
Date.now(),
'13.4.9',
true,
'/',
);
expect(result).toBe(true);
expect(result.current.showMultichainIntroModal).toBe(true);
});
});

describe('does NOT show banner correctly', () => {
it('does NOT show for upgrade from 13.5.0 (threshold version)', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
true,
true,
false,
Date.now(),
'13.5.0',
true,
'/',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show for upgrade from 13.7.0', () => {
const result = shouldShowBip44Banner(
it('does NOT show for upgrade from 13.5.0-flask.0 (threshold version)', () => {
const { result } = renderHook(
true,
true,
false,
Date.now(),
'13.7.0',
true,
'13.5.0-flask.0',
'/',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show for fresh install (no previous version)', () => {
const result = shouldShowBip44Banner(
it('does NOT show for upgrade from 13.7.0', () => {
const { result } = renderHook(
true,
true,
false,
Date.now(),
null,
true,
'13.7.0',
'/',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show for fresh install (no previous version)', () => {
const { result } = renderHook(true, true, false, Date.now(), null, '/');
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show when wallet is locked', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
false,
true,
false,
Date.now(),
'13.4.0',
true,
'/',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show when multichain accounts disabled', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
true,
false,
false,
Date.now(),
'13.4.0',
true,
'/',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show when modal already shown', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
true,
true,
true,
Date.now(),
'13.4.0',
true,
'/',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show on non-main route', () => {
const result = shouldShowBip44Banner(
const { result } = renderHook(
true,
true,
false,
Date.now(),
'13.4.0',
false,
'/confirmation/foo',
);
expect(result).toBe(false);
expect(result.current.showMultichainIntroModal).toBe(false);
});

it('does NOT show for fresh install (lastUpdatedAt is null)', () => {
const result = shouldShowBip44Banner(
true,
true,
false,
null,
'13.4.0',
true,
);
expect(result).toBe(false);
const { result } = renderHook(true, true, false, null, '13.4.0', '/');
expect(result.current.showMultichainIntroModal).toBe(false);
});
});
});
20 changes: 13 additions & 7 deletions ui/hooks/useMultichainAccountsIntroModal.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { useState, useEffect } from 'react';
import { lt as semverLt } from 'semver';
import { lt as semverLt, parse as semverParse } from 'semver';
import { useAppSelector } from '../store/store';
import { getIsMultichainAccountsState2Enabled } from '../selectors/multichain-accounts/feature-flags';
import { getLastUpdatedFromVersion } from '../selectors/selectors';
import { DEFAULT_ROUTE } from '../helpers/constants/routes';

// Version threshold for BIP-44 multichain accounts introduction
const BIP44_ACCOUNTS_INTRODUCTION_VERSION = '13.5.0';
export const BIP44_ACCOUNTS_INTRODUCTION_VERSION = '13.5.0';

/**
* Hook to manage the multichain accounts intro modal display logic
Expand All @@ -33,17 +32,24 @@ export function useMultichainAccountsIntroModal(
);

const lastUpdatedAt = useAppSelector((state) => state.metamask.lastUpdatedAt);
const lastUpdatedFromVersion = useAppSelector(getLastUpdatedFromVersion);
const lastUpdatedFromVersion = useAppSelector(
(state) => state.metamask.previousAppVersion,
);

useEffect(() => {
// Only show modal on the main wallet/home route
const isMainWalletArea = location.pathname === DEFAULT_ROUTE;

const parsedLastVersion = semverParse(lastUpdatedFromVersion);
// Strip prerelease versions as they just indicate build types.
const strippedLastVersion = parsedLastVersion
? `${parsedLastVersion.major}.${parsedLastVersion.minor}.${parsedLastVersion.patch}`
: null;

// Check if this is an upgrade from a version lower than BIP-44 introduction version
const isUpgradeFromLowerThanBip44Version = Boolean(
lastUpdatedFromVersion &&
typeof lastUpdatedFromVersion === 'string' &&
semverLt(lastUpdatedFromVersion, BIP44_ACCOUNTS_INTRODUCTION_VERSION),
strippedLastVersion &&
semverLt(strippedLastVersion, BIP44_ACCOUNTS_INTRODUCTION_VERSION),
);

// Show modal only for upgrades from versions < BIP-44 introduction version
Expand Down
Loading