Skip to content

Commit

Permalink
chore: remove @metamask/eth-query package (#29649)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This PR removes `@metamask/eth-query` package by using directly the
provider without using any wrapper package.

The purpose of this PR is to simplify and break down the process of
replacing web3-stream-provider
([issue](#28774)),
which uses the legacy sendAsync method and is not EIP-1193 compliant,
with StreamProvider from @metamask/providers, which fully adheres to the
EIP-1193 Specs.

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

[![Open in GitHub
Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/29620?quickstart=1)

## **Related issues**

Fixes: partially completes
#28774

## **Manual testing steps**

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask
Extension Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

---------

Co-authored-by: MetaMask Bot <[email protected]>
  • Loading branch information
cryptodev-2s and metamaskbot authored Jan 15, 2025
1 parent 0bcd385 commit 3944d7e
Show file tree
Hide file tree
Showing 23 changed files with 161 additions and 232 deletions.
27 changes: 0 additions & 27 deletions .yarn/patches/eth-query-npm-2.1.2-7c6adc825f.patch

This file was deleted.

26 changes: 15 additions & 11 deletions app/scripts/controllers/account-tracker-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
* on each new block.
*/

import EthQuery from '@metamask/eth-query';
import { v4 as random } from 'uuid';

import log from 'loglevel';
import pify from 'pify';
import { Web3Provider } from '@ethersproject/providers';
import { Contract } from '@ethersproject/contracts';
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi';
Expand All @@ -24,7 +22,7 @@ import {
NetworkControllerGetStateAction,
Provider,
} from '@metamask/network-controller';
import { hasProperty, Hex } from '@metamask/utils';
import { hasProperty, type Hex, type JsonRpcParams } from '@metamask/utils';
import {
BaseController,
ControllerGetStateAction,
Expand Down Expand Up @@ -481,7 +479,7 @@ export default class AccountTrackerController extends BaseController<
* AccountTrackerController.
*
* Once this AccountTrackerController accounts are up to date with those referenced by the passed addresses, each
* of these accounts are given an updated balance via EthQuery.
* of these accounts are given an updated balance via Provider.
*
* @param addresses - The array of hex addresses for accounts with which this AccountTrackerController accounts should be
* in sync
Expand Down Expand Up @@ -588,7 +586,7 @@ export default class AccountTrackerController extends BaseController<

/**
* Given a block, updates this AccountTrackerController currentBlockGasLimit and currentBlockGasLimitByChainId and then updates
* each local account's balance via EthQuery
* each local account's balance via Provider
*
* @private
* @param blockNumber - the block number to update to.
Expand All @@ -600,7 +598,7 @@ export default class AccountTrackerController extends BaseController<

/**
* Given a block, updates this AccountTrackerController currentBlockGasLimitByChainId, and then updates each local account's balance
* via EthQuery
* via Provider
*
* @private
* @param networkClientId - optional network client ID to use instead of the globally selected network.
Expand All @@ -616,10 +614,13 @@ export default class AccountTrackerController extends BaseController<
this.#currentBlockNumberByChainId[chainId] = blockNumber;

// block gasLimit polling shouldn't be in account-tracker shouldn't be here...
const currentBlock = await pify(new EthQuery(provider)).getBlockByNumber(
blockNumber,
false,
);
const currentBlock = await provider.request<
JsonRpcParams,
{ gasLimit: string }
>({
method: 'eth_getBlockByNumber',
params: [blockNumber, false],
});
if (!currentBlock) {
return;
}
Expand Down Expand Up @@ -729,7 +730,10 @@ export default class AccountTrackerController extends BaseController<

// query balance
try {
balance = await pify(new EthQuery(provider)).getBalance(address);
balance = await provider.request({
method: 'eth_getBalance',
params: [address, 'latest'],
});
} catch (error) {
if (
error &&
Expand Down
30 changes: 16 additions & 14 deletions app/scripts/lib/transaction/decode/proxy.test.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
import EthQuery from '@metamask/eth-query';
import type { Provider } from '@metamask/network-controller';
import { getContractProxyAddress } from './proxy';

const CONTRACT_ADDRESS_MOCK = '0x456';

function createEthQueryMock(storageValues: string[]): EthQuery {
const ethQuery = {
eth_getStorageAt: jest.fn(),
};
function createProviderMock(storageValues: string[]): Provider {
const ethGetStorageAt = jest.fn();

for (const storageValue of storageValues) {
ethQuery.eth_getStorageAt.mockImplementationOnce(
(_contractAddress, _storageSlot, _blockNumber, cb) =>
cb(null, storageValue),
);
ethGetStorageAt.mockImplementationOnce(() => storageValue);
}

return ethQuery as unknown as EthQuery;
return {
request: async (request) => {
if (request.method === 'eth_getStorageAt') {
return ethGetStorageAt(request);
}
throw new Error(`Unexpected method: ${request.method}`);
},
} as Provider;
}

describe('Proxy', () => {
describe('getContractProxyAddress', () => {
it('returns undefined if all responses empty', async () => {
const ethQuery = createEthQueryMock([
const provider = createProviderMock([
'0x0000000000000000000000000000000000000000000000000000000000000000',
'0x0000000000000000000000000000000000000000000000000000000000000000',
]);

expect(
await getContractProxyAddress(CONTRACT_ADDRESS_MOCK, ethQuery),
await getContractProxyAddress(CONTRACT_ADDRESS_MOCK, provider),
).toBeUndefined();
});

it('returns first non-empty response', async () => {
const ethQuery = createEthQueryMock([
const provider = createProviderMock([
'0x0000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000123',
]);

expect(
await getContractProxyAddress(CONTRACT_ADDRESS_MOCK, ethQuery),
await getContractProxyAddress(CONTRACT_ADDRESS_MOCK, provider),
).toBe('0x123');
});
});
Expand Down
19 changes: 8 additions & 11 deletions app/scripts/lib/transaction/decode/proxy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { query } from '@metamask/controller-utils';
import EthQuery from '@metamask/eth-query';
import { Hex } from '@metamask/utils';
import type { Provider } from '@metamask/network-controller';
import type { Hex, JsonRpcParams } from '@metamask/utils';
import { addHexPrefix, stripHexPrefix } from 'ethereumjs-util';

const IMPLEMENTATION_STORAGE_SLOTS = [
Expand All @@ -15,16 +14,14 @@ const EMPTY_RESULT = '0'.padEnd(64, '0');

export async function getContractProxyAddress(
contractAddress: Hex,
ethQuery: EthQuery,
provider: Provider,
): Promise<Hex | undefined> {
const responses = await Promise.all(
IMPLEMENTATION_STORAGE_SLOTS.map(
(storageSlot) =>
query(ethQuery, 'eth_getStorageAt', [
contractAddress,
storageSlot,
'latest',
]) as Promise<Hex>,
IMPLEMENTATION_STORAGE_SLOTS.map((storageSlot) =>
provider.request<JsonRpcParams, Hex>({
method: 'eth_getStorageAt',
params: [contractAddress, storageSlot, 'latest'],
}),
),
);

Expand Down
12 changes: 6 additions & 6 deletions app/scripts/lib/transaction/decode/util.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import EthQuery from '@metamask/eth-query';
import type { Provider } from '@metamask/network-controller';
import {
TRANSACTION_DATA_FOUR_BYTE,
TRANSACTION_DATA_SOURCIFY,
Expand All @@ -20,7 +20,7 @@ jest.mock('./proxy');

const CONTRACT_ADDRESS_MOCK = '0x456';
const CHAIN_ID_MOCK = '0x123';
const ETH_QUERY_MOCK = {} as EthQuery;
const PROVIDER_MOCK = {} as Provider;

describe('Transaction Decode Utils', () => {
const decodeUniswapRouterTransactionDataMock = jest.mocked(
Expand Down Expand Up @@ -56,7 +56,7 @@ describe('Transaction Decode Utils', () => {
transactionData: TRANSACTION_DATA_UNISWAP,
contractAddress: CONTRACT_ADDRESS_MOCK,
chainId: CHAIN_ID_MOCK,
ethQuery: ETH_QUERY_MOCK,
provider: PROVIDER_MOCK,
});

expect(result).toStrictEqual(TRANSACTION_DECODE_UNISWAP);
Expand All @@ -71,7 +71,7 @@ describe('Transaction Decode Utils', () => {
transactionData: TRANSACTION_DATA_SOURCIFY,
contractAddress: CONTRACT_ADDRESS_MOCK,
chainId: CHAIN_ID_MOCK,
ethQuery: ETH_QUERY_MOCK,
provider: PROVIDER_MOCK,
});

expect(result).toStrictEqual(TRANSACTION_DECODE_SOURCIFY);
Expand All @@ -86,7 +86,7 @@ describe('Transaction Decode Utils', () => {
transactionData: TRANSACTION_DATA_FOUR_BYTE,
contractAddress: CONTRACT_ADDRESS_MOCK,
chainId: CHAIN_ID_MOCK,
ethQuery: ETH_QUERY_MOCK,
provider: PROVIDER_MOCK,
});

expect(result).toStrictEqual(TRANSACTION_DECODE_FOUR_BYTE);
Expand All @@ -97,7 +97,7 @@ describe('Transaction Decode Utils', () => {
transactionData: TRANSACTION_DATA_FOUR_BYTE,
contractAddress: CONTRACT_ADDRESS_MOCK,
chainId: CHAIN_ID_MOCK,
ethQuery: ETH_QUERY_MOCK,
provider: PROVIDER_MOCK,
});

expect(result).toBeUndefined();
Expand Down
8 changes: 4 additions & 4 deletions app/scripts/lib/transaction/decode/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Hex, createProjectLogger } from '@metamask/utils';
import EthQuery from '@metamask/eth-query';
import type { Provider } from '@metamask/network-controller';
import {
DecodedTransactionDataMethod,
DecodedTransactionDataParam,
Expand All @@ -17,12 +17,12 @@ export async function decodeTransactionData({
transactionData,
contractAddress,
chainId,
ethQuery,
provider,
}: {
transactionData: Hex;
contractAddress: Hex;
chainId: Hex;
ethQuery: EthQuery;
provider: Provider;
}): Promise<DecodedTransactionDataResponse | undefined> {
log('Decoding transaction data', {
transactionData,
Expand All @@ -45,7 +45,7 @@ export async function decodeTransactionData({
};
}

const proxyAddress = await getContractProxyAddress(contractAddress, ethQuery);
const proxyAddress = await getContractProxyAddress(contractAddress, provider);

if (proxyAddress) {
log('Retrieved proxy implementation address', proxyAddress);
Expand Down
3 changes: 2 additions & 1 deletion app/scripts/lib/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
TransactionEnvelopeType,
TransactionMeta,
} from '@metamask/transaction-controller';
import type { Provider } from '@metamask/network-controller';
import {
ENVIRONMENT_TYPE_BACKGROUND,
ENVIRONMENT_TYPE_FULLSCREEN,
Expand Down Expand Up @@ -394,7 +395,7 @@ export const getMethodDataName = async (
use4ByteResolution: boolean,
prefixedData: string,
addKnownMethodData: (fourBytePrefix: string, methodData: MethodData) => void,
provider: object,
provider: Provider,
) => {
if (!prefixedData || !use4ByteResolution) {
return null;
Expand Down
59 changes: 28 additions & 31 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import {
import LatticeKeyring from 'eth-lattice-keyring';
import { rawChainData } from 'eth-chainlist';
import { MetaMaskKeyring as QRHardwareKeyring } from '@keystonehq/metamask-airgapped-keyring';
import EthQuery from '@metamask/eth-query';
import { nanoid } from 'nanoid';
import { captureException } from '@sentry/browser';
import { AddressBookController } from '@metamask/address-book-controller';
Expand Down Expand Up @@ -3397,17 +3396,16 @@ export default class MetamaskController extends EventEmitter {

let networkVersion = this.deprecatedNetworkVersions[networkClientId];
if (networkVersion === undefined && completedOnboarding) {
const ethQuery = new EthQuery(networkClient.provider);
networkVersion = await new Promise((resolve) => {
ethQuery.sendAsync({ method: 'net_version' }, (error, result) => {
if (error) {
console.error(error);
resolve(null);
} else {
resolve(convertNetworkId(result));
}
try {
const result = await networkClient.provider.request({
method: 'net_version',
});
});
networkVersion = convertNetworkId(result);
} catch (error) {
console.error(error);
networkVersion = null;
}

this.deprecatedNetworkVersions[networkClientId] = networkVersion;
}

Expand Down Expand Up @@ -4439,7 +4437,7 @@ export default class MetamaskController extends EventEmitter {
decodeTransactionData: (request) =>
decodeTransactionData({
...request,
ethQuery: new EthQuery(this.provider),
provider: this.provider,
}),
// metrics data deleteion
createMetaMetricsDataDeletionTask:
Expand Down Expand Up @@ -4659,12 +4657,11 @@ export default class MetamaskController extends EventEmitter {
try {
// Scan accounts until we find an empty one
const chainId = this.#getGlobalChainId();
const ethQuery = new EthQuery(this.provider);
const accounts = await this.keyringController.getAccounts();
let address = accounts[accounts.length - 1];

for (let count = accounts.length; ; count++) {
const balance = await this.getBalance(address, ethQuery);
const balance = await this.getBalance(address, this.provider);

if (balance === '0x0') {
// This account has no balance, so check for tokens
Expand Down Expand Up @@ -4734,25 +4731,25 @@ export default class MetamaskController extends EventEmitter {
* Get an account balance from the AccountTrackerController or request it directly from the network.
*
* @param {string} address - The account address
* @param {EthQuery} ethQuery - The EthQuery instance to use when asking the network
* @param {Provider} provider - The provider instance to use when asking the network
*/
getBalance(address, ethQuery) {
return new Promise((resolve, reject) => {
const cached = this.accountTrackerController.state.accounts[address];
async getBalance(address, provider) {
const cached = this.accountTrackerController.state.accounts[address];

if (cached && cached.balance) {
resolve(cached.balance);
} else {
ethQuery.getBalance(address, (error, balance) => {
if (error) {
reject(error);
log.error(error);
} else {
resolve(balance || '0x0');
}
});
}
});
if (cached && cached.balance) {
return cached.balance;
}

try {
const balance = await provider.request({
method: 'eth_getBalance',
params: [address, 'latest'],
});
return balance || '0x0';
} catch (error) {
log.error(error);
throw error;
}
}

/**
Expand Down
Loading

0 comments on commit 3944d7e

Please sign in to comment.