Skip to content

Commit 5db56bf

Browse files
feat!: Add method for getting genesis block (#3788)
Add method for getting genesis block to Ethereum provider example Snap. This is useful for properly testing what chain we are connected to in E2E. Also removes some unused methods. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Add `getGenesisBlock` RPC to the example Snap (with `getBlock` helper), remove `getGasPrice`/`getVersion`, and update tests and UI to support it. > > - **Ethereum Provider Snap**: > - Add `getGenesisBlock` RPC; implement `getBlock(number)` using `eth_getBlockByNumber` and wire into `onRpcRequest`. > - Remove unused RPCs `getGasPrice` and `getVersion`; retain `getChainId` and existing signing/account methods. > - **Tests**: > - Add genesis block test mocking `eth_getBlockByNumber`; remove gas price/version tests. > - **Test App UI**: > - Add "Get Genesis Block" button and handler in `packages/test-snaps/src/features/snaps/ethereum-provider/EthereumProvider.tsx`. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit f1b0591. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent db7a1ca commit 5db56bf

File tree

4 files changed

+69
-59
lines changed

4 files changed

+69
-59
lines changed

packages/examples/packages/ethereum-provider/snap.manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snaps.git"
88
},
99
"source": {
10-
"shasum": "/yD9JVMe1ppdLCocldK6/6D9Cx0j1+iZQy5Z5INLlEU=",
10+
"shasum": "HQcHCmjI/cTIiFTeAr/PywSGgXUWYUi/otWoHST40h4=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",

packages/examples/packages/ethereum-provider/src/index.test.ts

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,53 @@ describe('onRpcRequest', () => {
2020
});
2121
});
2222

23-
describe('getGasPrice', () => {
24-
const MOCK_GAS_PRICE = '0x387c64b64';
25-
26-
it('returns the current gas price', async () => {
23+
describe('getGenesisBlock', () => {
24+
// Ethereum Mainnet
25+
const GENESIS_BLOCK = {
26+
difficulty: '0x400000000',
27+
extraData:
28+
'0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa',
29+
gasLimit: '0x1388',
30+
gasUsed: '0x0',
31+
hash: '0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3',
32+
logsBloom:
33+
'0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
34+
miner: '0x0000000000000000000000000000000000000000',
35+
mixHash:
36+
'0x0000000000000000000000000000000000000000000000000000000000000000',
37+
nonce: '0x0000000000000042',
38+
number: '0x0',
39+
parentHash:
40+
'0x0000000000000000000000000000000000000000000000000000000000000000',
41+
receiptsRoot:
42+
'0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
43+
sha3Uncles:
44+
'0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347',
45+
size: '0x21c',
46+
stateRoot:
47+
'0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544',
48+
timestamp: '0x0',
49+
transactions: [],
50+
transactionsRoot:
51+
'0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421',
52+
uncles: [],
53+
};
54+
55+
it('returns the genesis block', async () => {
2756
const { request, mockJsonRpc } = await installSnap();
2857

2958
// To avoid relying on the network, we mock the response from the Ethereum
3059
// provider.
3160
mockJsonRpc({
32-
method: 'eth_gasPrice',
33-
result: MOCK_GAS_PRICE,
34-
});
35-
36-
const response = await request({
37-
method: 'getGasPrice',
61+
method: 'eth_getBlockByNumber',
62+
result: GENESIS_BLOCK,
3863
});
3964

40-
expect(response).toRespondWith(MOCK_GAS_PRICE);
41-
});
42-
});
43-
44-
describe('getVersion', () => {
45-
const MOCK_VERSION = '1'; // Ethereum Mainnet
46-
47-
it('returns the current network version', async () => {
48-
const { request } = await installSnap();
49-
5065
const response = await request({
51-
method: 'getVersion',
66+
method: 'getGenesisBlock',
5267
});
5368

54-
expect(response).toRespondWith(MOCK_VERSION);
69+
expect(response).toRespondWith(GENESIS_BLOCK);
5570
});
5671
});
5772

packages/examples/packages/ethereum-provider/src/index.ts

Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
stringToBytes,
99
bytesToHex,
1010
hexToNumber,
11+
numberToHex,
1112
} from '@metamask/utils';
1213

1314
import type {
@@ -29,60 +30,47 @@ async function switchChain(chainId: Hex) {
2930
}
3031

3132
/**
32-
* Get the current gas price using the `ethereum` global. This is essentially
33+
* Get the current chain ID using the `ethereum` global. This is essentially
3334
* the same as the `window.ethereum` global, but does not have access to all
3435
* methods.
3536
*
3637
* Note that using the `ethereum` global requires the
3738
* `endowment:ethereum-provider` permission.
3839
*
39-
* @returns The current gas price as a hexadecimal string.
40+
* @returns The current chain ID as a string.
4041
* @see https://docs.metamask.io/snaps/reference/permissions/#endowmentethereum-provider
4142
*/
42-
async function getGasPrice() {
43-
const gasPrice = await ethereum.request<Hex>({ method: 'eth_gasPrice' });
44-
assert(gasPrice, 'Ethereum provider did not return a gas price.');
45-
46-
return gasPrice;
47-
}
43+
async function getChainId() {
44+
const chainId = await ethereum.request<string>({
45+
method: 'eth_chainId',
46+
});
4847

49-
/**
50-
* Get the current network version using the `ethereum` global. This is
51-
* essentially the same as the `window.ethereum` global, but does not have
52-
* access to all methods.
53-
*
54-
* Note that using the `ethereum` global requires the
55-
* `endowment:ethereum-provider` permission.
56-
*
57-
* @returns The current network version as a string.
58-
* @see https://docs.metamask.io/snaps/reference/permissions/#endowmentethereum-provider
59-
*/
60-
async function getVersion() {
61-
const version = await ethereum.request<string>({ method: 'net_version' });
62-
assert(version, 'Ethereum provider did not return a version.');
48+
assert(chainId, 'Ethereum provider did not return a chain ID.');
6349

64-
return version;
50+
return chainId;
6551
}
6652

6753
/**
68-
* Get the current chain ID using the `ethereum` global. This is essentially
54+
* Get a block by number using the `ethereum` global. This is essentially
6955
* the same as the `window.ethereum` global, but does not have access to all
7056
* methods.
7157
*
7258
* Note that using the `ethereum` global requires the
7359
* `endowment:ethereum-provider` permission.
7460
*
75-
* @returns The current chain ID as a string.
61+
* @param blockNumber - The block number.
62+
* @returns Information about the requested block.
7663
* @see https://docs.metamask.io/snaps/reference/permissions/#endowmentethereum-provider
7764
*/
78-
async function getChainId() {
79-
const chainId = await ethereum.request<string>({
80-
method: 'eth_chainId',
65+
async function getBlock(blockNumber: number) {
66+
const block = await ethereum.request<string>({
67+
method: 'eth_getBlockByNumber',
68+
params: [numberToHex(blockNumber), false],
8169
});
8270

83-
assert(chainId, 'Ethereum provider did not return a chain ID.');
71+
assert(block, 'Ethereum provider did not return a block.');
8472

85-
return chainId;
73+
return block;
8674
}
8775

8876
/**
@@ -249,18 +237,15 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
249237
await switchChain(chainId);
250238

251239
switch (request.method) {
252-
case 'getGasPrice':
253-
return await getGasPrice();
254-
255-
case 'getVersion':
256-
return await getVersion();
257-
258240
case 'getChainId':
259241
return await getChainId();
260242

261243
case 'getAccounts':
262244
return await getAccounts();
263245

246+
case 'getGenesisBlock':
247+
return await getBlock(0);
248+
264249
case 'personalSign': {
265250
const params = request.params as PersonalSignParams;
266251
const accounts = await getAccounts();

packages/test-snaps/src/features/snaps/ethereum-provider/EthereumProvider.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const EthereumProvider: FunctionComponent = () => {
2929
};
3030

3131
const handleGetChainId = () => handleSubmit('getChainId');
32+
const handleGetGenesisBlock = () => handleSubmit('getGenesisBlock');
3233
const handleGetAccounts = () => handleSubmit('getAccounts');
3334

3435
return (
@@ -50,6 +51,15 @@ export const EthereumProvider: FunctionComponent = () => {
5051
>
5152
Get Chain ID
5253
</Button>
54+
<Button
55+
variant="secondary"
56+
id="sendGenesisBlockEthProvider"
57+
className="mb-3"
58+
disabled={isLoading}
59+
onClick={handleGetGenesisBlock}
60+
>
61+
Get Genesis Block
62+
</Button>
5363
<Button
5464
variant="primary"
5565
id="sendEthproviderAccounts"

0 commit comments

Comments
 (0)