-
-
Notifications
You must be signed in to change notification settings - Fork 274
fix(wallet): Fix builds and most lint issues #8420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/wallet-library
Are you sure you want to change the base?
Changes from all commits
9d908c5
c4b0728
8626c7c
b36ee54
36691cc
e91bbe2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,4 +37,9 @@ scripts/coverage | |
| packages/*/*.tsbuildinfo | ||
|
|
||
| # AI | ||
| .sisyphus/ | ||
| .sisyphus/ | ||
|
|
||
| # Wallet | ||
| .claude/ | ||
| .env | ||
| !.env.example | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| INFURA_PROJECT_KEY= | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,9 @@ | ||
| import { | ||
| ClientConfigApiService, | ||
| ClientType, | ||
| DistributionType, | ||
| EnvironmentType, | ||
| } from '@metamask/remote-feature-flag-controller'; | ||
| import { enableNetConnect } from 'nock'; | ||
|
|
||
| import { importSecretRecoveryPhrase, sendTransaction } from './utilities'; | ||
|
|
@@ -7,12 +13,27 @@ const TEST_PHRASE = | |
| 'test test test test test test test test test test test ball'; | ||
| const TEST_PASSWORD = 'testpass'; | ||
|
|
||
| async function setupWallet() { | ||
| async function setupWallet(): Promise<Wallet> { | ||
| if (!process.env.INFURA_PROJECT_KEY) { | ||
| throw new Error( | ||
| 'INFURA_PROJECT_KEY is not set. Copy .env.example to .env and fill in your key.', | ||
| ); | ||
| } | ||
|
|
||
| const wallet = new Wallet({ | ||
| options: { | ||
| infuraProjectId: 'infura-project-id', | ||
| infuraProjectId: process.env.INFURA_PROJECT_KEY, | ||
| clientVersion: '1.0.0', | ||
| showApprovalRequest: () => undefined, | ||
| showApprovalRequest: (): undefined => undefined, | ||
| clientConfigApiService: new ClientConfigApiService({ | ||
| fetch: globalThis.fetch, | ||
| config: { | ||
| client: ClientType.Extension, | ||
| distribution: DistributionType.Main, | ||
| environment: EnvironmentType.Production, | ||
| }, | ||
| }), | ||
| getMetaMetricsId: (): string => 'fake-metrics-id', | ||
| }, | ||
| }); | ||
|
|
||
|
|
@@ -22,8 +43,21 @@ async function setupWallet() { | |
| } | ||
|
|
||
| describe('Wallet', () => { | ||
| let wallet: Wallet; | ||
|
|
||
| beforeEach(() => { | ||
| jest.useFakeTimers({ doNotFake: ['nextTick', 'queueMicrotask'] }); | ||
| }); | ||
|
|
||
| afterEach(async () => { | ||
| await wallet?.destroy(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Any concern with just doing
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As opposed to in |
||
| enableNetConnect(); | ||
| jest.useRealTimers(); | ||
| }); | ||
|
|
||
| it('can unlock and populate accounts', async () => { | ||
| const { messenger } = await setupWallet(); | ||
| wallet = await setupWallet(); | ||
| const { messenger } = wallet; | ||
|
|
||
| expect( | ||
| messenger | ||
|
|
@@ -35,7 +69,7 @@ describe('Wallet', () => { | |
| it('signs transactions', async () => { | ||
| enableNetConnect(); | ||
|
|
||
| const wallet = await setupWallet(); | ||
| wallet = await setupWallet(); | ||
|
|
||
| const addresses = wallet.messenger | ||
| .call('AccountsController:listAccounts') | ||
|
|
@@ -47,7 +81,8 @@ describe('Wallet', () => { | |
| { networkClientId: 'sepolia' }, | ||
| ); | ||
|
|
||
| const hash = await result; | ||
| // Advance timers by an arbitrary value to trigger downstream timer logic. | ||
| const hash = await jest.advanceTimersByTimeAsync(60_000).then(() => result); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused as to why this is needed. Why specifically 60 seconds?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's something in the call chain that relies on timers and if we don't advance the timers the test hangs. The amount of time is arbitrary. Added a comment: e91bbe2 |
||
|
|
||
| expect(hash).toStrictEqual(expect.any(String)); | ||
| expect(transactionMeta).toStrictEqual( | ||
|
|
@@ -61,10 +96,11 @@ describe('Wallet', () => { | |
| }), | ||
| }), | ||
| ); | ||
| }); | ||
| }, 10_000); | ||
|
|
||
| it('exposes state', async () => { | ||
| const { state } = await setupWallet(); | ||
| wallet = await setupWallet(); | ||
| const { state } = wallet; | ||
|
|
||
| expect(state.KeyringController).toStrictEqual({ | ||
| isUnlocked: true, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ export function initialize({ | |
| messenger, | ||
| initializationConfigurations = [], | ||
| options, | ||
| }: InitializeArgs) { | ||
| }: InitializeArgs): Record<string, Record<string, unknown>> { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess fine for now, but we should come up with a way to type this to at least include the instances from |
||
| const overriddenConfiguration = initializationConfigurations.map( | ||
| (config) => config.name, | ||
| ); | ||
|
|
@@ -30,7 +30,7 @@ export function initialize({ | |
| ), | ||
| ); | ||
|
|
||
| const instances = {}; | ||
| const instances: Record<string, Record<string, unknown>> = {}; | ||
|
|
||
| for (const config of configurationEntries) { | ||
| const { name } = config; | ||
|
|
@@ -45,7 +45,7 @@ export function initialize({ | |
| options, | ||
| }); | ||
|
|
||
| instances[name] = instance; | ||
| instances[name] = instance as Record<string, unknown>; | ||
| } | ||
|
|
||
| return instances; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { | |
| MessengerActions, | ||
| MessengerEvents, | ||
| } from '@metamask/messenger'; | ||
| import type { NetworkControllerOptions } from '@metamask/network-controller'; | ||
| import { | ||
| NetworkController, | ||
| NetworkControllerMessenger, | ||
|
|
@@ -24,36 +25,38 @@ export const networkController: InitializationConfiguration< | |
| name: 'NetworkController', | ||
| init: ({ state, messenger, options }) => { | ||
| // TODO: This was gutted to simplify implementation for now. | ||
| const getRpcServiceOptions = () => { | ||
| const maxRetries = DEFAULT_MAX_RETRIES; | ||
| const getRpcServiceOptions: NetworkControllerOptions['getRpcServiceOptions'] = | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this a lint fix? 🤔
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, for explicit function return type. |
||
| () => { | ||
| const maxRetries = DEFAULT_MAX_RETRIES; | ||
|
|
||
| const isOffline = (): boolean => { | ||
| const connectivityState = messenger.call( | ||
| 'ConnectivityController:getState', | ||
| ); | ||
| return ( | ||
| connectivityState.connectivityStatus === CONNECTIVITY_STATUSES.Offline | ||
| ); | ||
| }; | ||
| const isOffline = (): boolean => { | ||
| const connectivityState = messenger.call( | ||
| 'ConnectivityController:getState', | ||
| ); | ||
| return ( | ||
| connectivityState.connectivityStatus === | ||
| CONNECTIVITY_STATUSES.Offline | ||
| ); | ||
| }; | ||
|
|
||
| return { | ||
| fetch: globalThis.fetch.bind(globalThis), | ||
| btoa: globalThis.btoa.bind(globalThis), | ||
| isOffline, | ||
| policyOptions: { | ||
| // Ensure that the "cooldown" period after breaking the circuit is short. | ||
| circuitBreakDuration: inMilliseconds(30, Duration.Second), | ||
| maxRetries, | ||
| // Ensure that if the endpoint continually responds with errors, we | ||
| // break the circuit relatively fast (but not prematurely). | ||
| // | ||
| // Note that the circuit will break much faster if the errors are | ||
| // retriable (e.g. 503) than if not (e.g. 500), so we attempt to strike | ||
| // a balance here. | ||
| maxConsecutiveFailures: (maxRetries + 1) * 3, | ||
| }, | ||
| return { | ||
| fetch: globalThis.fetch.bind(globalThis), | ||
| btoa: globalThis.btoa.bind(globalThis), | ||
| isOffline, | ||
| policyOptions: { | ||
| // Ensure that the "cooldown" period after breaking the circuit is short. | ||
| circuitBreakDuration: inMilliseconds(30, Duration.Second), | ||
| maxRetries, | ||
| // Ensure that if the endpoint continually responds with errors, we | ||
| // break the circuit relatively fast (but not prematurely). | ||
| // | ||
| // Note that the circuit will break much faster if the errors are | ||
| // retriable (e.g. 503) than if not (e.g. 500), so we attempt to strike | ||
| // a balance here. | ||
| maxConsecutiveFailures: (maxRetries + 1) * 3, | ||
| }, | ||
| }; | ||
| }; | ||
| }; | ||
|
|
||
| // TODO: Add the rest of the arguments. | ||
| const instance = new NetworkController({ | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we need to pass this entire thing in? Maybe just add
client,distribution,environmenttoWalletOptionsand we can constructClientConfigApiServicebased on that?