Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5587761
feat(wallet): wire ClaimsService and ClaimsController initialization
tuna1207 Jul 22, 2026
4285b44
docs(wallet): add Claims initialization changelog entry
tuna1207 Jul 22, 2026
be1ebc7
refactor: claim controller export env
tuna1207 Jul 22, 2026
8be9983
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Jul 22, 2026
84750e0
refactor(wallet): nest ClaimsService under claims-controller init
tuna1207 Jul 22, 2026
7dc5df2
refactor(wallet): re-export claims Env as ClaimsEnv
tuna1207 Jul 22, 2026
19de465
docs(wallet-cli): note claimsService instance options wiring
tuna1207 Jul 22, 2026
8a31a85
fix: lint
tuna1207 Jul 23, 2026
0efe75a
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Jul 23, 2026
4446ad5
fix: changelog
tuna1207 Jul 23, 2026
745fd37
fix: lint
tuna1207 Jul 23, 2026
17bf62a
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Jul 29, 2026
588cda9
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Jul 30, 2026
458c94b
refactor(claims-controller): update ClaimsService environment handling
tuna1207 Jul 30, 2026
a93ecdb
chore: update changelog
tuna1207 Jul 30, 2026
022dd84
fix: remove unneeded import
tuna1207 Jul 30, 2026
e799716
feat(claims-controller): add ClaimsControllerOptions and ClaimsServic…
tuna1207 Jul 30, 2026
6af6ff4
chore: update changelog
tuna1207 Jul 30, 2026
9edc0c4
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Aug 1, 2026
063e097
feat: enhance Claims Service Integration
tuna1207 Aug 2, 2026
99dba27
fix: lint
tuna1207 Aug 2, 2026
5f5394d
feat: enhance ClaimsService with bearer token handling and caching logic
tuna1207 Aug 2, 2026
c0be717
test: add handling for malformed GET responses in ClaimsService tests
tuna1207 Aug 2, 2026
b57ba9b
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Aug 4, 2026
01d318f
feat(claims-controller): add query invalidation before submitting claims
tuna1207 Aug 4, 2026
507508c
refactor(claims-controller): remove query invalidation logic from Cla…
tuna1207 Aug 4, 2026
6063e21
feat(claims-controller): integrate session profile into ClaimsService…
tuna1207 Aug 4, 2026
e74a5d6
refactor(claims-controller): update caching logic to use profileId in…
tuna1207 Aug 4, 2026
e7ed2be
fix: update test
tuna1207 Aug 4, 2026
406e0ce
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Aug 5, 2026
0217d8b
fix: package version
tuna1207 Aug 5, 2026
d2910fe
fix: update package version
tuna1207 Aug 5, 2026
9f0c1a4
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Aug 5, 2026
a21a7ad
feat: update ClaimsService to make fetchFunction optional, defaulting…
tuna1207 Aug 6, 2026
a2f64e0
chore: update CHANGELOG to reflect changes in wallet-cli daemon behav…
tuna1207 Aug 6, 2026
679056e
Merge branch 'main' into feat/claim-controller-mm-wallet
tuna1207 Aug 6, 2026
e6c1c54
fix: test
tuna1207 Aug 6, 2026
a0c7a54
Merge commit 'c344f4d1831ab7b0d3ef798edc99cad660c9dcb3' into feat/cla…
tuna1207 Aug 6, 2026
bcc2c08
fix: test
tuna1207 Aug 6, 2026
0402bc0
refactor: replace 'object' with 'type' in ClaimsService-structs and e…
tuna1207 Aug 6, 2026
636d78e
fix: test
tuna1207 Aug 6, 2026
1b7eef8
refactor: remove redundant ClaimsController type and related imports …
tuna1207 Aug 7, 2026
4d3a865
test: update claims-service tests to reflect changes in options handl…
tuna1207 Aug 7, 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 .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
/packages/wallet/src/initialization/instances/accounts-controller/ @MetaMask/accounts-engineers
/packages/wallet/src/initialization/instances/address-book-controller/ @MetaMask/confirmations
/packages/wallet/src/initialization/instances/approval-controller/ @MetaMask/confirmations
/packages/wallet/src/initialization/instances/claims-controller/ @MetaMask/web3auth
/packages/wallet/src/initialization/instances/connectivity-controller/ @MetaMask/core-platform
/packages/wallet/src/initialization/instances/gas-fee-controller/ @MetaMask/confirmations
/packages/wallet/src/initialization/instances/keyring-controller/ @MetaMask/accounts-engineers @MetaMask/core-platform
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,7 @@ linkStyle default opacity:0.5
wallet --> address_book_controller;
wallet --> approval_controller;
wallet --> base_controller;
wallet --> claims_controller;
wallet --> connectivity_controller;
wallet --> controller_utils;
wallet --> gas_fee_controller;
Expand Down
1 change: 1 addition & 0 deletions codeowners.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ const PACKAGES: Record<string, PackageInfo> = {
},
'claims-controller': {
teams: ['@MetaMask/web3auth'],
initializationPath: 'claims-controller',
},
'client-controller': {
teams: [
Expand Down
1 change: 1 addition & 0 deletions packages/wallet-cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Wire the `claimsService` slot in the daemon wallet's instance options (`ClaimsEnv.PRD` and `globalThis.fetch`), so the daemon initializes `ClaimsService` with the wallet's required configuration ([#9588](https://github.com/MetaMask/core/pull/9588))
- Add the `mm wallet send` command and a dedicated daemon `sendTransaction` RPC handler for sending a transaction through the daemon-hosted `TransactionController` ([#9636](https://github.com/MetaMask/core/pull/9636))
- The command converts the ether `--value` to wei, resolves the network client (`--network-client-id` or `--chain-id`) and sender (defaulting to the selected account), previews the resolved plan, and broadcasts after confirmation, printing the resulting transaction hash. `--yes` skips the prompt; `--dry-run` resolves and validates without broadcasting.
- The `sendTransaction` handler awaits the broadcast server-side and returns a serializable `{ transactionHash, transactionId, status }`, because `addTransaction`'s `result` promise cannot travel back over the generic `call` dispatch. Transactions are submitted as internal (auto-approved by the daemon).
Expand Down
3 changes: 3 additions & 0 deletions packages/wallet-cli/src/daemon/wallet-factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ describe('createWallet', () => {
);
expect(instanceOptions.transactionController?.disableSwaps).toBe(true);
expect(instanceOptions.transactionController?.hooks).toStrictEqual({});
expect(instanceOptions.claimsService).toStrictEqual({
fetchFunction: globalThis.fetch,
});
expect(ClientConfigApiService).toHaveBeenCalled();

await dispose();
Expand Down
6 changes: 6 additions & 0 deletions packages/wallet-cli/src/daemon/wallet-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { InMemoryStorageAdapter } from '@metamask/storage-service';
import type { Json } from '@metamask/utils';
import {
AlwaysOnlineAdapter,
ClaimsEnv,
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
importSecretRecoveryPhrase,
Wallet,
} from '@metamask/wallet';
Expand Down Expand Up @@ -83,6 +84,8 @@ export type CreateWalletResult = {
* - `transactionController` — swaps processing disabled and no client hooks;
* see the slot's inline comment for why the daemon relies on the
* controller's defaults for everything else.
* - `claimsService` — production Claims API environment and the platform
* `fetch` implementation.
*
* The optional `keyringController` slot is intentionally omitted so the
* controller's built-in defaults (e.g. the PBKDF2 encryptor) apply.
Expand Down Expand Up @@ -142,6 +145,9 @@ function buildInstanceOptions(
// the controller's default.
hooks: {},
},
claimsService: {
fetchFunction: globalThis.fetch,
},
};
}

Expand Down
4 changes: 4 additions & 0 deletions packages/wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- **BREAKING:** Wire `ClaimsService` and `ClaimsController` into the default wallet initialization ([#9588](https://github.com/MetaMask/core/pull/9588))
- Passing `instanceOptions.claimsService.env` is now required.
Comment thread
tuna1207 marked this conversation as resolved.
Outdated
- Passing `instanceOptions.claimsService.fetchFunction` is now required.
- `ClaimsService` delegates `AuthenticationController:getBearerToken`; hosts must register `AuthenticationController` on the supplied root messenger before authenticated Claims API calls succeed.
- **BREAKING:** Wire analytics into the default `NetworkController` initialization ([#9270](https://github.com/MetaMask/core/pull/9270))
- Adds an optional `instanceOptions.networkController.analyticsOptions` option (`isRpcEndpointUrlPublic` and `rpcServiceEventsSampleRate`, both optional) that the controller uses to emit `RPC Service Unavailable` and `RPC Service Degraded` events.
- The `Wallet` root messenger now requires the `AnalyticsController:getState` and `AnalyticsController:trackEvent` actions. Consumers must register handlers for them on the root messenger; a consumer that does not use analytics can register handlers that do nothing.
Expand Down
1 change: 1 addition & 0 deletions packages/wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"@metamask/approval-controller": "^9.0.2",
"@metamask/base-controller": "^9.1.0",
"@metamask/browser-passworder": "^6.0.0",
"@metamask/claims-controller": "^0.5.3",
"@metamask/connectivity-controller": "^0.3.0",
"@metamask/controller-utils": "^12.3.0",
"@metamask/gas-fee-controller": "^26.3.0",
Expand Down
157 changes: 44 additions & 113 deletions packages/wallet/src/Wallet.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getDefaultAddressBookControllerState } from '@metamask/address-book-controller';
import { Env } from '@metamask/claims-controller';
import { getDefaultClaimsControllerState } from '@metamask/claims-controller';
import { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller';
import { Messenger } from '@metamask/messenger';
import { InMemoryStorageAdapter } from '@metamask/storage-service';
Expand All @@ -8,6 +10,7 @@ import { webcrypto } from 'crypto';
import MockEncryptor from '../../keyring-controller/tests/mocks/mockEncryptor.js';
import * as initializationModule from './initialization/initialization.js';
import { AlwaysOnlineAdapter } from './initialization/instances/connectivity-controller/always-online-adapter.js';
import type { WalletOptions } from './types.js';
import { importSecretRecoveryPhrase } from './utilities.js';
import { Wallet } from './Wallet.js';

Expand All @@ -23,23 +26,31 @@ const REMOTE_FEATURE_FLAG_OPTIONS = {
},
};

function getInstanceOptions(): WalletOptions['instanceOptions'] {
return {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
claimsService: {
env: Env.DEV,
fetchFunction: globalThis.fetch,
},
};
}

async function setupWallet(): Promise<Wallet> {
const wallet = new Wallet({
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
instanceOptions: getInstanceOptions(),
});

await importSecretRecoveryPhrase(wallet, TEST_PASSWORD, TEST_SRP);
Expand Down Expand Up @@ -89,22 +100,10 @@ describe('Wallet', () => {
it('supports passing instance options', async () => {
const wallet = new Wallet({
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
...getInstanceOptions(),
keyringController: {
encryptor: new MockEncryptor(),
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
});

Expand Down Expand Up @@ -143,21 +142,7 @@ describe('Wallet', () => {
init: (): DummyService => new DummyService(),
},
],
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
instanceOptions: getInstanceOptions(),
});
const { state } = wallet;

Expand Down Expand Up @@ -189,21 +174,7 @@ describe('Wallet', () => {
});

const wallet = new Wallet({
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
instanceOptions: getInstanceOptions(),
});

expect(wallet.controllerMetadata).toStrictEqual({
Expand Down Expand Up @@ -302,21 +273,7 @@ describe('Wallet', () => {
addressBook: { '0x1': { [ADDRESS]: entry } },
},
},
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
instanceOptions: getInstanceOptions(),
});

expect(
Expand All @@ -337,21 +294,7 @@ describe('Wallet', () => {
describe('ConnectivityController', () => {
it('reports online connectivity status', () => {
const wallet = new Wallet({
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
instanceOptions: getInstanceOptions(),
});

expect(wallet.state.ConnectivityController.connectivityStatus).toBe(
Expand Down Expand Up @@ -380,21 +323,7 @@ describe('Wallet', () => {
vault,
},
},
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
storageService: {
storage: new InMemoryStorageAdapter(),
},
remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS,
},
instanceOptions: getInstanceOptions(),
});

await wallet.messenger.call(
Expand Down Expand Up @@ -472,17 +401,8 @@ describe('Wallet', () => {
it('routes injected instanceOptions through to the controller', async () => {
const wallet = new Wallet({
instanceOptions: {
connectivityController: {
connectivityAdapter: new AlwaysOnlineAdapter(),
},
gasFeeController: {
clientId: 'test',
},
networkController: {
infuraProjectId: 'fake-infura-project-id',
},
...getInstanceOptions(),
keyringController: { encryptor: new MockEncryptor() },
storageService: { storage: new InMemoryStorageAdapter() },
remoteFeatureFlagController: {
clientConfigApiService: {
fetchRemoteFeatureFlags: async (): Promise<{
Expand All @@ -508,4 +428,15 @@ describe('Wallet', () => {
).toStrictEqual({ testFlag: true });
});
});

describe('ClaimsController', () => {
it('is wired and exposes its state on the wallet messenger', async () => {
const wallet = await setupWallet();
const { messenger } = wallet;

expect(messenger.call('ClaimsController:getState')).toStrictEqual(
getDefaultClaimsControllerState(),
);
});
});
});
Loading
Loading