From baa44729ae6b80d7c695412eb9228b1cbbf1dcec Mon Sep 17 00:00:00 2001 From: Dimitris Marlagkoutsos Date: Tue, 21 Jul 2026 21:03:13 +0300 Subject: [PATCH] feat(wallet)!: wire `GasFeeController` into default initialization Wire `GasFeeController` into `@metamask/wallet`'s default initialization set as its own `InitializationConfiguration`, mirroring the `transaction-controller` / `network-controller` instances. A wired `TransactionController` delegates `GasFeeController:fetchGasFeeEstimates` lazily, so the wallet boots today but throws the first time a transaction flow needs gas estimates; wiring `GasFeeController` supplies that handler. Adds a required `instanceOptions.gasFeeController` option whose `clientId` (sent as `X-Client-Id` to the gas API) is required, so every client identifies itself; all other fields are optional and fall back to platform-agnostic defaults. wallet-cli passes `clientId: 'cli'`. The instance builds `getProvider` / `getCurrentNetworkEIP1559Compatibility` as lazy closures over `NetworkController`, and `GasFeeController` was made initialization-order-agnostic upstream (#9569), so no dependency-ordering machinery is needed. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/CODEOWNERS | 1 + README.md | 1 + codeowners.ts | 1 + packages/wallet-cli/CHANGELOG.md | 1 + .../src/daemon/wallet-factory.test.ts | 1 + .../wallet-cli/src/daemon/wallet-factory.ts | 5 + packages/wallet/CHANGELOG.md | 2 + packages/wallet/package.json | 1 + packages/wallet/src/Wallet.test.ts | 24 ++ .../gas-fee-controller.test.ts | 239 ++++++++++++++++++ .../gas-fee-controller/gas-fee-controller.ts | 77 ++++++ .../instances/gas-fee-controller/types.ts | 30 +++ .../src/initialization/instances/index.ts | 1 + .../transaction-controller.test.ts | 3 + packages/wallet/src/types.ts | 2 + packages/wallet/tsconfig.build.json | 1 + packages/wallet/tsconfig.json | 3 + yarn.lock | 1 + 18 files changed, 394 insertions(+) create mode 100644 packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.test.ts create mode 100644 packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.ts create mode 100644 packages/wallet/src/initialization/instances/gas-fee-controller/types.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f7d8e29ec70..360764abba6 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -150,6 +150,7 @@ /packages/wallet/src/initialization/instances/address-book-controller/ @MetaMask/confirmations /packages/wallet/src/initialization/instances/approval-controller/ @MetaMask/confirmations /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 /packages/wallet/src/initialization/instances/passkey-controller/ @MetaMask/web3auth /packages/wallet/src/initialization/instances/remote-feature-flag-controller/ @MetaMask/extension-platform @MetaMask/mobile-platform @MetaMask/core-platform diff --git a/README.md b/README.md index ec3d61dc7b9..e03df83f857 100644 --- a/README.md +++ b/README.md @@ -649,6 +649,7 @@ linkStyle default opacity:0.5 wallet --> base_controller; wallet --> connectivity_controller; wallet --> controller_utils; + wallet --> gas_fee_controller; wallet --> keyring_controller; wallet --> messenger; wallet --> network_controller; diff --git a/codeowners.ts b/codeowners.ts index ce77d6b6877..2a864d499ba 100644 --- a/codeowners.ts +++ b/codeowners.ts @@ -160,6 +160,7 @@ const PACKAGES: Record = { }, 'gas-fee-controller': { teams: ['@MetaMask/confirmations'], + initializationPath: 'gas-fee-controller', }, 'gator-permissions-controller': { teams: ['@MetaMask/delegation'], diff --git a/packages/wallet-cli/CHANGELOG.md b/packages/wallet-cli/CHANGELOG.md index 9e83315b448..3ec8f37b592 100644 --- a/packages/wallet-cli/CHANGELOG.md +++ b/packages/wallet-cli/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Wire the `transactionController` slot in the daemon wallet's instance options, so the daemon runs the `TransactionController` with an explicit CLI-appropriate configuration (swaps processing disabled, no client hooks) rather than relying on the controller's implicit defaults ([#9509](https://github.com/MetaMask/core/pull/9509)) +- Wire the `gasFeeController` slot in the daemon wallet's instance options, passing `clientId: 'cli'` so the CLI identifies itself to the gas estimation API, now that `@metamask/wallet` requires this option ([#9527](https://github.com/MetaMask/core/pull/9527)) - Add the `mm wallet unlock` command, which dispatches `KeyringController:submitPassword` over the daemon socket, allowing the keyring to be unlocked after a daemon start with no password or after a `mm daemon call KeyringController:setLocked` ([#8821](https://github.com/MetaMask/core/pull/8821)) - Add the `mm daemon list` command, which prints the messenger actions the running daemon can dispatch via `daemon call`, enumerated from the live messenger so the list cannot drift from what `call` accepts ([#9339](https://github.com/MetaMask/core/pull/9339)) - Add the `mm daemon` command suite (`start`, `stop`, `status`, `purge`, and `call`) for running the wallet daemon and dispatching messenger actions over its socket ([#9255](https://github.com/MetaMask/core/pull/9255)) diff --git a/packages/wallet-cli/src/daemon/wallet-factory.test.ts b/packages/wallet-cli/src/daemon/wallet-factory.test.ts index de29cebdd7c..d50a2b4fd78 100644 --- a/packages/wallet-cli/src/daemon/wallet-factory.test.ts +++ b/packages/wallet-cli/src/daemon/wallet-factory.test.ts @@ -103,6 +103,7 @@ describe('createWallet', () => { expect( instanceOptions.connectivityController.connectivityAdapter, ).toBeInstanceOf(AlwaysOnlineAdapter); + expect(instanceOptions.gasFeeController.clientId).toBe('cli'); expect(instanceOptions.networkController.infuraProjectId).toBe( 'test-infura-id', ); diff --git a/packages/wallet-cli/src/daemon/wallet-factory.ts b/packages/wallet-cli/src/daemon/wallet-factory.ts index f281c74f230..832c16a155a 100644 --- a/packages/wallet-cli/src/daemon/wallet-factory.ts +++ b/packages/wallet-cli/src/daemon/wallet-factory.ts @@ -83,6 +83,11 @@ function buildInstanceOptions( connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + // Identifies the CLI to the gas estimation API via the `X-Client-Id` + // header. + clientId: 'cli', + }, networkController: { infuraProjectId, }, diff --git a/packages/wallet/CHANGELOG.md b/packages/wallet/CHANGELOG.md index b39b7418e51..1872924c4a0 100644 --- a/packages/wallet/CHANGELOG.md +++ b/packages/wallet/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- **BREAKING:** Wire `GasFeeController` into the default wallet initialization ([#9527](https://github.com/MetaMask/core/pull/9527)) + - Adds a required `instanceOptions.gasFeeController` option whose `clientId` (sent as `X-Client-Id` to the gas API) is required, so every client identifies itself; all other fields are optional and fall back to platform-agnostic defaults. - **BREAKING** Wire `SeedlessOnboardingController` and `PasskeyController` into the default wallet initialization ([#9533](https://github.com/MetaMask/core/pull/9533)) ### Changed diff --git a/packages/wallet/package.json b/packages/wallet/package.json index b56f1b253f5..838d1a9a3f2 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -62,6 +62,7 @@ "@metamask/browser-passworder": "^6.0.0", "@metamask/connectivity-controller": "^0.3.0", "@metamask/controller-utils": "^12.3.0", + "@metamask/gas-fee-controller": "^26.2.4", "@metamask/keyring-controller": "^27.1.0", "@metamask/messenger": "^2.0.0", "@metamask/network-controller": "^34.0.0", diff --git a/packages/wallet/src/Wallet.test.ts b/packages/wallet/src/Wallet.test.ts index 75dac034e92..e370c699aa0 100644 --- a/packages/wallet/src/Wallet.test.ts +++ b/packages/wallet/src/Wallet.test.ts @@ -29,6 +29,9 @@ async function setupWallet(): Promise { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, @@ -89,6 +92,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, keyringController: { encryptor: new MockEncryptor(), }, @@ -141,6 +147,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, @@ -184,6 +193,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, @@ -294,6 +306,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, @@ -326,6 +341,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, @@ -366,6 +384,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, @@ -454,6 +475,9 @@ describe('Wallet', () => { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'fake-infura-project-id', }, diff --git a/packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.test.ts b/packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.test.ts new file mode 100644 index 00000000000..5f2a91e3904 --- /dev/null +++ b/packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.test.ts @@ -0,0 +1,239 @@ +import { GasFeeController } from '@metamask/gas-fee-controller'; +import { Messenger } from '@metamask/messenger'; +import { InMemoryStorageAdapter } from '@metamask/storage-service'; + +import type { WalletOptions } from '../../../types.js'; +import { Wallet } from '../../../Wallet.js'; +import { defaultConfigurations } from '../../defaults.js'; +import type { + DefaultActions, + DefaultEvents, + RootMessenger, +} from '../../defaults.js'; +import { AlwaysOnlineAdapter } from '../connectivity-controller/always-online-adapter.js'; +import { gasFeeController } from './gas-fee-controller.js'; + +const controllers: GasFeeController[] = []; +const wallets: Wallet[] = []; + +const REMOTE_FEATURE_FLAG_OPTIONS = { + clientConfigApiService: { + fetchRemoteFeatureFlags: async (): Promise<{ + remoteFeatureFlags: Record; + cacheTimestamp: number; + }> => ({ remoteFeatureFlags: {}, cacheTimestamp: Date.now() }), + }, +}; + +type ActionHandler = (...args: unknown[]) => unknown; + +type AnyMessenger = Messenger; + +describe('gasFeeController', () => { + afterEach(async () => { + for (const controller of controllers.splice(0)) { + controller.destroy(); + } + + await Promise.all(wallets.splice(0).map((wallet) => wallet.destroy())); + }); + + it('is registered as a default initialization configuration', () => { + expect(Object.values(defaultConfigurations)).toContain(gasFeeController); + }); + + it('initializes a GasFeeController with default state', () => { + const rootMessenger = getRootMessenger(); + const messenger = gasFeeController.getMessenger(rootMessenger); + + const instance = gasFeeController.init({ + state: undefined, + messenger, + options: { clientId: 'test' }, + }); + controllers.push(instance); + + expect(instance).toBeInstanceOf(GasFeeController); + expect(rootMessenger.call('GasFeeController:getState')).toStrictEqual({ + gasFeeEstimatesByChainId: {}, + gasFeeEstimates: {}, + estimatedGasFeeTimeBounds: {}, + gasEstimateType: 'none', + nonRPCGasFeeApisDisabled: false, + }); + }); + + it('is initialized by the default Wallet configuration', () => { + const wallet = new Wallet({ + instanceOptions: getInstanceOptions(), + }); + wallets.push(wallet); + + expect(wallet.getInstance('GasFeeController')).toBeInstanceOf( + GasFeeController, + ); + }); + + it('exposes GasFeeController:fetchGasFeeEstimates over the shared bus, resolving the TransactionController delegation', async () => { + // The messenger binds the method at construction, so spy on the prototype + // before building the wallet. This also avoids the real network fetch. + const fetchGasFeeEstimates = jest + .spyOn(GasFeeController.prototype, 'fetchGasFeeEstimates') + .mockResolvedValue({ + gasFeeEstimatesByChainId: {}, + gasFeeEstimates: {}, + estimatedGasFeeTimeBounds: {}, + gasEstimateType: 'none', + nonRPCGasFeeApisDisabled: false, + }); + + const wallet = new Wallet({ + instanceOptions: getInstanceOptions(), + }); + wallets.push(wallet); + + await wallet.messenger.call('GasFeeController:fetchGasFeeEstimates'); + + expect(fetchGasFeeEstimates).toHaveBeenCalled(); + }); + + it('forwards the provided state to the controller', () => { + const rootMessenger = getRootMessenger(); + const messenger = gasFeeController.getMessenger(rootMessenger); + + const instance = gasFeeController.init({ + state: { + gasFeeEstimatesByChainId: {}, + gasFeeEstimates: {}, + estimatedGasFeeTimeBounds: {}, + gasEstimateType: 'none', + nonRPCGasFeeApisDisabled: true, + }, + messenger, + options: { clientId: 'test' }, + }); + controllers.push(instance); + + expect(instance.state.nonRPCGasFeeApisDisabled).toBe(true); + }); + + it('builds the network callbacks from the wired NetworkController', async () => { + const rootMessenger = getRootMessenger(); + const messenger = gasFeeController.getMessenger(rootMessenger); + + const instance = gasFeeController.init({ + state: undefined, + messenger, + options: { clientId: 'test' }, + }); + controllers.push(instance); + + // Drives `getProvider` and the EIP-1559/legacy/account callbacks; the + // estimate then fails at the offline provider, which is irrelevant here. + await expect(instance.fetchGasFeeEstimates()).rejects.toThrow( + 'Gas fee/price estimation failed', + ); + }); + + it('applies injectable options over the defaults', () => { + const rootMessenger = getRootMessenger(); + const messenger = gasFeeController.getMessenger(rootMessenger); + const getCurrentAccountEIP1559Compatibility = jest + .fn() + .mockReturnValue(false); + const getCurrentNetworkLegacyGasAPICompatibility = jest + .fn() + .mockReturnValue(true); + + const instance = gasFeeController.init({ + state: undefined, + messenger, + options: { + EIP1559APIEndpoint: 'https://example.test//eip1559', + legacyAPIEndpoint: 'https://example.test//legacy', + clientId: 'test-client', + interval: 30_000, + getCurrentAccountEIP1559Compatibility, + getCurrentNetworkLegacyGasAPICompatibility, + }, + }); + controllers.push(instance); + + expect(instance).toBeInstanceOf(GasFeeController); + }); +}); + +function getRootMessenger(): RootMessenger { + const rootMessenger = new Messenger<'Root', DefaultActions, DefaultEvents>({ + namespace: 'Root', + }); + + registerActionHandler( + rootMessenger, + 'NetworkController', + 'NetworkController:getState', + jest.fn().mockReturnValue({ selectedNetworkClientId: 'mainnet' }), + ); + + registerActionHandler( + rootMessenger, + 'NetworkController', + 'NetworkController:getNetworkClientById', + jest.fn().mockReturnValue({ + // Errors immediately so `eth_gasPrice` fallback settles without a network + // call rather than hanging. + provider: { + sendAsync: (_request: unknown, callback: (error: Error) => void) => + callback(new Error('offline')), + }, + configuration: { chainId: '0x1' }, + }), + ); + + registerActionHandler( + rootMessenger, + 'NetworkController', + 'NetworkController:getEIP1559Compatibility', + // `false` skips the EIP-1559/legacy API fetches, so a fetch goes straight to + // the offline provider above. + jest.fn().mockResolvedValue(false), + ); + + return rootMessenger; +} + +function getInstanceOptions(): WalletOptions['instanceOptions'] { + return { + connectivityController: { + connectivityAdapter: new AlwaysOnlineAdapter(), + }, + gasFeeController: { + clientId: 'test', + }, + networkController: { + infuraProjectId: 'test-infura-project-id', + }, + storageService: { + storage: new InMemoryStorageAdapter(), + }, + remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + }; +} + +function registerActionHandler( + parent: RootMessenger, + namespace: string, + actionType: string, + handler: ActionHandler, +): void { + const messenger = new Messenger({ + namespace, + parent: parent as unknown as AnyMessenger, + }); + + ( + messenger as unknown as { + registerActionHandler(type: string, handler: ActionHandler): void; + } + ).registerActionHandler(actionType, handler); +} diff --git a/packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.ts b/packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.ts new file mode 100644 index 00000000000..fc2f1b2effe --- /dev/null +++ b/packages/wallet/src/initialization/instances/gas-fee-controller/gas-fee-controller.ts @@ -0,0 +1,77 @@ +import type { GasFeeMessenger } from '@metamask/gas-fee-controller'; +import { GasFeeController } from '@metamask/gas-fee-controller'; +import { Messenger } from '@metamask/messenger'; +import type { ProviderProxy } from '@metamask/network-controller'; + +import type { InitializationConfiguration } from '../../types.js'; + +export type { GasFeeControllerInstanceOptions } from './types.js'; + +const GAS_API_BASE_URL = 'https://gas.api.cx.metamask.io'; + +// The controller substitutes `` with the decimal chain ID per request. +const DEFAULT_EIP1559_API_ENDPOINT = `${GAS_API_BASE_URL}/networks//suggestedGasFees`; +const DEFAULT_LEGACY_API_ENDPOINT = `${GAS_API_BASE_URL}/networks//gasPrices`; + +export const gasFeeController: InitializationConfiguration< + GasFeeController, + GasFeeMessenger +> = { + name: 'GasFeeController', + init: ({ state, messenger, options }) => { + const { + clientId, + EIP1559APIEndpoint = DEFAULT_EIP1559_API_ENDPOINT, + legacyAPIEndpoint = DEFAULT_LEGACY_API_ENDPOINT, + interval, + getCurrentNetworkLegacyGasAPICompatibility = (): boolean => false, + getCurrentAccountEIP1559Compatibility = (): boolean => true, + } = options; + + return new GasFeeController({ + messenger, + state, + interval, + EIP1559APIEndpoint, + legacyAPIEndpoint, + clientId, + getCurrentNetworkLegacyGasAPICompatibility, + getCurrentAccountEIP1559Compatibility, + // Built from `NetworkController`, which the controller expects as direct + // callbacks rather than messenger actions. + getProvider: (): ProviderProxy => { + const { selectedNetworkClientId } = messenger.call( + 'NetworkController:getState', + ); + // The client's provider proxy lacks `setTarget`, which `ProviderProxy` + // nominally requires but `GasFeeController` never calls. + return messenger.call( + 'NetworkController:getNetworkClientById', + selectedNetworkClientId, + ).provider as ProviderProxy; + }, + getCurrentNetworkEIP1559Compatibility: async () => + Boolean( + await messenger.call('NetworkController:getEIP1559Compatibility'), + ), + }); + }, + getMessenger: (parent) => { + const messenger: GasFeeMessenger = new Messenger({ + namespace: 'GasFeeController', + parent, + }); + + parent.delegate({ + messenger, + actions: [ + 'NetworkController:getEIP1559Compatibility', + 'NetworkController:getNetworkClientById', + 'NetworkController:getState', + ], + events: ['NetworkController:networkDidChange'], + }); + + return messenger; + }, +}; diff --git a/packages/wallet/src/initialization/instances/gas-fee-controller/types.ts b/packages/wallet/src/initialization/instances/gas-fee-controller/types.ts new file mode 100644 index 00000000000..d63fdc20ecc --- /dev/null +++ b/packages/wallet/src/initialization/instances/gas-fee-controller/types.ts @@ -0,0 +1,30 @@ +import type { GasFeeController } from '@metamask/gas-fee-controller'; + +type GasFeeControllerOptions = ConstructorParameters< + typeof GasFeeController +>[0]; + +/** + * Per-instance options for the wallet's `GasFeeController`. `clientId` is + * required so every client (extension, mobile, wallet-cli) identifies itself to + * the gas API; the remaining fields are optional and the instance's `init` + * applies a platform-agnostic default for each one, which clients may override. + */ +export type GasFeeControllerInstanceOptions = { + /** + * Sent as `X-Client-Id` to the gas API to identify the calling client. Has no + * platform-agnostic default, so each client must set it explicitly. + */ + clientId: NonNullable; + /** EIP-1559 gas price API URL. Defaults to the production endpoint. */ + // eslint-disable-next-line @typescript-eslint/naming-convention + EIP1559APIEndpoint?: GasFeeControllerOptions['EIP1559APIEndpoint']; + /** Legacy gas price API URL. Defaults to the production endpoint. */ + legacyAPIEndpoint?: GasFeeControllerOptions['legacyAPIEndpoint']; + /** Milliseconds between polls. Defaults to the controller's own 15 seconds. */ + interval?: GasFeeControllerOptions['interval']; + /** Defaults to `() => false`. */ + getCurrentNetworkLegacyGasAPICompatibility?: GasFeeControllerOptions['getCurrentNetworkLegacyGasAPICompatibility']; + /** Defaults to `() => true`. */ + getCurrentAccountEIP1559Compatibility?: GasFeeControllerOptions['getCurrentAccountEIP1559Compatibility']; +}; diff --git a/packages/wallet/src/initialization/instances/index.ts b/packages/wallet/src/initialization/instances/index.ts index 858e36e9769..d45bb0917b2 100644 --- a/packages/wallet/src/initialization/instances/index.ts +++ b/packages/wallet/src/initialization/instances/index.ts @@ -2,6 +2,7 @@ export { accountsController } from './accounts-controller/accounts-controller.js export { addressBookController } from './address-book-controller/address-book-controller.js'; export { approvalController } from './approval-controller/approval-controller.js'; export { connectivityController } from './connectivity-controller/connectivity-controller.js'; +export { gasFeeController } from './gas-fee-controller/gas-fee-controller.js'; export { keyringController } from './keyring-controller/keyring-controller.js'; export { networkController } from './network-controller/network-controller.js'; export { passkeyController } from './passkey-controller/passkey-controller.js'; diff --git a/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts b/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts index 4870eca7c18..a3831f1b973 100644 --- a/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts +++ b/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts @@ -115,6 +115,9 @@ function getInstanceOptions(): WalletOptions['instanceOptions'] { connectivityController: { connectivityAdapter: new AlwaysOnlineAdapter(), }, + gasFeeController: { + clientId: 'test', + }, networkController: { infuraProjectId: 'test-infura-project-id', }, diff --git a/packages/wallet/src/types.ts b/packages/wallet/src/types.ts index 46bb9c5993c..978bf1b1afd 100644 --- a/packages/wallet/src/types.ts +++ b/packages/wallet/src/types.ts @@ -7,6 +7,7 @@ import type { } from './initialization/defaults.js'; import type { ApprovalControllerInstanceOptions } from './initialization/instances/approval-controller/types.js'; import type { ConnectivityControllerInstanceOptions } from './initialization/instances/connectivity-controller/types.js'; +import type { GasFeeControllerInstanceOptions } from './initialization/instances/gas-fee-controller/types.js'; import type { KeyringControllerInstanceOptions } from './initialization/instances/keyring-controller/types.js'; import type { NetworkControllerInstanceOptions } from './initialization/instances/network-controller/types.js'; import type { PasskeyControllerInstanceOptions } from './initialization/instances/passkey-controller/types.js'; @@ -29,6 +30,7 @@ export type WalletOptions = { export type InstanceSpecificOptions = { approvalController?: ApprovalControllerInstanceOptions; connectivityController: ConnectivityControllerInstanceOptions; + gasFeeController: GasFeeControllerInstanceOptions; keyringController?: KeyringControllerInstanceOptions; networkController: NetworkControllerInstanceOptions; remoteFeatureFlagController: RemoteFeatureFlagControllerInstanceOptions; diff --git a/packages/wallet/tsconfig.build.json b/packages/wallet/tsconfig.build.json index d4caa50ec1c..dae6d88285a 100644 --- a/packages/wallet/tsconfig.build.json +++ b/packages/wallet/tsconfig.build.json @@ -12,6 +12,7 @@ { "path": "../base-controller/tsconfig.build.json" }, { "path": "../connectivity-controller/tsconfig.build.json" }, { "path": "../controller-utils/tsconfig.build.json" }, + { "path": "../gas-fee-controller/tsconfig.build.json" }, { "path": "../keyring-controller/tsconfig.build.json" }, { "path": "../messenger/tsconfig.build.json" }, { "path": "../network-controller/tsconfig.build.json" }, diff --git a/packages/wallet/tsconfig.json b/packages/wallet/tsconfig.json index 62f5137fc5b..10221177468 100644 --- a/packages/wallet/tsconfig.json +++ b/packages/wallet/tsconfig.json @@ -22,6 +22,9 @@ { "path": "../controller-utils" }, + { + "path": "../gas-fee-controller" + }, { "path": "../keyring-controller" }, diff --git a/yarn.lock b/yarn.lock index 8fc98d15567..111a7b3a711 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9170,6 +9170,7 @@ __metadata: "@metamask/browser-passworder": "npm:^6.0.0" "@metamask/connectivity-controller": "npm:^0.3.0" "@metamask/controller-utils": "npm:^12.3.0" + "@metamask/gas-fee-controller": "npm:^26.2.4" "@metamask/keyring-controller": "npm:^27.1.0" "@metamask/messenger": "npm:^2.0.0" "@metamask/network-controller": "npm:^34.0.0"