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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@metamask/core-monorepo",
"version": "983.0.0",
"version": "985.0.0",
"private": true,
"description": "Monorepo for packages shared between MetaMask clients",
"repository": {
Expand Down
6 changes: 6 additions & 0 deletions packages/assets-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Bump `@metamask/transaction-controller` from `^65.3.0` to `^65.4.0` ([#8796](https://github.com/MetaMask/core/pull/8796))
- Bump `@metamask/core-backend` from `^6.2.2` to `^6.3.0` ([#8813](https://github.com/MetaMask/core/pull/8813))

### Fixed

- Non-EVM assets with a `slip44` asset namespace (e.g. Bitcoin, Solana native, TRON) are now correctly typed as `native` instead of `erc20` in `assetsInfo` ([#8811](https://github.com/MetaMask/core/pull/8811))
- Solana SPL tokens (CAIP-19 `solana:.../token:<address>`) are now correctly typed as `spl` instead of `erc20` in `assetsInfo` ([#8811](https://github.com/MetaMask/core/pull/8811))

## [7.1.2]

Expand Down
2 changes: 1 addition & 1 deletion packages/assets-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"@metamask/base-controller": "^9.1.0",
"@metamask/client-controller": "^1.0.1",
"@metamask/controller-utils": "^12.1.0",
"@metamask/core-backend": "^6.2.2",
"@metamask/core-backend": "^6.3.0",
"@metamask/keyring-api": "^23.1.0",
"@metamask/keyring-controller": "^25.5.0",
"@metamask/keyring-internal-api": "^11.0.1",
Expand Down
11 changes: 9 additions & 2 deletions packages/assets-controller/src/AssetsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import type { Hex } from '@metamask/utils';
import {
isCaipChainId,
isStrictHexString,
KnownCaipNamespace,
parseCaipAssetType,
parseCaipChainId,
} from '@metamask/utils';
Expand All @@ -82,7 +83,10 @@ import type { AccountsControllerAccountBalancesUpdatedEvent } from './data-sourc
import { SnapDataSource } from './data-sources/SnapDataSource';
import type { StakedBalanceDataSourceConfig } from './data-sources/StakedBalanceDataSource';
import { StakedBalanceDataSource } from './data-sources/StakedBalanceDataSource';
import { TokenDataSource } from './data-sources/TokenDataSource';
import {
CaipAssetNamespace,
TokenDataSource,
} from './data-sources/TokenDataSource';
import {
CHAINS_WITH_DEFAULT_TRACKED_ASSETS,
DEFAULT_TRACKED_ASSETS_BY_CHAIN,
Expand Down Expand Up @@ -1663,7 +1667,10 @@ export class AssetsController extends BaseController<
let tokenType: FungibleAssetMetadata['type'] = 'erc20';
if (this.#isNativeAsset(normalizedAssetId)) {
tokenType = 'native';
} else if (parsed.assetNamespace === 'spl') {
} else if (
parsed.chain.namespace === KnownCaipNamespace.Solana &&
parsed.assetNamespace === CaipAssetNamespace.Token
) {
tokenType = 'spl';
}

Expand Down
2 changes: 1 addition & 1 deletion packages/assets-controller/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ type Caip19AssetId = string;
// - Native ETH: "eip155:1/slip44:60"
// - USDC on Ethereum: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
// - SOL: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501"
// - SPL Token: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5..."
// - SPL Token: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5..."

// CAIP-2 chain identifier
type ChainId = string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ const MOCK_ADDRESS = '0x1234567890123456789012345678901234567890';
const MOCK_TOKEN_ASSET =
'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' as Caip19AssetId;
const MOCK_NATIVE_ASSET = 'eip155:1/slip44:60' as Caip19AssetId;
const MOCK_BTC_ASSET =
'bip122:000000000019d6689c085ae165831e93/slip44:0' as Caip19AssetId;
const MOCK_SOL_NATIVE_ASSET =
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501' as Caip19AssetId;
const MOCK_TRX_ASSET = 'tron:728126428/slip44:195' as Caip19AssetId;
const MOCK_SPL_ASSET =
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' as Caip19AssetId;
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' as Caip19AssetId;

type MockApiClient = {
tokens: {
Expand Down Expand Up @@ -516,6 +521,57 @@ describe('TokenDataSource', () => {
expect(context.response.assetsInfo?.[MOCK_SPL_ASSET]?.type).toBe('spl');
});

it.each([
{
label: 'Bitcoin (bip122/slip44)',
assetId: MOCK_BTC_ASSET,
chainId: 'bip122:000000000019d6689c085ae165831e93',
name: 'Bitcoin',
symbol: 'BTC',
decimals: 8,
},
{
label: 'SOL native (solana/slip44)',
assetId: MOCK_SOL_NATIVE_ASSET,
chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
name: 'Solana',
symbol: 'SOL',
decimals: 9,
},
{
label: 'TRX native (tron/slip44)',
assetId: MOCK_TRX_ASSET,
chainId: 'tron:728126428',
name: 'TRON',
symbol: 'TRX',
decimals: 6,
},
])(
'middleware types non-EVM slip44 asset as native: $label',
async ({ assetId, chainId, name, symbol, decimals }) => {
const { controller } = setupController({
messenger: createTestMessenger(),
supportedNetworks: [chainId],
assetsResponse: [
createMockAssetResponse(assetId, { name, symbol, decimals }),
],
});

const next = jest.fn().mockResolvedValue(undefined);
const context = createMiddlewareContext({
response: {
detectedAssets: {
'mock-account-id': [assetId],
},
},
});

await controller.assetsMiddleware(context, next);

expect(context.response.assetsInfo?.[assetId]?.type).toBe('native');
},
);

it('middleware merges metadata into existing response', async () => {
const anotherAsset =
'eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f' as Caip19AssetId;
Expand Down
13 changes: 10 additions & 3 deletions packages/assets-controller/src/data-sources/TokenDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const BULK_SCAN_BATCH_SIZE = 100;
const MIN_TOKEN_OCCURRENCES = 3;

/** CAIP-19 `assetNamespace` segments used across filtering logic. */
enum CaipAssetNamespace {
export enum CaipAssetNamespace {
Slip44 = 'slip44',
Erc20 = 'erc20',
Token = 'token',
Expand Down Expand Up @@ -102,11 +102,18 @@ function transformV3AssetResponseToMetadata(
const parsed = parseCaipAssetType(assetId);
let tokenType: 'native' | 'erc20' | 'spl' = 'erc20';

if (nativeAssetIds.has(assetId.toLowerCase())) {
if (
nativeAssetIds.has(assetId.toLowerCase()) ||
parsed.assetNamespace === CaipAssetNamespace.Slip44
) {
tokenType = 'native';
} else if (parsed.assetNamespace === 'spl') {
} else if (
parsed.chain.namespace === KnownCaipNamespace.Solana &&
parsed.assetNamespace === CaipAssetNamespace.Token
) {
tokenType = 'spl';
}
// TODO: Add support for Tron trc20 standard

const metadata: FungibleAssetMetadata = {
// Type derived from assetId
Expand Down
2 changes: 1 addition & 1 deletion packages/assets-controller/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import type { CaipAssetType, CaipChainId, Json } from '@metamask/utils';
* - Native: "eip155:1/slip44:60" (ETH)
* - ERC20: "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" (USDC)
* - ERC721: "eip155:1/erc721:0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D/1234" (BAYC #1234)
* - SPL: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
* - SPL: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
*/
export type Caip19AssetId = CaipAssetType;

Expand Down
1 change: 1 addition & 0 deletions packages/assets-controllers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Bump `@metamask/transaction-controller` from `^65.3.0` to `^65.4.0` ([#8796](https://github.com/MetaMask/core/pull/8796))
- Bump `@metamask/core-backend` from `^6.2.2` to `^6.3.0` ([#8813](https://github.com/MetaMask/core/pull/8813))

## [108.1.0]

Expand Down
2 changes: 1 addition & 1 deletion packages/assets-controllers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"@metamask/base-controller": "^9.1.0",
"@metamask/contract-metadata": "^2.4.0",
"@metamask/controller-utils": "^12.1.0",
"@metamask/core-backend": "^6.2.2",
"@metamask/core-backend": "^6.3.0",
"@metamask/eth-query": "^4.0.0",
"@metamask/keyring-api": "^23.1.0",
"@metamask/keyring-controller": "^25.5.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/bridge-controller/src/selectors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('Bridge Selectors', () => {
exchangeRate: '2.5',
usdExchangeRate: '1.5',
},
'solana:101/spl:456': {
'solana:101/token:456': {
exchangeRate: '3.0',
},
},
Expand Down
7 changes: 5 additions & 2 deletions packages/core-backend/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [6.3.0]

### Added

- Add `OHLCVService` for real-time OHLCV (candlestick) data streaming via WebSocket ([#8695](https://github.com/MetaMask/core/pull/8695))
Expand Down Expand Up @@ -68,7 +70,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Bump `@metamask/accounts-controller` from `^36.0.0` to `^37.0.0` ([#7996](https://github.com/MetaMask/core/pull/7996)), ([#8140](https://github.com/MetaMask/core/pull/8140))
- Bump `@metamask/accounts-controller` from `^36.0.0` to `^37.0.0` ([#7996](https://github.com/MetaMask/core/pull/7996), [#8140](https://github.com/MetaMask/core/pull/8140))
- Bump `@metamask/controller-utils` from `^11.18.0` to `^11.19.0` ([#7995](https://github.com/MetaMask/core/pull/7995))

## [6.0.0]
Expand Down Expand Up @@ -282,7 +284,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Type definitions** - Comprehensive TypeScript types for transactions, balances, WebSocket messages, and service configurations
- **Logging infrastructure** - Structured logging with module-specific loggers for debugging and monitoring

[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/core-backend@6.2.2...HEAD
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/core-backend@6.3.0...HEAD
[6.3.0]: https://github.com/MetaMask/core/compare/@metamask/core-backend@6.2.2...@metamask/core-backend@6.3.0
[6.2.2]: https://github.com/MetaMask/core/compare/@metamask/core-backend@6.2.1...@metamask/core-backend@6.2.2
[6.2.1]: https://github.com/MetaMask/core/compare/@metamask/core-backend@6.2.0...@metamask/core-backend@6.2.1
[6.2.0]: https://github.com/MetaMask/core/compare/@metamask/core-backend@6.1.1...@metamask/core-backend@6.2.0
Expand Down
2 changes: 1 addition & 1 deletion packages/core-backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@metamask/core-backend",
"version": "6.2.2",
"version": "6.3.0",
"description": "Core backend services for MetaMask",
"keywords": [
"Ethereum",
Expand Down
5 changes: 5 additions & 0 deletions packages/notification-services-controller/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `registerPushNotifications` to `NotificationServicesControllerEnableNotificationsOptions` so clients can enable MetaMask notifications without registering push notifications. ([#8782](https://github.com/MetaMask/core/pull/8782))
- Add optional mobile OS and app version metadata to push token registrations so clients can provide Firebase error attribution data. ([#8782](https://github.com/MetaMask/core/pull/8782))

## [24.0.0]

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export type NotificationServicesControllerSetFeatureAnnouncementsEnabledAction =
* Used only during initialization to seed marketing push notifications.
* @param opts.productAnnouncementEnabled - The user's product-announcement flag.
* Used only during initialization to seed marketing in-app notifications.
* @param opts.registerPushNotifications - Whether to attempt FCM/device push registration.
* @returns The updated or newly created user storage.
* @throws {Error} Throws an error if unauthenticated or from other operations.
*/
Expand All @@ -72,7 +73,7 @@ export type NotificationServicesControllerCreateOnChainTriggersAction = {
* Enables all MetaMask notifications for the user.
* This is identical flow when initializing notifications for the first time.
*
* @param opts - Optional settings for first-time AUS notification preferences initialization.
* @param opts - Optional options to mutate this functionality.
* @throws {Error} If there is an error during the process of enabling notifications.
*/
export type NotificationServicesControllerEnableMetamaskNotificationsAction = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,45 @@ describe('NotificationServicesController', () => {
]);
});

it('skips push registration when registerPushNotifications is false', async () => {
const {
messenger,
mockEnablePushNotifications,
mockGetConfig,
mockUpdateNotifications,
mockKeyringControllerGetState,
} = arrangeMocks({
configurePrefs: (mock) => mock.mockResolvedValueOnce(null),
});

mockKeyringControllerGetState.mockReturnValue({
isUnlocked: true,
keyrings: [
{
accounts: [ADDRESS_1],
type: KeyringTypes.hd,
metadata: { id: 'srp-1', name: 'SRP 1' },
},
],
});
const mockTriggerQuery = mockGetOnChainNotificationsConfig();

const controller = new NotificationServicesController({
messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
});

await controller.createOnChainTriggers({
registerPushNotifications: false,
});

expect(mockGetConfig).toHaveBeenCalled();
expect(mockTriggerQuery.isDone()).toBe(true);
expect(mockUpdateNotifications).toHaveBeenCalled();
expect(controller.state.isNotificationServicesEnabled).toBe(true);
expect(mockEnablePushNotifications).not.toHaveBeenCalled();
});

it('enables all wallet-activity accounts when Trigger API has no enabled accounts for first-time setup', async () => {
const {
messenger,
Expand Down Expand Up @@ -1447,6 +1486,28 @@ describe('NotificationServicesController', () => {
expect(mocks.mockUpdateNotifications).toHaveBeenCalled();
});

it('forwards registerPushNotifications false when enabling MetaMask notifications', async () => {
const mocks = arrangeMocks({
configurePrefs: (mock) => mock.mockResolvedValueOnce(null),
});
const mockTriggerQuery = mockGetOnChainNotificationsConfig();

const controller = new NotificationServicesController({
messenger: mocks.messenger,
env: { featureAnnouncements: featureAnnouncementsEnv },
});

await controller.enableMetamaskNotifications({
registerPushNotifications: false,
});

expect(mocks.mockGetConfig).toHaveBeenCalled();
expect(mockTriggerQuery.isDone()).toBe(true);
expect(mocks.mockUpdateNotifications).toHaveBeenCalled();
expect(controller.state.isNotificationServicesEnabled).toBe(true);
expect(mocks.mockEnablePushNotifications).not.toHaveBeenCalled();
});

it('should not create new notification subscriptions when enabling an account that already has notifications', async () => {
const mocks = arrangeMocks({
// Mock fully-initialized existing notifications
Expand Down
Loading
Loading