Skip to content
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

Prague support #6223

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion docs/src/content/hardhat-network/docs/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- merge
- shanghai
- cancun
- prague

## Config

Expand Down Expand Up @@ -66,7 +67,7 @@ The block gas limit to use in Hardhat Network's blockchain. Default value: `30_0

#### `hardfork`

This setting changes how Hardhat Network works, to mimic Ethereum's mainnet at a given hardfork. It must be one of `"byzantium"`, `"constantinople"`, `"petersburg"`, `"istanbul"`, `"muirGlacier"`, `"berlin"`, `"london"`, `"arrowGlacier"`, `"grayGlacier"`, `"merge"`, `"shanghai"` and `"cancun"`. Default value: `"cancun"`
This setting changes how Hardhat Network works, to mimic Ethereum's mainnet at a given hardfork. It must be one of `"byzantium"`, `"constantinople"`, `"petersburg"`, `"istanbul"`, `"muirGlacier"`, `"berlin"`, `"london"`, `"arrowGlacier"`, `"grayGlacier"`, `"merge"`, `"shanghai"`, `"cancun"` and `"prague"`. Default value: `"cancun"`

#### `throwOnTransactionFailures`

Expand Down
10 changes: 4 additions & 6 deletions packages/hardhat-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
"devDependencies": {
"@nomicfoundation/eslint-plugin-hardhat-internal-rules": "workspace:^",
"@nomicfoundation/eslint-plugin-slow-imports": "workspace:^",
"@nomicfoundation/ethereumjs-block": "5.0.4",
"@types/async-eventemitter": "^0.2.1",
"@types/bn.js": "^5.1.0",
"@types/chai": "^4.2.0",
Expand Down Expand Up @@ -98,12 +97,12 @@
"typescript": "~5.0.0"
},
"dependencies": {
"@ethereumjs/common": "^4.4.0",
"@ethereumjs/tx": "^5.4.0",
"@ethereumjs/util": "^9.1.0",
"@ethersproject/abi": "^5.1.2",
"@metamask/eth-sig-util": "^4.0.0",
"@nomicfoundation/edr": "^0.9.0",
"@nomicfoundation/ethereumjs-common": "4.0.4",
"@nomicfoundation/ethereumjs-tx": "5.0.4",
"@nomicfoundation/ethereumjs-util": "9.0.4",
"@nomicfoundation/edr": "^0.10.0",
"@nomicfoundation/solidity-analyzer": "^0.1.0",
"@sentry/node": "^5.18.1",
"@types/bn.js": "^5.1.0",
Expand All @@ -118,7 +117,6 @@
"enquirer": "^2.3.0",
"env-paths": "^2.2.0",
"ethereum-cryptography": "^1.0.3",
"ethereumjs-abi": "^0.6.8",
"find-up": "^5.0.0",
"fp-ts": "1.19.3",
"fs-extra": "^7.0.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/hardhat-core/src/builtin-tasks/node.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type EthereumjsUtilT from "@nomicfoundation/ethereumjs-util";
import type EthereumjsUtilT from "@ethereumjs/util";

import picocolors from "picocolors";
import debug from "debug";
Expand Down Expand Up @@ -56,7 +56,7 @@ function logHardhatNetworkAccounts(networkConfig: HardhatNetworkConfig) {
privateToAddress,
toBytes,
toChecksumAddress,
} = require("@nomicfoundation/ethereumjs-util") as typeof EthereumjsUtilT;
} = require("@ethereumjs/util") as typeof EthereumjsUtilT;

console.log("Accounts");
console.log("========");
Expand Down
1 change: 1 addition & 0 deletions packages/hardhat-core/src/internal/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const HARDHAT_NETWORK_SUPPORTED_HARDFORKS = [
"merge",
"shanghai",
"cancun",
"prague",
];

export const HARDHAT_MEMPOOL_SUPPORTED_ORDERS = ["fifo", "priority"] as const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export const defaultHardhatNetworkParams: Omit<
[HardforkName.MERGE, 15_537_394],
[HardforkName.SHANGHAI, 17_034_870],
[HardforkName.CANCUN, 19_426_589],
[HardforkName.PRAGUE, 30_000_000], // TODO: replace with actual block number
]),
},
],
Expand Down Expand Up @@ -138,6 +139,7 @@ export const defaultHardhatNetworkParams: Omit<
[HardforkName.MERGE, 1_450_409],
[HardforkName.SHANGHAI, 2_990_908],
[HardforkName.CANCUN, 5_187_023],
[HardforkName.PRAGUE, 30_000_000], // TODO: replace with actual block number
]),
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as t from "io-ts";

import { rpcAddress, rpcQuantity, rpcHash, rpcParity } from "./base-types";

const rpcAuthorizationListTuple = t.type({
chainId: rpcQuantity,
address: rpcAddress,
nonce: rpcQuantity,
yParity: rpcParity,
r: rpcHash,
s: rpcHash,
});

export const rpcAuthorizationList = t.array(rpcAuthorizationListTuple);

export type RpcAuthorizationListTuple = t.TypeOf<
typeof rpcAuthorizationListTuple
>;

export type RpcAuthorizationList = t.TypeOf<typeof rpcAuthorizationList>;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
bytesToHex as bufferToHex,
isValidAddress,
toBytes,
} from "@nomicfoundation/ethereumjs-util";
} from "@ethereumjs/util";
import * as t from "io-ts";

import * as BigIntUtils from "../../../util/bigint";
Expand All @@ -27,6 +27,14 @@ export const rpcData = new t.Type<Buffer>(
t.identity
);

export const rpcParity = new t.Type<Buffer>(
"PARITY",
Buffer.isBuffer,
(u, c) =>
isRpcParityString(u) ? t.success(Buffer.from(toBytes(u))) : t.failure(u, c),
t.identity
);

export const rpcHash = new t.Type<Buffer>(
"HASH",
(v): v is Buffer => Buffer.isBuffer(v) && v.length === HASH_LENGTH_BYTES,
Expand Down Expand Up @@ -216,6 +224,10 @@ function isRpcDataString(u: unknown): u is string {
return typeof u === "string" && u.match(/^0x(?:[0-9a-fA-F]{2})*$/) !== null;
}

function isRpcParityString(u: unknown): u is string {
return typeof u === "string" && u.match(/^0x[0-9a-fA-F]{1,2}$/) !== null;
}

function isRpcHashString(u: unknown): u is string {
return typeof u === "string" && u.length === 66 && isRpcDataString(u);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as t from "io-ts";
import { optionalOrNullable } from "../../../../util/io-ts";
import { rpcAccessList } from "../access-list";
import { rpcAddress, rpcData, rpcHash, rpcQuantity } from "../base-types";
import { rpcAuthorizationList } from "../authorization-list";

// Type used by eth_sendTransaction
export const rpcTransactionRequest = t.type(
Expand All @@ -20,6 +21,7 @@ export const rpcTransactionRequest = t.type(
maxPriorityFeePerGas: optionalOrNullable(rpcQuantity),
blobs: optionalOrNullable(t.array(rpcData)),
blobVersionedHashes: optionalOrNullable(t.array(rpcHash)),
authorizationList: optionalOrNullable(rpcAuthorizationList),
},
"RpcTransactionRequest"
);
Expand All @@ -42,6 +44,14 @@ export interface RpcTransactionRequestInput {
maxPriorityFeePerGas?: string;
blobs?: string[];
blobVersionedHashes?: string[];
authorizationList?: Array<{
chainId: string;
address: string;
nonce: string;
yParity: string;
r: string;
s: string;
}>;
}

export type RpcTransactionRequest = t.TypeOf<typeof rpcTransactionRequest>;
62 changes: 45 additions & 17 deletions packages/hardhat-core/src/internal/core/providers/accounts.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as t from "io-ts";

import { signTypedData, SignTypedDataVersion } from "@metamask/eth-sig-util";
import { FeeMarketEIP1559Transaction } from "@nomicfoundation/ethereumjs-tx";
import { FeeMarketEIP1559Transaction } from "@ethereumjs/tx";
import { EIP1193Provider, RequestArguments } from "../../../types";
import { HardhatError } from "../errors";
import { ERRORS } from "../errors-list";
Expand Down Expand Up @@ -49,7 +49,7 @@ export class LocalAccountsProvider extends ProviderWrapperWithChainId {
toRpcSig,
toBytes,
bytesToHex: bufferToHex,
} = await import("@nomicfoundation/ethereumjs-util");
} = await import("@ethereumjs/util");

if (
args.method === "eth_accounts" ||
Expand Down Expand Up @@ -197,7 +197,7 @@ export class LocalAccountsProvider extends ProviderWrapperWithChainId {
bytesToHex: bufferToHex,
toBytes,
privateToAddress,
} = require("@nomicfoundation/ethereumjs-util");
} = require("@ethereumjs/util");

const privateKeys: Buffer[] = localAccountsHexPrivateKeys.map((h) =>
toBytes(h)
Expand All @@ -210,9 +210,7 @@ export class LocalAccountsProvider extends ProviderWrapperWithChainId {
}

private _getPrivateKeyForAddress(address: Buffer): Buffer {
const {
bytesToHex: bufferToHex,
} = require("@nomicfoundation/ethereumjs-util");
const { bytesToHex: bufferToHex } = require("@ethereumjs/util");
const pk = this._addressToPrivateKey.get(bufferToHex(address));
if (pk === undefined) {
throw new HardhatError(ERRORS.NETWORK.NOT_LOCAL_ACCOUNT, {
Expand All @@ -232,9 +230,7 @@ export class LocalAccountsProvider extends ProviderWrapperWithChainId {
}

private async _getNonce(address: Buffer): Promise<bigint> {
const { bytesToHex: bufferToHex } = await import(
"@nomicfoundation/ethereumjs-util"
);
const { bytesToHex: bufferToHex } = await import("@ethereumjs/util");

const response = (await this._wrappedProvider.request({
method: "eth_getTransactionCount",
Expand All @@ -249,11 +245,15 @@ export class LocalAccountsProvider extends ProviderWrapperWithChainId {
chainId: number,
privateKey: Buffer
): Promise<Uint8Array> {
const { AccessListEIP2930Transaction, LegacyTransaction } = await import(
"@nomicfoundation/ethereumjs-tx"
);
const {
AccessListEIP2930Transaction,
LegacyTransaction,
EOACodeEIP7702Transaction,
} = await import("@ethereumjs/tx");

const { Common } = await import("@nomicfoundation/ethereumjs-common");
const { Common } = await import("@ethereumjs/common");

const { toBytes } = await import("@ethereumjs/util");

const txData = {
...transactionRequest,
Expand All @@ -272,8 +272,38 @@ export class LocalAccountsProvider extends ProviderWrapperWithChainId {
({ address, storageKeys }) => [address, storageKeys] as [Buffer, Buffer[]]
);

// we convert the authorization list to the type
// that EOACodeEIP7702Transaction expects
const authorizationList = txData.authorizationList?.map(
({ chainId: authChainId, address, nonce, yParity, r, s }) =>
// TODO: There is an error in the type definition of rpcAuthorizationList
// in the @ethereumjs/[email protected] package where nonce is defined as an
// array but it should be a string. This is fixed in the alpha version
// of the package but is not yet released. To work around this, we wrap
// nonce in an array here. However, this will not be accepted by the
// node and will throw an error.
[
Buffer.from(toBytes(authChainId)),
address,
[Buffer.from(toBytes(nonce))],
yParity,
r,
s,
] as [Buffer, Buffer, Buffer[], Buffer, Buffer, Buffer]
);

let transaction;
if (txData.maxFeePerGas !== undefined) {
if (authorizationList !== undefined) {
transaction = EOACodeEIP7702Transaction.fromTxData(
{
...txData,
accessList,
authorizationList,
gasPrice: undefined,
},
{ common }
);
} else if (txData.maxFeePerGas !== undefined) {
transaction = FeeMarketEIP1559Transaction.fromTxData(
{
...txData,
Expand Down Expand Up @@ -320,9 +350,7 @@ export class HDWalletProvider extends LocalAccountsProvider {
passphrase
);

const {
bytesToHex: bufferToHex,
} = require("@nomicfoundation/ethereumjs-util");
const { bytesToHex: bufferToHex } = require("@ethereumjs/util");
const privateKeysAsHex = privateKeys.map((pk) => bufferToHex(pk));
super(provider, privateKeysAsHex);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/hardhat-core/src/internal/core/providers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export function normalizeHardhatNetworkAccountsConfig(
return accountsConfig;
}

const { bytesToHex } = require("@nomicfoundation/ethereumjs-util");
const { bytesToHex } = require("@ethereumjs/util");

return derivePrivateKeys(
accountsConfig.mnemonic,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import {
Address,
bytesToHex as bufferToHex,
} from "@nomicfoundation/ethereumjs-util";
import { Address, bytesToHex as bufferToHex } from "@ethereumjs/util";
import fsExtra from "fs-extra";
import * as t from "io-ts";
import path from "path";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export interface LegacyTransactionParams extends BaseTransactionParams {

export interface AccessListTransactionParams extends BaseTransactionParams {
gasPrice: bigint;
// We use this access list format because @nomicfoundation/ethereumjs-tx access list data
// We use this access list format because @ethereumjs/tx access list data
// forces us to use it or stringify them
accessList: AccessListBufferItem[];
// We don't include chainId as it's not necessary, the node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export interface RpcBlockOutput {
export type RpcTransactionOutput =
| LegacyRpcTransactionOutput
| AccessListEIP2930RpcTransactionOutput
| EIP1559RpcTransactionOutput;
| EIP1559RpcTransactionOutput
| EOACodeEIP7702TransactionOutput;

interface BaseRpcTransactionOutput {
blockHash: string | null;
Expand Down Expand Up @@ -60,6 +61,15 @@ export type RpcAccessListOutput = Array<{
storageKeys: string[];
}>;

export type RpcAuthorizationListOutput = Array<{
chainId: string;
address: string;
nonce: string;
yParity: string;
r: string;
s: string;
}>;

export interface AccessListEIP2930RpcTransactionOutput
extends BaseRpcTransactionOutput {
gasPrice: string;
Expand All @@ -75,6 +85,11 @@ export interface EIP1559RpcTransactionOutput extends BaseRpcTransactionOutput {
chainId: string;
}

export interface EOACodeEIP7702TransactionOutput
extends EIP1559RpcTransactionOutput {
authorizationList?: RpcAuthorizationListOutput;
}

export interface RpcReceiptOutput {
blockHash: string;
blockNumber: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
HttpHeader,
TracingConfigWithBuffers,
} from "@nomicfoundation/edr";
import { Common } from "@nomicfoundation/ethereumjs-common";
import { Common } from "@ethereumjs/common";
import picocolors from "picocolors";
import debug from "debug";
import { EventEmitter } from "events";
Expand Down
Loading
Loading