diff --git a/CHANGELOG.md b/CHANGELOG.md index 754b6654696..85b5dbfa441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1308,6 +1308,10 @@ should use 4.0.1-alpha.0 for testing. - `formatTransaction` will now replace `data` transaction property with `input` (#5915) - `isTransactionCall` will now check if `value.input` `isHexStrict` if provided (#5915) +#### web3-eth-accounts + +- Moved @ethereumjs/tx, @ethereumjs/common code to our source code (#5963) + #### web3-eth-contract - `getSendTxParams` will now return `input` instead of `data` in returned transaction parameters object (#5915) @@ -1336,7 +1340,6 @@ should use 4.0.1-alpha.0 for testing. #### web3-eth -- Added hybrid build (ESM and CJS) of library (#5904) - Added source files (#5956) #### web3-eth-abi @@ -1409,6 +1412,7 @@ should use 4.0.1-alpha.0 for testing. - Added source files (#5956) - Added hybrid build (ESM and CJS) of library (#5904) +- Added functions `isHexString`, `isHexPrefixed`, `validateNoLeadingZeroes` (#5963) ### Removed @@ -1416,6 +1420,10 @@ should use 4.0.1-alpha.0 for testing. - `getConfig` method from `Web3Config` class, `config` is now public and accessible using `Web3Config.config` (#5950) +#### web3-eth + +- Removed dependencies @ethereumjs/tx, @ethereumjs/common (#5963) + #### web3-eth-abi - Removed `formatDecodedObject` function (#5934) @@ -1424,6 +1432,10 @@ should use 4.0.1-alpha.0 for testing. - `data` was removed as a property of `ContractOptions` type (#5915) +#### web3-utils + +- Removed dependencies @ethereumjs/tx, @ethereumjs/common (#5963) + ### Fixed #### web3-eth-ens diff --git a/packages/web3-errors/src/errors/transaction_errors.ts b/packages/web3-errors/src/errors/transaction_errors.ts index e7e0aa96582..0bdbac9e85e 100644 --- a/packages/web3-errors/src/errors/transaction_errors.ts +++ b/packages/web3-errors/src/errors/transaction_errors.ts @@ -287,7 +287,7 @@ export class CommonOrChainAndHardforkError extends InvalidValueError { public constructor() { super( 'CommonOrChainAndHardforkError', - 'Please provide the @ethereumjs/common object or the chain and hardfork property but not all together.', + 'Please provide the common object or the chain and hardfork property but not all together.', ); } } diff --git a/packages/web3-eth-accounts/CHANGELOG.md b/packages/web3-eth-accounts/CHANGELOG.md index 638f5a9d1cf..4e2814d7d1e 100644 --- a/packages/web3-eth-accounts/CHANGELOG.md +++ b/packages/web3-eth-accounts/CHANGELOG.md @@ -77,3 +77,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added source files (#5956) - Added hybrid build (ESM and CJS) of library (#5904) + +### Changed + +- Moved @ethereumjs/tx, @ethereumjs/common code to our source code (#5963) diff --git a/packages/web3-eth-accounts/package.json b/packages/web3-eth-accounts/package.json index 37bb219d763..eb5e2eb0fd8 100644 --- a/packages/web3-eth-accounts/package.json +++ b/packages/web3-eth-accounts/package.json @@ -57,7 +57,8 @@ "typescript": "^4.7.4" }, "dependencies": { - "@ethereumjs/tx": "^3.5.2", + "@ethereumjs/rlp": "^4.0.1", + "crc-32": "^1.2.2", "ethereum-cryptography": "^1.1.2", "web3-errors": "^1.0.0-rc.0", "web3-types": "^1.0.0-rc.0", diff --git a/packages/web3-eth-accounts/src/account.ts b/packages/web3-eth-accounts/src/account.ts index 16c9c985616..403c1ba81d9 100644 --- a/packages/web3-eth-accounts/src/account.ts +++ b/packages/web3-eth-accounts/src/account.ts @@ -15,8 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { TypedTransaction } from '@ethereumjs/tx'; -import defaultImport, * as fullImport from '@ethereumjs/tx'; import { decrypt as createDecipheriv, encrypt as createCipheriv } from 'ethereum-cryptography/aes'; import { pbkdf2Sync } from 'ethereum-cryptography/pbkdf2'; import { scryptSync } from 'ethereum-cryptography/scrypt'; @@ -54,11 +52,17 @@ import { utf8ToHex, uuidV4, } from 'web3-utils'; + import { isBuffer, isNullish, isString, validator, isHexStrict } from 'web3-validator'; +import { TransactionFactory } from './tx/transactionFactory'; import { keyStoreSchema } from './schemas'; -import { SignatureObject, SignResult, SignTransactionResult, Web3Account } from './types'; - -const { TransactionFactory } = defaultImport || fullImport; +import type { + SignatureObject, + SignResult, + SignTransactionResult, + Web3Account, + TypedTransaction, +} from './types'; /** * Get the private key buffer after the validation @@ -267,9 +271,9 @@ export const signTransaction = async ( return { messageHash: bytesToHex(Buffer.from(signedTx.getMessageToSign(true))), - v: `0x${signedTx.v.toString('hex')}`, - r: `0x${signedTx.r.toString('hex')}`, - s: `0x${signedTx.s.toString('hex')}`, + v: `0x${signedTx.v.toString(16)}`, + r: `0x${signedTx.r.toString(16)}`, + s: `0x${signedTx.s.toString(16)}`, rawTransaction: rawTx, transactionHash: bytesToHex(txHash), }; diff --git a/packages/web3-eth-accounts/src/common/chains/goerli.json b/packages/web3-eth-accounts/src/common/chains/goerli.json new file mode 100644 index 00000000000..4bf14cba143 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/chains/goerli.json @@ -0,0 +1,96 @@ +{ + "name": "goerli", + "chainId": 5, + "networkId": 5, + "defaultHardfork": "merge", + "consensus": { + "type": "poa", + "algorithm": "clique", + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "comment": "Cross-client PoA test network", + "url": "https://github.com/goerli/testnet", + "genesis": { + "timestamp": "0x5c51a607", + "gasLimit": 10485760, + "difficulty": 1, + "nonce": "0x0000000000000000", + "extraData": "0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "homestead", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "tangerineWhistle", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "spuriousDragon", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "byzantium", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "constantinople", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "petersburg", + "block": 0, + "forkHash": "0xa3f5ab08" + }, + { + "name": "istanbul", + "block": 1561651, + "forkHash": "0xc25efa5c" + }, + { + "name": "berlin", + "block": 4460644, + "forkHash": "0x757a1c47" + }, + { + "name": "london", + "block": 5062605, + "forkHash": "0xb8c6299d" + }, + { + "//_comment": "The forkHash will remain same as mergeForkIdTransition is post merge, terminal block: https://goerli.etherscan.io/block/7382818", + "name": "merge", + "ttd": "10790000", + "block": 7382819, + "forkHash": "0xb8c6299d" + }, + { + "name": "mergeForkIdTransition", + "block": null, + "forkHash": null + }, + { + "name": "shanghai", + "block": null, + "forkHash": null + } + ], + "bootstrapNodes": [], + "dnsNetworks": [ + "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.goerli.ethdisco.net" + ] +} diff --git a/packages/web3-eth-accounts/src/common/chains/mainnet.json b/packages/web3-eth-accounts/src/common/chains/mainnet.json new file mode 100644 index 00000000000..035673a027e --- /dev/null +++ b/packages/web3-eth-accounts/src/common/chains/mainnet.json @@ -0,0 +1,112 @@ +{ + "name": "mainnet", + "chainId": 1, + "networkId": 1, + "defaultHardfork": "merge", + "consensus": { + "type": "pow", + "algorithm": "ethash", + "ethash": {} + }, + "comment": "The Ethereum main chain", + "url": "https://ethstats.net/", + "genesis": { + "gasLimit": 5000, + "difficulty": 17179869184, + "nonce": "0x0000000000000042", + "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0, + "forkHash": "0xfc64ec04" + }, + { + "name": "homestead", + "block": 1150000, + "forkHash": "0x97c2c34c" + }, + { + "name": "dao", + "block": 1920000, + "forkHash": "0x91d1f948" + }, + { + "name": "tangerineWhistle", + "block": 2463000, + "forkHash": "0x7a64da13" + }, + { + "name": "spuriousDragon", + "block": 2675000, + "forkHash": "0x3edd5b10" + }, + { + "name": "byzantium", + "block": 4370000, + "forkHash": "0xa00bc324" + }, + { + "name": "constantinople", + "block": 7280000, + "forkHash": "0x668db0af" + }, + { + "name": "petersburg", + "block": 7280000, + "forkHash": "0x668db0af" + }, + { + "name": "istanbul", + "block": 9069000, + "forkHash": "0x879d6e30" + }, + { + "name": "muirGlacier", + "block": 9200000, + "forkHash": "0xe029e991" + }, + { + "name": "berlin", + "block": 12244000, + "forkHash": "0x0eb440f6" + }, + { + "name": "london", + "block": 12965000, + "forkHash": "0xb715077d" + }, + { + "name": "arrowGlacier", + "block": 13773000, + "forkHash": "0x20c327fc" + }, + { + "name": "grayGlacier", + "block": 15050000, + "forkHash": "0xf0afd0e3" + }, + { + "//_comment": "The forkHash will remain same as mergeForkIdTransition is post merge, terminal block: https://etherscan.io/block/15537393", + "name": "merge", + "ttd": "58750000000000000000000", + "block": 15537394, + "forkHash": "0xf0afd0e3" + }, + { + "name": "mergeForkIdTransition", + "block": null, + "forkHash": null + }, + { + "name": "shanghai", + "block": null, + "forkHash": null + } + ], + "bootstrapNodes": [], + "dnsNetworks": [ + "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net" + ] +} diff --git a/packages/web3-eth-accounts/src/common/chains/sepolia.json b/packages/web3-eth-accounts/src/common/chains/sepolia.json new file mode 100644 index 00000000000..7ffbe062e93 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/chains/sepolia.json @@ -0,0 +1,99 @@ +{ + "name": "sepolia", + "chainId": 11155111, + "networkId": 11155111, + "defaultHardfork": "merge", + "consensus": { + "type": "pow", + "algorithm": "ethash", + "ethash": {} + }, + "comment": "PoW test network to replace Ropsten", + "url": "https://github.com/ethereum/go-ethereum/pull/23730", + "genesis": { + "timestamp": "0x6159af19", + "gasLimit": 30000000, + "difficulty": 131072, + "nonce": "0x0000000000000000", + "extraData": "0x5365706f6c69612c20417468656e732c204174746963612c2047726565636521" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "homestead", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "tangerineWhistle", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "spuriousDragon", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "byzantium", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "constantinople", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "petersburg", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "istanbul", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "muirGlacier", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "berlin", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "name": "london", + "block": 0, + "forkHash": "0xfe3366e7" + }, + { + "//_comment": "The forkHash will remain same as mergeForkIdTransition is post merge, terminal block: https://sepolia.etherscan.io/block/1450408", + "name": "merge", + "ttd": "17000000000000000", + "block": 1450409, + "forkHash": "0xfe3366e7" + }, + { + "name": "mergeForkIdTransition", + "block": 1735371, + "forkHash": "0xb96cbd13" + }, + { + "name": "shanghai", + "block": null, + "timestamp": "1677557088", + "forkHash": "0xf7f9bc08" + } + ], + "bootstrapNodes": [], + "dnsNetworks": [ + "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.sepolia.ethdisco.net" + ] +} diff --git a/packages/web3-eth-accounts/src/common/common.ts b/packages/web3-eth-accounts/src/common/common.ts new file mode 100644 index 00000000000..ed29ccd8b15 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/common.ts @@ -0,0 +1,1207 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { buf as crc32Buffer } from 'crc-32'; +import { EventEmitter } from 'events'; +import type { Numbers } from 'web3-types'; +import { TypeOutput } from './types'; +import { intToBuffer, toType, parseGethGenesis } from './utils'; +import goerli from './chains/goerli.json'; +import mainnet from './chains/mainnet.json'; +import sepolia from './chains/sepolia.json'; +import { EIPs } from './eips'; +import type { ConsensusAlgorithm, ConsensusType } from './enums'; +import { Chain, CustomChain, Hardfork } from './enums'; +import { hardforks as HARDFORK_SPECS } from './hardforks'; +import type { + BootstrapNodeConfig, + CasperConfig, + ChainConfig, + ChainName, + ChainsConfig, + CliqueConfig, + CommonOpts, + CustomCommonOpts, + EthashConfig, + GenesisBlockConfig, + GethConfigOpts, + HardforkConfig, +} from './types'; + +type HardforkSpecKeys = keyof typeof HARDFORK_SPECS; +type HardforkSpecValues = typeof HARDFORK_SPECS[HardforkSpecKeys]; +/** + * Common class to access chain and hardfork parameters and to provide + * a unified and shared view on the network and hardfork state. + * + * Use the {@link Common.custom} static constructor for creating simple + * custom chain {@link Common} objects (more complete custom chain setups + * can be created via the main constructor and the {@link CommonOpts.customChains} parameter). + */ +export class Common extends EventEmitter { + public readonly DEFAULT_HARDFORK: string | Hardfork; + + private _chainParams: ChainConfig; + private _hardfork: string | Hardfork; + private _eips: number[] = []; + private readonly _customChains: ChainConfig[]; + + private readonly HARDFORK_CHANGES: [HardforkSpecKeys, HardforkSpecValues][]; + + /** + * Creates a {@link Common} object for a custom chain, based on a standard one. + * + * It uses all the {@link Chain} parameters from the {@link baseChain} option except the ones overridden + * in a provided {@link chainParamsOrName} dictionary. Some usage example: + * + * ```javascript + * Common.custom({chainId: 123}) + * ``` + * + * There are also selected supported custom chains which can be initialized by using one of the + * {@link CustomChains} for {@link chainParamsOrName}, e.g.: + * + * ```javascript + * Common.custom(CustomChains.MaticMumbai) + * ``` + * + * Note that these supported custom chains only provide some base parameters (usually the chain and + * network ID and a name) and can only be used for selected use cases (e.g. sending a tx with + * the `web3-utils/tx` library to a Layer-2 chain). + * + * @param chainParamsOrName Custom parameter dict (`name` will default to `custom-chain`) or string with name of a supported custom chain + * @param opts Custom chain options to set the {@link CustomCommonOpts.baseChain}, selected {@link CustomCommonOpts.hardfork} and others + */ + public static custom( + chainParamsOrName: Partial | CustomChain, + opts: CustomCommonOpts = {}, + ): Common { + const baseChain = opts.baseChain ?? 'mainnet'; + const standardChainParams = { ...Common._getChainParams(baseChain) }; + standardChainParams.name = 'custom-chain'; + + if (typeof chainParamsOrName !== 'string') { + return new Common({ + chain: { + ...standardChainParams, + ...chainParamsOrName, + }, + ...opts, + }); + } + if (chainParamsOrName === CustomChain.PolygonMainnet) { + return Common.custom( + { + name: CustomChain.PolygonMainnet, + chainId: 137, + networkId: 137, + }, + opts, + ); + } + if (chainParamsOrName === CustomChain.PolygonMumbai) { + return Common.custom( + { + name: CustomChain.PolygonMumbai, + chainId: 80001, + networkId: 80001, + }, + opts, + ); + } + if (chainParamsOrName === CustomChain.ArbitrumRinkebyTestnet) { + return Common.custom( + { + name: CustomChain.ArbitrumRinkebyTestnet, + chainId: 421611, + networkId: 421611, + }, + opts, + ); + } + if (chainParamsOrName === CustomChain.ArbitrumOne) { + return Common.custom( + { + name: CustomChain.ArbitrumOne, + chainId: 42161, + networkId: 42161, + }, + opts, + ); + } + if (chainParamsOrName === CustomChain.xDaiChain) { + return Common.custom( + { + name: CustomChain.xDaiChain, + chainId: 100, + networkId: 100, + }, + opts, + ); + } + + if (chainParamsOrName === CustomChain.OptimisticKovan) { + return Common.custom( + { + name: CustomChain.OptimisticKovan, + chainId: 69, + networkId: 69, + }, + // Optimism has not implemented the London hardfork yet (targeting Q1.22) + { hardfork: Hardfork.Berlin, ...opts }, + ); + } + + if (chainParamsOrName === CustomChain.OptimisticEthereum) { + return Common.custom( + { + name: CustomChain.OptimisticEthereum, + chainId: 10, + networkId: 10, + }, + // Optimism has not implemented the London hardfork yet (targeting Q1.22) + { hardfork: Hardfork.Berlin, ...opts }, + ); + } + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`Custom chain ${chainParamsOrName} not supported`); + } + + /** + * Static method to load and set common from a geth genesis json + * @param genesisJson json of geth configuration + * @param { chain, eips, genesisHash, hardfork, mergeForkIdPostMerge } to further configure the common instance + * @returns Common + */ + public static fromGethGenesis( + genesisJson: any, + { chain, eips, genesisHash, hardfork, mergeForkIdPostMerge }: GethConfigOpts, + ): Common { + const genesisParams = parseGethGenesis(genesisJson, chain, mergeForkIdPostMerge); + const common = new Common({ + chain: genesisParams.name ?? 'custom', + customChains: [genesisParams], + eips, + hardfork: hardfork ?? genesisParams.hardfork, + }); + if (genesisHash !== undefined) { + common.setForkHashes(genesisHash); + } + return common; + } + + /** + * Static method to determine if a {@link chainId} is supported as a standard chain + * @param chainId bigint id (`1`) of a standard chain + * @returns boolean + */ + public static isSupportedChainId(chainId: bigint): boolean { + const initializedChains = this._getInitializedChains(); + return Boolean((initializedChains.names as ChainName)[chainId.toString()]); + } + + private static _getChainParams( + _chain: string | number | Chain | bigint, + customChains?: ChainConfig[], + ): ChainConfig { + let chain = _chain; + const initializedChains = this._getInitializedChains(customChains); + if (typeof chain === 'number' || typeof chain === 'bigint') { + chain = chain.toString(); + + if ((initializedChains.names as ChainName)[chain]) { + const name: string = (initializedChains.names as ChainName)[chain]; + return initializedChains[name] as ChainConfig; + } + + throw new Error(`Chain with ID ${chain} not supported`); + } + + if (initializedChains[chain] !== undefined) { + return initializedChains[chain] as ChainConfig; + } + + throw new Error(`Chain with name ${chain} not supported`); + } + + public constructor(opts: CommonOpts) { + super(); + this._customChains = opts.customChains ?? []; + this._chainParams = this.setChain(opts.chain); + this.DEFAULT_HARDFORK = this._chainParams.defaultHardfork ?? Hardfork.Merge; + // Assign hardfork changes in the sequence of the applied hardforks + this.HARDFORK_CHANGES = this.hardforks().map(hf => [ + hf.name as HardforkSpecKeys, + HARDFORK_SPECS[hf.name as HardforkSpecKeys], + ]); + this._hardfork = this.DEFAULT_HARDFORK; + if (opts.hardfork !== undefined) { + this.setHardfork(opts.hardfork); + } + if (opts.eips) { + this.setEIPs(opts.eips); + } + } + + /** + * Sets the chain + * @param chain String ('mainnet') or Number (1) chain representation. + * Or, a Dictionary of chain parameters for a private network. + * @returns The dictionary with parameters set as chain + */ + public setChain(chain: string | number | Chain | bigint | object): ChainConfig { + if (typeof chain === 'number' || typeof chain === 'bigint' || typeof chain === 'string') { + this._chainParams = Common._getChainParams(chain, this._customChains); + } else if (typeof chain === 'object') { + if (this._customChains.length > 0) { + throw new Error( + 'Chain must be a string, number, or bigint when initialized with customChains passed in', + ); + } + const required = ['networkId', 'genesis', 'hardforks', 'bootstrapNodes']; + for (const param of required) { + if (!(param in chain)) { + throw new Error(`Missing required chain parameter: ${param}`); + } + } + this._chainParams = chain as ChainConfig; + } else { + throw new Error('Wrong input format'); + } + for (const hf of this.hardforks()) { + if (hf.block === undefined) { + throw new Error(`Hardfork cannot have undefined block number`); + } + } + return this._chainParams; + } + + /** + * Sets the hardfork to get params for + * @param hardfork String identifier (e.g. 'byzantium') or {@link Hardfork} enum + */ + public setHardfork(hardfork: string | Hardfork): void { + let existing = false; + for (const hfChanges of this.HARDFORK_CHANGES) { + if (hfChanges[0] === hardfork) { + if (this._hardfork !== hardfork) { + this._hardfork = hardfork; + this.emit('hardforkChanged', hardfork); + } + existing = true; + } + } + if (!existing) { + throw new Error(`Hardfork with name ${hardfork} not supported`); + } + } + + /** + * Returns the hardfork based on the block number or an optional + * total difficulty (Merge HF) provided. + * + * An optional TD takes precedence in case the corresponding HF block + * is set to `null` or otherwise needs to match (if not an error + * will be thrown). + * + * @param blockNumber + * @param td : total difficulty of the parent block (for block hf) OR of the chain latest (for chain hf) + * @param timestamp: timestamp in seconds at which block was/is to be minted + * @returns The name of the HF + */ + public getHardforkByBlockNumber( + _blockNumber: Numbers, + _td?: Numbers, + _timestamp?: Numbers, + ): string { + const blockNumber = toType(_blockNumber, TypeOutput.BigInt); + const td = toType(_td, TypeOutput.BigInt); + const timestamp = toType(_timestamp, TypeOutput.Number); + + // Filter out hardforks with no block number, no ttd or no timestamp (i.e. unapplied hardforks) + const hfs = this.hardforks().filter( + hf => + // eslint-disable-next-line no-null/no-null + hf.block !== null || + // eslint-disable-next-line no-null/no-null + (hf.ttd !== null && hf.ttd !== undefined) || + hf.timestamp !== undefined, + ); + // eslint-disable-next-line no-null/no-null + const mergeIndex = hfs.findIndex(hf => hf.ttd !== null && hf.ttd !== undefined); + const doubleTTDHF = hfs + .slice(mergeIndex + 1) + // eslint-disable-next-line no-null/no-null + .findIndex(hf => hf.ttd !== null && hf.ttd !== undefined); + if (doubleTTDHF >= 0) { + throw Error(`More than one merge hardforks found with ttd specified`); + } + + // Find the first hardfork that has a block number greater than `blockNumber` + // (skips the merge hardfork since it cannot have a block number specified). + // If timestamp is not provided, it also skips timestamps hardforks to continue + // discovering/checking number hardforks. + let hfIndex = hfs.findIndex( + hf => + // eslint-disable-next-line no-null/no-null + (hf.block !== null && hf.block > blockNumber) || + (timestamp !== undefined && Number(hf.timestamp) > timestamp), + ); + + if (hfIndex === -1) { + // all hardforks apply, set hfIndex to the last one as that's the candidate + hfIndex = hfs.length; + } else if (hfIndex === 0) { + // cannot have a case where a block number is before all applied hardforks + // since the chain has to start with a hardfork + throw Error('Must have at least one hardfork at block 0'); + } + + // If timestamp is not provided, we need to rollback to the last hf with block or ttd + if (timestamp === undefined) { + const stepBack = hfs + .slice(0, hfIndex) + .reverse() + // eslint-disable-next-line no-null/no-null + .findIndex(hf => hf.block !== null || hf.ttd !== undefined); + hfIndex -= stepBack; + } + // Move hfIndex one back to arrive at candidate hardfork + hfIndex -= 1; + + // If the timestamp was not provided, we could have skipped timestamp hardforks to look for number + // hardforks. so it will now be needed to rollback + // eslint-disable-next-line no-null/no-null + if (hfs[hfIndex].block === null && hfs[hfIndex].timestamp === undefined) { + // We're on the merge hardfork. Let's check the TTD + // eslint-disable-next-line no-null/no-null + if (td === undefined || td === null || BigInt(hfs[hfIndex].ttd!) > td) { + // Merge ttd greater than current td so we're on hardfork before merge + hfIndex -= 1; + } + // eslint-disable-next-line no-null/no-null + } else if (mergeIndex >= 0 && td !== undefined && td !== null) { + if (hfIndex >= mergeIndex && BigInt(hfs[mergeIndex].ttd!) > td) { + throw Error( + 'Maximum HF determined by total difficulty is lower than the block number HF', + ); + } else if (hfIndex < mergeIndex && BigInt(hfs[mergeIndex].ttd!) <= td) { + throw Error( + 'HF determined by block number is lower than the minimum total difficulty HF', + ); + } + } + + const hfStartIndex = hfIndex; + // Move the hfIndex to the end of the hardforks that might be scheduled on the same block/timestamp + // This won't anyway be the case with Merge hfs + for (; hfIndex < hfs.length - 1; hfIndex += 1) { + // break out if hfIndex + 1 is not scheduled at hfIndex + if ( + hfs[hfIndex].block !== hfs[hfIndex + 1].block || + hfs[hfIndex].timestamp !== hfs[hfIndex + 1].timestamp + ) { + break; + } + } + + if (timestamp) { + const minTimeStamp = hfs + .slice(0, hfStartIndex) + .reduce( + (acc: number, hf: HardforkConfig) => Math.max(Number(hf.timestamp ?? '0'), acc), + 0, + ); + if (minTimeStamp > timestamp) { + throw Error( + `Maximum HF determined by timestamp is lower than the block number/ttd HF`, + ); + } + + const maxTimeStamp = hfs + .slice(hfIndex + 1) + .reduce( + (acc: number, hf: HardforkConfig) => + Math.min(Number(hf.timestamp ?? timestamp), acc), + timestamp, + ); + if (maxTimeStamp < timestamp) { + throw Error(`Maximum HF determined by block number/ttd is lower than timestamp HF`); + } + } + const hardfork = hfs[hfIndex]; + return hardfork.name; + } + + /** + * Sets a new hardfork based on the block number or an optional + * total difficulty (Merge HF) provided. + * + * An optional TD takes precedence in case the corresponding HF block + * is set to `null` or otherwise needs to match (if not an error + * will be thrown). + * + * @param blockNumber + * @param td + * @param timestamp + * @returns The name of the HF set + */ + public setHardforkByBlockNumber( + blockNumber: Numbers, + td?: Numbers, + timestamp?: Numbers, + ): string { + const hardfork = this.getHardforkByBlockNumber(blockNumber, td, timestamp); + this.setHardfork(hardfork); + return hardfork; + } + + /** + * Internal helper function, returns the params for the given hardfork for the chain set + * @param hardfork Hardfork name + * @returns Dictionary with hardfork params or null if hardfork not on chain + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public _getHardfork(hardfork: string | Hardfork): HardforkConfig | null { + const hfs = this.hardforks(); + for (const hf of hfs) { + if (hf.name === hardfork) return hf; + } + // eslint-disable-next-line no-null/no-null + return null; + } + + /** + * Sets the active EIPs + * @param eips + */ + public setEIPs(eips: number[] = []) { + for (const eip of eips) { + if (!(eip in EIPs)) { + throw new Error(`${eip} not supported`); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument + const minHF = this.gteHardfork(EIPs[eip].minimumHardfork); + if (!minHF) { + throw new Error( + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `${eip} cannot be activated on hardfork ${this.hardfork()}, minimumHardfork: ${minHF}`, + ); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (EIPs[eip].requiredEIPs !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + for (const elem of EIPs[eip].requiredEIPs) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + if (!(eips.includes(elem) || this.isActivatedEIP(elem))) { + throw new Error( + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + `${eip} requires EIP ${elem}, but is not included in the EIP list`, + ); + } + } + } + } + this._eips = eips; + } + + /** + * Returns a parameter for the current chain setup + * + * If the parameter is present in an EIP, the EIP always takes precedence. + * Otherwise the parameter if taken from the latest applied HF with + * a change on the respective parameter. + * + * @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow') + * @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic) + * @returns The value requested or `BigInt(0)` if not found + */ + public param(topic: string, name: string): bigint { + // TODO: consider the case that different active EIPs + // can change the same parameter + let value; + for (const eip of this._eips) { + value = this.paramByEIP(topic, name, eip); + if (value !== undefined) return value; + } + return this.paramByHardfork(topic, name, this._hardfork); + } + + /** + * Returns the parameter corresponding to a hardfork + * @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow') + * @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic) + * @param hardfork Hardfork name + * @returns The value requested or `BigInt(0)` if not found + */ + public paramByHardfork(topic: string, name: string, hardfork: string | Hardfork): bigint { + // eslint-disable-next-line no-null/no-null + let value = null; + for (const hfChanges of this.HARDFORK_CHANGES) { + // EIP-referencing HF file (e.g. berlin.json) + if ('eips' in hfChanges[1]) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + const hfEIPs = hfChanges[1].eips; + for (const eip of hfEIPs) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const valueEIP = this.paramByEIP(topic, name, eip); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + value = typeof valueEIP === 'bigint' ? valueEIP : value; + } + // Parameter-inlining HF file (e.g. istanbul.json) + } else { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (hfChanges[1][topic] === undefined) { + throw new Error(`Topic ${topic} not defined`); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (hfChanges[1][topic][name] !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + value = hfChanges[1][topic][name].v; + } + } + if (hfChanges[0] === hardfork) break; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return BigInt(value ?? 0); + } + + /** + * Returns a parameter corresponding to an EIP + * @param topic Parameter topic ('gasConfig', 'gasPrices', 'vm', 'pow') + * @param name Parameter name (e.g. 'minGasLimit' for 'gasConfig' topic) + * @param eip Number of the EIP + * @returns The value requested or `undefined` if not found + */ + // eslint-disable-next-line class-methods-use-this + public paramByEIP(topic: string, name: string, eip: number): bigint | undefined { + if (!(eip in EIPs)) { + throw new Error(`${eip} not supported`); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const eipParams = EIPs[eip]; + if (!(topic in eipParams)) { + throw new Error(`Topic ${topic} not defined`); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (eipParams[topic][name] === undefined) { + return undefined; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + const value = eipParams[topic][name].v; + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return BigInt(value); + } + + /** + * Returns a parameter for the hardfork active on block number or + * optional provided total difficulty (Merge HF) + * @param topic Parameter topic + * @param name Parameter name + * @param blockNumber Block number + * @param td Total difficulty + * * @returns The value requested or `BigInt(0)` if not found + */ + public paramByBlock( + topic: string, + name: string, + blockNumber: Numbers, + td?: Numbers, + timestamp?: Numbers, + ): bigint { + const hardfork = this.getHardforkByBlockNumber(blockNumber, td, timestamp); + return this.paramByHardfork(topic, name, hardfork); + } + + /** + * Checks if an EIP is activated by either being included in the EIPs + * manually passed in with the {@link CommonOpts.eips} or in a + * hardfork currently being active + * + * Note: this method only works for EIPs being supported + * by the {@link CommonOpts.eips} constructor option + * @param eip + */ + public isActivatedEIP(eip: number): boolean { + if (this.eips().includes(eip)) { + return true; + } + for (const hfChanges of this.HARDFORK_CHANGES) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const hf = hfChanges[1]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument + if (this.gteHardfork(hf.name) && 'eips' in hf) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if ((hf.eips as number[]).includes(eip)) { + return true; + } + } + } + return false; + } + + /** + * Checks if set or provided hardfork is active on block number + * @param hardfork Hardfork name or null (for HF set) + * @param blockNumber + * @returns True if HF is active on block number + */ + public hardforkIsActiveOnBlock( + // eslint-disable-next-line @typescript-eslint/ban-types + _hardfork: string | Hardfork | null, + _blockNumber: Numbers, + ): boolean { + const blockNumber = toType(_blockNumber, TypeOutput.BigInt); + const hardfork = _hardfork ?? this._hardfork; + const hfBlock = this.hardforkBlock(hardfork); + if (typeof hfBlock === 'bigint' && hfBlock !== BigInt(0) && blockNumber >= hfBlock) { + return true; + } + return false; + } + + /** + * Alias to hardforkIsActiveOnBlock when hardfork is set + * @param blockNumber + * @returns True if HF is active on block number + */ + public activeOnBlock(blockNumber: Numbers): boolean { + // eslint-disable-next-line no-null/no-null + return this.hardforkIsActiveOnBlock(null, blockNumber); + } + + /** + * Sequence based check if given or set HF1 is greater than or equal HF2 + * @param hardfork1 Hardfork name or null (if set) + * @param hardfork2 Hardfork name + * @param opts Hardfork options + * @returns True if HF1 gte HF2 + */ + public hardforkGteHardfork( + // eslint-disable-next-line @typescript-eslint/ban-types + _hardfork1: string | Hardfork | null, + hardfork2: string | Hardfork, + ): boolean { + const hardfork1 = _hardfork1 ?? this._hardfork; + const hardforks = this.hardforks(); + + let posHf1 = -1; + let posHf2 = -1; + let index = 0; + for (const hf of hardforks) { + if (hf.name === hardfork1) posHf1 = index; + if (hf.name === hardfork2) posHf2 = index; + index += 1; + } + return posHf1 >= posHf2 && posHf2 !== -1; + } + + /** + * Alias to hardforkGteHardfork when hardfork is set + * @param hardfork Hardfork name + * @returns True if hardfork set is greater than hardfork provided + */ + public gteHardfork(hardfork: string | Hardfork): boolean { + // eslint-disable-next-line no-null/no-null + return this.hardforkGteHardfork(null, hardfork); + } + + /** + * Returns the hardfork change block for hardfork provided or set + * @param hardfork Hardfork name, optional if HF set + * @returns Block number or null if unscheduled + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public hardforkBlock(_hardfork?: string | Hardfork): bigint | null { + const hardfork = _hardfork ?? this._hardfork; + const block = this._getHardfork(hardfork)?.block; + // eslint-disable-next-line no-null/no-null + if (block === undefined || block === null) { + // eslint-disable-next-line no-null/no-null + return null; + } + return BigInt(block); + } + // eslint-disable-next-line @typescript-eslint/ban-types + public hardforkTimestamp(_hardfork?: string | Hardfork): bigint | null { + const hardfork = _hardfork ?? this._hardfork; + const timestamp = this._getHardfork(hardfork)?.timestamp; + // eslint-disable-next-line no-null/no-null + if (timestamp === undefined || timestamp === null) { + // eslint-disable-next-line no-null/no-null + return null; + } + return BigInt(timestamp); + } + + /** + * Returns the hardfork change block for eip + * @param eip EIP number + * @returns Block number or null if unscheduled + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public eipBlock(eip: number): bigint | null { + for (const hfChanges of this.HARDFORK_CHANGES) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const hf = hfChanges[1]; + if ('eips' in hf) { + // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + if (hf.eips.includes(eip)) { + return this.hardforkBlock( + typeof hfChanges[0] === 'number' ? String(hfChanges[0]) : hfChanges[0], + ); + } + } + } + // eslint-disable-next-line no-null/no-null + return null; + } + + /** + * Returns the hardfork change total difficulty (Merge HF) for hardfork provided or set + * @param hardfork Hardfork name, optional if HF set + * @returns Total difficulty or null if no set + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public hardforkTTD(_hardfork?: string | Hardfork): bigint | null { + const hardfork = _hardfork ?? this._hardfork; + const ttd = this._getHardfork(hardfork)?.ttd; + // eslint-disable-next-line no-null/no-null + if (ttd === undefined || ttd === null) { + // eslint-disable-next-line no-null/no-null + return null; + } + return BigInt(ttd); + } + + /** + * True if block number provided is the hardfork (given or set) change block + * @param blockNumber Number of the block to check + * @param hardfork Hardfork name, optional if HF set + * @returns True if blockNumber is HF block + * @deprecated + */ + public isHardforkBlock(_blockNumber: Numbers, _hardfork?: string | Hardfork): boolean { + const blockNumber = toType(_blockNumber, TypeOutput.BigInt); + const hardfork = _hardfork ?? this._hardfork; + const block = this.hardforkBlock(hardfork); + return typeof block === 'bigint' && block !== BigInt(0) ? block === blockNumber : false; + } + + /** + * Returns the change block for the next hardfork after the hardfork provided or set + * @param hardfork Hardfork name, optional if HF set + * @returns Block timestamp, number or null if not available + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public nextHardforkBlockOrTimestamp(_hardfork?: string | Hardfork): bigint | null { + const hardfork = _hardfork ?? this._hardfork; + const hfs = this.hardforks(); + let hfIndex = hfs.findIndex(hf => hf.name === hardfork); + // If the current hardfork is merge, go one behind as merge hf is not part of these + // calcs even if the merge hf block is set + if (hardfork === Hardfork.Merge) { + hfIndex -= 1; + } + // Hardfork not found + if (hfIndex < 0) { + // eslint-disable-next-line no-null/no-null + return null; + } + + let currHfTimeOrBlock = hfs[hfIndex].timestamp ?? hfs[hfIndex].block; + currHfTimeOrBlock = + // eslint-disable-next-line no-null/no-null + currHfTimeOrBlock !== null && currHfTimeOrBlock !== undefined + ? Number(currHfTimeOrBlock) + : // eslint-disable-next-line no-null/no-null + null; + + const nextHf = hfs.slice(hfIndex + 1).find(hf => { + let hfTimeOrBlock = hf.timestamp ?? hf.block; + hfTimeOrBlock = + // eslint-disable-next-line no-null/no-null + hfTimeOrBlock !== null && hfTimeOrBlock !== undefined + ? Number(hfTimeOrBlock) + : // eslint-disable-next-line no-null/no-null + null; + return ( + hf.name !== Hardfork.Merge && + // eslint-disable-next-line no-null/no-null + hfTimeOrBlock !== null && + hfTimeOrBlock !== undefined && + hfTimeOrBlock !== currHfTimeOrBlock + ); + }); + // If no next hf found with valid block or timestamp return null + if (nextHf === undefined) { + // eslint-disable-next-line no-null/no-null + return null; + } + + const nextHfBlock = nextHf.timestamp ?? nextHf.block; + // eslint-disable-next-line no-null/no-null + if (nextHfBlock === null || nextHfBlock === undefined) { + // eslint-disable-next-line no-null/no-null + return null; + } + + return BigInt(nextHfBlock); + } + + /** + * Returns the change block for the next hardfork after the hardfork provided or set + * @param hardfork Hardfork name, optional if HF set + * @returns Block number or null if not available + * @deprecated + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public nextHardforkBlock(_hardfork?: string | Hardfork): bigint | null { + const hardfork = _hardfork ?? this._hardfork; + let hfBlock = this.hardforkBlock(hardfork); + // If this is a merge hardfork with block not set, then we fallback to previous hardfork + // to find the nextHardforkBlock + // eslint-disable-next-line no-null/no-null + if (hfBlock === null && hardfork === Hardfork.Merge) { + const hfs = this.hardforks(); + // eslint-disable-next-line no-null/no-null + const mergeIndex = hfs.findIndex(hf => hf.ttd !== null && hf.ttd !== undefined); + if (mergeIndex < 0) { + throw Error(`Merge hardfork should have been found`); + } + hfBlock = this.hardforkBlock(hfs[mergeIndex - 1].name); + } + // eslint-disable-next-line no-null/no-null + if (hfBlock === null) { + // eslint-disable-next-line no-null/no-null + return null; + } + // Next fork block number or null if none available + // Logic: if accumulator is still null and on the first occurrence of + // a block greater than the current hfBlock set the accumulator, + // pass on the accumulator as the final result from this time on + // eslint-disable-next-line no-null/no-null, @typescript-eslint/ban-types + const nextHfBlock = this.hardforks().reduce((acc: bigint | null, hf: HardforkConfig) => { + // We need to ignore the merge block in our next hardfork calc + const block = BigInt( + // eslint-disable-next-line no-null/no-null + hf.block === null || (hf.ttd !== undefined && hf.ttd !== null) ? 0 : hf.block, + ); + // Typescript can't seem to follow that the hfBlock is not null at this point + // eslint-disable-next-line no-null/no-null + return block > hfBlock! && acc === null ? block : acc; + // eslint-disable-next-line no-null/no-null + }, null); + return nextHfBlock; + } + + /** + * True if block number provided is the hardfork change block following the hardfork given or set + * @param blockNumber Number of the block to check + * @param hardfork Hardfork name, optional if HF set + * @returns True if blockNumber is HF block + * @deprecated + */ + public isNextHardforkBlock(_blockNumber: Numbers, _hardfork?: string | Hardfork): boolean { + const blockNumber = toType(_blockNumber, TypeOutput.BigInt); + const hardfork = _hardfork ?? this._hardfork; + // eslint-disable-next-line deprecation/deprecation + const nextHardforkBlock = this.nextHardforkBlock(hardfork); + // eslint-disable-next-line no-null/no-null + return nextHardforkBlock === null ? false : nextHardforkBlock === blockNumber; + } + + /** + * Internal helper function to calculate a fork hash + * @param hardfork Hardfork name + * @param genesisHash Genesis block hash of the chain + * @returns Fork hash as hex string + */ + public _calcForkHash(hardfork: string | Hardfork, genesisHash: Buffer) { + let hfBuffer = Buffer.alloc(0); + let prevBlockOrTime = 0; + for (const hf of this.hardforks()) { + const { block, timestamp, name } = hf; + // Timestamp to be used for timestamp based hfs even if we may bundle + // block number with them retrospectively + let blockOrTime = timestamp ?? block; + // eslint-disable-next-line no-null/no-null + blockOrTime = blockOrTime !== null ? Number(blockOrTime) : null; + + // Skip for chainstart (0), not applied HFs (null) and + // when already applied on same blockOrTime HFs + // and on the merge since forkhash doesn't change on merge hf + if ( + typeof blockOrTime === 'number' && + blockOrTime !== 0 && + blockOrTime !== prevBlockOrTime && + name !== Hardfork.Merge + ) { + const hfBlockBuffer = Buffer.from( + blockOrTime.toString(16).padStart(16, '0'), + 'hex', + ); + hfBuffer = Buffer.concat([hfBuffer, hfBlockBuffer]); + prevBlockOrTime = blockOrTime; + } + + if (hf.name === hardfork) break; + } + const inputBuffer = Buffer.concat([genesisHash, hfBuffer]); + + // CRC32 delivers result as signed (negative) 32-bit integer, + // convert to hex string + // eslint-disable-next-line no-bitwise + const forkhash = intToBuffer(crc32Buffer(inputBuffer) >>> 0).toString('hex'); + return `0x${forkhash}`; + } + + /** + * Returns an eth/64 compliant fork hash (EIP-2124) + * @param hardfork Hardfork name, optional if HF set + * @param genesisHash Genesis block hash of the chain, optional if already defined and not needed to be calculated + */ + public forkHash(_hardfork?: string | Hardfork, genesisHash?: Buffer): string { + const hardfork = _hardfork ?? this._hardfork; + const data = this._getHardfork(hardfork); + if ( + // eslint-disable-next-line no-null/no-null + data === null || + // eslint-disable-next-line no-null/no-null + (data?.block === null && data?.timestamp === undefined && data?.ttd === undefined) + ) { + const msg = 'No fork hash calculation possible for future hardfork'; + throw new Error(msg); + } + // eslint-disable-next-line no-null/no-null + if (data?.forkHash !== null && data?.forkHash !== undefined) { + return data.forkHash; + } + if (!genesisHash) throw new Error('genesisHash required for forkHash calculation'); + return this._calcForkHash(hardfork, genesisHash); + } + + /** + * + * @param forkHash Fork hash as a hex string + * @returns Array with hardfork data (name, block, forkHash) + */ + // eslint-disable-next-line @typescript-eslint/ban-types + public hardforkForForkHash(forkHash: string): HardforkConfig | null { + const resArray = this.hardforks().filter((hf: HardforkConfig) => hf.forkHash === forkHash); + // eslint-disable-next-line no-null/no-null + return resArray.length >= 1 ? resArray[resArray.length - 1] : null; + } + + /** + * Sets any missing forkHashes on the passed-in {@link Common} instance + * @param common The {@link Common} to set the forkHashes for + * @param genesisHash The genesis block hash + */ + public setForkHashes(genesisHash: Buffer) { + for (const hf of this.hardforks()) { + const blockOrTime = hf.timestamp ?? hf.block; + if ( + // eslint-disable-next-line no-null/no-null + (hf.forkHash === null || hf.forkHash === undefined) && + // eslint-disable-next-line no-null/no-null + ((blockOrTime !== null && blockOrTime !== undefined) || + typeof hf.ttd !== 'undefined') + ) { + hf.forkHash = this.forkHash(hf.name, genesisHash); + } + } + } + + /** + * Returns the Genesis parameters of the current chain + * @returns Genesis dictionary + */ + public genesis(): GenesisBlockConfig { + return this._chainParams.genesis; + } + + /** + * Returns the hardforks for current chain + * @returns {Array} Array with arrays of hardforks + */ + public hardforks(): HardforkConfig[] { + return this._chainParams.hardforks; + } + + /** + * Returns bootstrap nodes for the current chain + * @returns {Dictionary} Dict with bootstrap nodes + */ + public bootstrapNodes(): BootstrapNodeConfig[] | undefined { + return this._chainParams.bootstrapNodes; + } + + /** + * Returns DNS networks for the current chain + * @returns {String[]} Array of DNS ENR urls + */ + public dnsNetworks(): string[] { + return this._chainParams.dnsNetworks!; + } + + /** + * Returns the hardfork set + * @returns Hardfork name + */ + public hardfork(): string | Hardfork { + return this._hardfork; + } + + /** + * Returns the Id of current chain + * @returns chain Id + */ + public chainId(): bigint { + return BigInt(this._chainParams.chainId); + } + + /** + * Returns the name of current chain + * @returns chain name (lower case) + */ + public chainName(): string { + return this._chainParams.name; + } + + /** + * Returns the Id of current network + * @returns network Id + */ + public networkId(): bigint { + return BigInt(this._chainParams.networkId); + } + + /** + * Returns the active EIPs + * @returns List of EIPs + */ + public eips(): number[] { + return this._eips; + } + + /** + * Returns the consensus type of the network + * Possible values: "pow"|"poa"|"pos" + * + * Note: This value can update along a Hardfork. + */ + public consensusType(): string | ConsensusType { + const hardfork = this.hardfork(); + + let value; + for (const hfChanges of this.HARDFORK_CHANGES) { + if ('consensus' in hfChanges[1]) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + value = hfChanges[1].consensus.type; + } + if (hfChanges[0] === hardfork) break; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return value ?? this._chainParams.consensus.type; + } + + /** + * Returns the concrete consensus implementation + * algorithm or protocol for the network + * e.g. "ethash" for "pow" consensus type, + * "clique" for "poa" consensus type or + * "casper" for "pos" consensus type. + * + * Note: This value can update along a Hardfork. + */ + public consensusAlgorithm(): string | ConsensusAlgorithm { + const hardfork = this.hardfork(); + + let value; + for (const hfChanges of this.HARDFORK_CHANGES) { + if ('consensus' in hfChanges[1]) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + value = hfChanges[1].consensus.algorithm; + } + if (hfChanges[0] === hardfork) break; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return value ?? (this._chainParams.consensus.algorithm as ConsensusAlgorithm); + } + + /** + * Returns a dictionary with consensus configuration + * parameters based on the consensus algorithm + * + * Expected returns (parameters must be present in + * the respective chain json files): + * + * ethash: empty object + * clique: period, epoch + * casper: empty object + * + * Note: This value can update along a Hardfork. + */ + public consensusConfig(): { [key: string]: CliqueConfig | EthashConfig | CasperConfig } { + const hardfork = this.hardfork(); + + let value; + for (const hfChanges of this.HARDFORK_CHANGES) { + if ('consensus' in hfChanges[1]) { + // The config parameter is named after the respective consensus algorithm + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + value = hfChanges[1].consensus[hfChanges[1].consensus.algorithm]; + } + if (hfChanges[0] === hardfork) break; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return ( + value ?? + this._chainParams.consensus[this.consensusAlgorithm() as ConsensusAlgorithm] ?? + {} + ); + } + + /** + * Returns a deep copy of this {@link Common} instance. + */ + public copy(): Common { + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment + const copy = Object.assign(Object.create(Object.getPrototypeOf(this)), this); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + copy.removeAllListeners(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return copy; + } + + public static _getInitializedChains(customChains?: ChainConfig[]): ChainsConfig { + const names: ChainName = {}; + for (const [name, id] of Object.entries(Chain)) { + names[id] = name.toLowerCase(); + } + const chains = { mainnet, goerli, sepolia } as ChainsConfig; + if (customChains) { + for (const chain of customChains) { + const { name } = chain; + names[chain.chainId.toString()] = name; + chains[name] = chain; + } + } + chains.names = names; + return chains; + } +} diff --git a/packages/web3-eth-accounts/src/common/eips/1153.json b/packages/web3-eth-accounts/src/common/eips/1153.json new file mode 100644 index 00000000000..7aa4c1dd859 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/1153.json @@ -0,0 +1,22 @@ +{ + "name": "EIP-1153", + "number": 1153, + "comment": "Transient Storage", + "url": "https://eips.ethereum.org/EIPS/eip-1153", + "status": "Review", + "minimumHardfork": "chainstart", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": { + "tstore": { + "v": 100, + "d": "Base fee of the TSTORE opcode" + }, + "tload": { + "v": 100, + "d": "Base fee of the TLOAD opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/1559.json b/packages/web3-eth-accounts/src/common/eips/1559.json new file mode 100644 index 00000000000..d18eb8da268 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/1559.json @@ -0,0 +1,26 @@ +{ + "name": "EIP-1559", + "number": 1559, + "comment": "Fee market change for ETH 1.0 chain", + "url": "https://eips.ethereum.org/EIPS/eip-1559", + "status": "Final", + "minimumHardfork": "berlin", + "requiredEIPs": [2930], + "gasConfig": { + "baseFeeMaxChangeDenominator": { + "v": 8, + "d": "Maximum base fee change denominator" + }, + "elasticityMultiplier": { + "v": 2, + "d": "Maximum block gas target elasticity" + }, + "initialBaseFee": { + "v": 1000000000, + "d": "Initial base fee on first EIP1559 block" + } + }, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/2315.json b/packages/web3-eth-accounts/src/common/eips/2315.json new file mode 100644 index 00000000000..31b1ffe8b3b --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/2315.json @@ -0,0 +1,25 @@ +{ + "name": "EIP-2315", + "number": 2315, + "comment": "Simple subroutines for the EVM", + "url": "https://eips.ethereum.org/EIPS/eip-2315", + "status": "Draft", + "minimumHardfork": "istanbul", + "gasConfig": {}, + "gasPrices": { + "beginsub": { + "v": 2, + "d": "Base fee of the BEGINSUB opcode" + }, + "returnsub": { + "v": 5, + "d": "Base fee of the RETURNSUB opcode" + }, + "jumpsub": { + "v": 10, + "d": "Base fee of the JUMPSUB opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/2537.json b/packages/web3-eth-accounts/src/common/eips/2537.json new file mode 100644 index 00000000000..e4258e16d9b --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/2537.json @@ -0,0 +1,178 @@ +{ + "name": "EIP-2537", + "number": 2537, + "comment": "BLS12-381 precompiles", + "url": "https://eips.ethereum.org/EIPS/eip-2537", + "status": "Draft", + "minimumHardfork": "chainstart", + "gasConfig": {}, + "gasPrices": { + "Bls12381G1AddGas": { + "v": 600, + "d": "Gas cost of a single BLS12-381 G1 addition precompile-call" + }, + "Bls12381G1MulGas": { + "v": 12000, + "d": "Gas cost of a single BLS12-381 G1 multiplication precompile-call" + }, + "Bls12381G2AddGas": { + "v": 4500, + "d": "Gas cost of a single BLS12-381 G2 addition precompile-call" + }, + "Bls12381G2MulGas": { + "v": 55000, + "d": "Gas cost of a single BLS12-381 G2 multiplication precompile-call" + }, + "Bls12381PairingBaseGas": { + "v": 115000, + "d": "Base gas cost of BLS12-381 pairing check" + }, + "Bls12381PairingPerPairGas": { + "v": 23000, + "d": "Per-pair gas cost of BLS12-381 pairing check" + }, + "Bls12381MapG1Gas": { + "v": 5500, + "d": "Gas cost of BLS12-381 map field element to G1" + }, + "Bls12381MapG2Gas": { + "v": 110000, + "d": "Gas cost of BLS12-381 map field element to G2" + }, + "Bls12381MultiExpGasDiscount": { + "v": [ + [1, 1200], + [2, 888], + [3, 764], + [4, 641], + [5, 594], + [6, 547], + [7, 500], + [8, 453], + [9, 438], + [10, 423], + [11, 408], + [12, 394], + [13, 379], + [14, 364], + [15, 349], + [16, 334], + [17, 330], + [18, 326], + [19, 322], + [20, 318], + [21, 314], + [22, 310], + [23, 306], + [24, 302], + [25, 298], + [26, 294], + [27, 289], + [28, 285], + [29, 281], + [30, 277], + [31, 273], + [32, 269], + [33, 268], + [34, 266], + [35, 265], + [36, 263], + [37, 262], + [38, 260], + [39, 259], + [40, 257], + [41, 256], + [42, 254], + [43, 253], + [44, 251], + [45, 250], + [46, 248], + [47, 247], + [48, 245], + [49, 244], + [50, 242], + [51, 241], + [52, 239], + [53, 238], + [54, 236], + [55, 235], + [56, 233], + [57, 232], + [58, 231], + [59, 229], + [60, 228], + [61, 226], + [62, 225], + [63, 223], + [64, 222], + [65, 221], + [66, 220], + [67, 219], + [68, 219], + [69, 218], + [70, 217], + [71, 216], + [72, 216], + [73, 215], + [74, 214], + [75, 213], + [76, 213], + [77, 212], + [78, 211], + [79, 211], + [80, 210], + [81, 209], + [82, 208], + [83, 208], + [84, 207], + [85, 206], + [86, 205], + [87, 205], + [88, 204], + [89, 203], + [90, 202], + [91, 202], + [92, 201], + [93, 200], + [94, 199], + [95, 199], + [96, 198], + [97, 197], + [98, 196], + [99, 196], + [100, 195], + [101, 194], + [102, 193], + [103, 193], + [104, 192], + [105, 191], + [106, 191], + [107, 190], + [108, 189], + [109, 188], + [110, 188], + [111, 187], + [112, 186], + [113, 185], + [114, 185], + [115, 184], + [116, 183], + [117, 182], + [118, 182], + [119, 181], + [120, 180], + [121, 179], + [122, 179], + [123, 178], + [124, 177], + [125, 176], + [126, 176], + [127, 175], + [128, 174] + ], + "d": "Discount gas costs of calls to the MultiExp precompiles with `k` (point, scalar) pair" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/2565.json b/packages/web3-eth-accounts/src/common/eips/2565.json new file mode 100644 index 00000000000..0452fc2346f --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/2565.json @@ -0,0 +1,17 @@ +{ + "name": "EIP-2565", + "number": 2565, + "comment": "ModExp gas cost", + "url": "https://eips.ethereum.org/EIPS/eip-2565", + "status": "Final", + "minimumHardfork": "byzantium", + "gasConfig": {}, + "gasPrices": { + "modexpGquaddivisor": { + "v": 3, + "d": "Gquaddivisor from modexp precompile for gas calculation" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/2718.json b/packages/web3-eth-accounts/src/common/eips/2718.json new file mode 100644 index 00000000000..9437a698856 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/2718.json @@ -0,0 +1,11 @@ +{ + "name": "EIP-2718", + "comment": "Typed Transaction Envelope", + "url": "https://eips.ethereum.org/EIPS/eip-2718", + "status": "Final", + "minimumHardfork": "chainstart", + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/2929.json b/packages/web3-eth-accounts/src/common/eips/2929.json new file mode 100644 index 00000000000..711883ccec1 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/2929.json @@ -0,0 +1,84 @@ +{ + "name": "EIP-2929", + "comment": "Gas cost increases for state access opcodes", + "url": "https://eips.ethereum.org/EIPS/eip-2929", + "status": "Final", + "minimumHardfork": "chainstart", + "gasConfig": {}, + "gasPrices": { + "coldsload": { + "v": 2100, + "d": "Gas cost of the first read of storage from a given location (per transaction)" + }, + "coldaccountaccess": { + "v": 2600, + "d": "Gas cost of the first read of a given address (per transaction)" + }, + "warmstorageread": { + "v": 100, + "d": "Gas cost of reading storage locations which have already loaded 'cold'" + }, + "sstoreCleanGasEIP2200": { + "v": 2900, + "d": "Once per SSTORE operation from clean non-zero to something else" + }, + "sstoreNoopGasEIP2200": { + "v": 100, + "d": "Once per SSTORE operation if the value doesn't change" + }, + "sstoreDirtyGasEIP2200": { + "v": 100, + "d": "Once per SSTORE operation if a dirty value is changed" + }, + "sstoreInitRefundEIP2200": { + "v": 19900, + "d": "Once per SSTORE operation for resetting to the original zero value" + }, + "sstoreCleanRefundEIP2200": { + "v": 4900, + "d": "Once per SSTORE operation for resetting to the original non-zero value" + }, + "call": { + "v": 0, + "d": "Base fee of the CALL opcode" + }, + "callcode": { + "v": 0, + "d": "Base fee of the CALLCODE opcode" + }, + "delegatecall": { + "v": 0, + "d": "Base fee of the DELEGATECALL opcode" + }, + "staticcall": { + "v": 0, + "d": "Base fee of the STATICCALL opcode" + }, + "balance": { + "v": 0, + "d": "Base fee of the BALANCE opcode" + }, + "extcodesize": { + "v": 0, + "d": "Base fee of the EXTCODESIZE opcode" + }, + "extcodecopy": { + "v": 0, + "d": "Base fee of the EXTCODECOPY opcode" + }, + "extcodehash": { + "v": 0, + "d": "Base fee of the EXTCODEHASH opcode" + }, + "sload": { + "v": 0, + "d": "Base fee of the SLOAD opcode" + }, + "sstore": { + "v": 0, + "d": "Base fee of the SSTORE opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/2930.json b/packages/web3-eth-accounts/src/common/eips/2930.json new file mode 100644 index 00000000000..6ceb668a9ce --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/2930.json @@ -0,0 +1,21 @@ +{ + "name": "EIP-2930", + "comment": "Optional access lists", + "url": "https://eips.ethereum.org/EIPS/eip-2930", + "status": "Final", + "minimumHardfork": "istanbul", + "requiredEIPs": [2718, 2929], + "gasConfig": {}, + "gasPrices": { + "accessListStorageKeyCost": { + "v": 1900, + "d": "Gas cost per storage key in an Access List transaction" + }, + "accessListAddressCost": { + "v": 2400, + "d": "Gas cost per storage key in an Access List transaction" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3074.json b/packages/web3-eth-accounts/src/common/eips/3074.json new file mode 100644 index 00000000000..fa8a0958460 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3074.json @@ -0,0 +1,25 @@ +{ + "name": "EIP-3074", + "number": 3074, + "comment": "AUTH and AUTHCALL opcodes", + "url": "https://eips.ethereum.org/EIPS/eip-3074", + "status": "Review", + "minimumHardfork": "london", + "gasConfig": {}, + "gasPrices": { + "auth": { + "v": 3100, + "d": "Gas cost of the AUTH opcode" + }, + "authcall": { + "v": 0, + "d": "Gas cost of the AUTHCALL opcode" + }, + "authcallValueTransfer": { + "v": 6700, + "d": "Paid for CALL when the value transfer is non-zero" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3198.json b/packages/web3-eth-accounts/src/common/eips/3198.json new file mode 100644 index 00000000000..804174d8727 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3198.json @@ -0,0 +1,17 @@ +{ + "name": "EIP-3198", + "number": 3198, + "comment": "BASEFEE opcode", + "url": "https://eips.ethereum.org/EIPS/eip-3198", + "status": "Final", + "minimumHardfork": "london", + "gasConfig": {}, + "gasPrices": { + "basefee": { + "v": 2, + "d": "Gas cost of the BASEFEE opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3529.json b/packages/web3-eth-accounts/src/common/eips/3529.json new file mode 100644 index 00000000000..d4136b95bab --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3529.json @@ -0,0 +1,26 @@ +{ + "name": "EIP-3529", + "comment": "Reduction in refunds", + "url": "https://eips.ethereum.org/EIPS/eip-3529", + "status": "Final", + "minimumHardfork": "berlin", + "requiredEIPs": [2929], + "gasConfig": { + "maxRefundQuotient": { + "v": 5, + "d": "Maximum refund quotient; max tx refund is min(tx.gasUsed/maxRefundQuotient, tx.gasRefund)" + } + }, + "gasPrices": { + "selfdestructRefund": { + "v": 0, + "d": "Refunded following a selfdestruct operation" + }, + "sstoreClearRefundEIP2200": { + "v": 4800, + "d": "Once per SSTORE operation for clearing an originally existing storage slot" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3540.json b/packages/web3-eth-accounts/src/common/eips/3540.json new file mode 100644 index 00000000000..e70c7f5b4dc --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3540.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-3540", + "number": 3540, + "comment": "EVM Object Format (EOF) v1", + "url": "https://eips.ethereum.org/EIPS/eip-3540", + "status": "Review", + "minimumHardfork": "london", + "requiredEIPs": [3541], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3541.json b/packages/web3-eth-accounts/src/common/eips/3541.json new file mode 100644 index 00000000000..5d11a3103f5 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3541.json @@ -0,0 +1,12 @@ +{ + "name": "EIP-3541", + "comment": "Reject new contracts starting with the 0xEF byte", + "url": "https://eips.ethereum.org/EIPS/eip-3541", + "status": "Final", + "minimumHardfork": "berlin", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3554.json b/packages/web3-eth-accounts/src/common/eips/3554.json new file mode 100644 index 00000000000..272d45e6c81 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3554.json @@ -0,0 +1,17 @@ +{ + "name": "EIP-3554", + "comment": "Reduction in refunds", + "url": "Difficulty Bomb Delay to December 1st 2021", + "status": "Final", + "minimumHardfork": "muirGlacier", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": { + "difficultyBombDelay": { + "v": 9500000, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/eips/3607.json b/packages/web3-eth-accounts/src/common/eips/3607.json new file mode 100644 index 00000000000..9cc04499e45 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3607.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-3607", + "number": 3607, + "comment": "Reject transactions from senders with deployed code", + "url": "https://eips.ethereum.org/EIPS/eip-3607", + "status": "Final", + "minimumHardfork": "chainstart", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3651.json b/packages/web3-eth-accounts/src/common/eips/3651.json new file mode 100644 index 00000000000..e7ad7c0b37b --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3651.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-3651", + "number": 3198, + "comment": "Warm COINBASE", + "url": "https://eips.ethereum.org/EIPS/eip-3651", + "status": "Review", + "minimumHardfork": "london", + "requiredEIPs": [2929], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3670.json b/packages/web3-eth-accounts/src/common/eips/3670.json new file mode 100644 index 00000000000..8848156062c --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3670.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-3670", + "number": 3670, + "comment": "EOF - Code Validation", + "url": "https://eips.ethereum.org/EIPS/eip-3670", + "status": "Review", + "minimumHardfork": "london", + "requiredEIPs": [3540], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3675.json b/packages/web3-eth-accounts/src/common/eips/3675.json new file mode 100644 index 00000000000..84f76dd3e2d --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3675.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-3675", + "number": 3675, + "comment": "Upgrade consensus to Proof-of-Stake", + "url": "https://eips.ethereum.org/EIPS/eip-3675", + "status": "Final", + "minimumHardfork": "london", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3855.json b/packages/web3-eth-accounts/src/common/eips/3855.json new file mode 100644 index 00000000000..112abb7bf48 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3855.json @@ -0,0 +1,18 @@ +{ + "name": "EIP-3855", + "number": 3855, + "comment": "PUSH0 instruction", + "url": "https://eips.ethereum.org/EIPS/eip-3855", + "status": "Review", + "minimumHardfork": "chainstart", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": { + "push0": { + "v": 2, + "d": "Base fee of the PUSH0 opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/3860.json b/packages/web3-eth-accounts/src/common/eips/3860.json new file mode 100644 index 00000000000..9cdd890c268 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/3860.json @@ -0,0 +1,23 @@ +{ + "name": "EIP-3860", + "number": 3860, + "comment": "Limit and meter initcode", + "url": "https://eips.ethereum.org/EIPS/eip-3860", + "status": "Review", + "minimumHardfork": "spuriousDragon", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": { + "initCodeWordCost": { + "v": 2, + "d": "Gas to pay for each word (32 bytes) of initcode when creating a contract" + } + }, + "vm": { + "maxInitCodeSize": { + "v": 49152, + "d": "Maximum length of initialization code when creating a contract" + } + }, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/4345.json b/packages/web3-eth-accounts/src/common/eips/4345.json new file mode 100644 index 00000000000..7928b1ece28 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/4345.json @@ -0,0 +1,17 @@ +{ + "name": "EIP-4345", + "number": 4345, + "comment": "Difficulty Bomb Delay to June 2022", + "url": "https://eips.ethereum.org/EIPS/eip-4345", + "status": "Final", + "minimumHardfork": "london", + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": { + "difficultyBombDelay": { + "v": 10700000, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/eips/4399.json b/packages/web3-eth-accounts/src/common/eips/4399.json new file mode 100644 index 00000000000..fd2f0faff96 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/4399.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-4399", + "number": 4399, + "comment": "Supplant DIFFICULTY opcode with PREVRANDAO", + "url": "https://eips.ethereum.org/EIPS/eip-4399", + "status": "Review", + "minimumHardfork": "london", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/4844.json b/packages/web3-eth-accounts/src/common/eips/4844.json new file mode 100644 index 00000000000..da755d6334a --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/4844.json @@ -0,0 +1,57 @@ +{ + "name": "EIP-4844", + "number": 4844, + "comment": "Shard Blob Transactions", + "url": "https://eips.ethereum.org/EIPS/eip-4844", + "status": "Draft", + "minimumHardfork": "merge", + "requiredEIPs": [1559, 2718, 2930, 4895], + "gasConfig": { + "dataGasPerBlob": { + "v": 131072, + "d": "The base fee for data gas per blob" + }, + "targetDataGasPerBlock": { + "v": 262144, + "d": "The target data gas consumed per block" + }, + "maxDataGasPerBlock": { + "v": 524288, + "d": "The max data gas allowable per block" + }, + "dataGasPriceUpdateFraction": { + "v": 2225652, + "d": "The denominator used in the exponential when calculating a data gas price" + } + }, + "gasPrices": { + "simpleGasPerBlob": { + "v": 12000, + "d": "The basic gas fee for each blob" + }, + "minDataGasPrice": { + "v": 1, + "d": "The minimum fee per data gas" + }, + "kzgPointEvaluationGasPrecompilePrice": { + "v": 50000, + "d": "The fee associated with the point evaluation precompile" + }, + "datahash": { + "v": 3, + "d": "Base fee of the DATAHASH opcode" + } + }, + "sharding": { + "blobCommitmentVersionKzg": { + "v": 1, + "d": "The number indicated a versioned hash is a KZG commitment" + }, + "fieldElementsPerBlob": { + "v": 4096, + "d": "The number of field elements allowed per blob" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/4895.json b/packages/web3-eth-accounts/src/common/eips/4895.json new file mode 100644 index 00000000000..6722f0e9b1e --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/4895.json @@ -0,0 +1,13 @@ +{ + "name": "EIP-4895", + "number": 4895, + "comment": "Beacon chain push withdrawals as operations", + "url": "https://eips.ethereum.org/EIPS/eip-4895", + "status": "Review", + "minimumHardfork": "merge", + "requiredEIPs": [], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/eips/5133.json b/packages/web3-eth-accounts/src/common/eips/5133.json new file mode 100644 index 00000000000..eaeb623baca --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/5133.json @@ -0,0 +1,17 @@ +{ + "name": "EIP-5133", + "number": 5133, + "comment": "Delaying Difficulty Bomb to mid-September 2022", + "url": "https://eips.ethereum.org/EIPS/eip-5133", + "status": "Draft", + "minimumHardfork": "grayGlacier", + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": { + "difficultyBombDelay": { + "v": 11400000, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/eips/index.ts b/packages/web3-eth-accounts/src/common/eips/index.ts new file mode 100644 index 00000000000..9c10148e746 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/eips/index.ts @@ -0,0 +1,63 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import e1153 from './1153.json'; +import e1559 from './1559.json'; +import e2315 from './2315.json'; +import e2537 from './2537.json'; +import e2565 from './2565.json'; +import e2718 from './2718.json'; +import e2929 from './2929.json'; +import e2930 from './2930.json'; +import e3198 from './3198.json'; +import e3529 from './3529.json'; +import e3540 from './3540.json'; +import e3541 from './3541.json'; +import e3554 from './3554.json'; +import e3607 from './3607.json'; +import e3651 from './3651.json'; +import e3670 from './3670.json'; +import e3675 from './3675.json'; +import e3855 from './3855.json'; +import e3860 from './3860.json'; +import e4345 from './4345.json'; +import e4399 from './4399.json'; +import e5133 from './5133.json'; + +export const EIPs: { [key: number]: any } = { + 1153: e1153, + 1559: e1559, + 2315: e2315, + 2537: e2537, + 2565: e2565, + 2718: e2718, + 2929: e2929, + 2930: e2930, + 3198: e3198, + 3529: e3529, + 3540: e3540, + 3541: e3541, + 3554: e3554, + 3607: e3607, + 3651: e3651, + 3670: e3670, + 3675: e3675, + 3855: e3855, + 3860: e3860, + 4345: e4345, + 4399: e4399, + 5133: e5133, +}; diff --git a/packages/web3-eth-accounts/src/common/enums.ts b/packages/web3-eth-accounts/src/common/enums.ts new file mode 100644 index 00000000000..0661dd0519b --- /dev/null +++ b/packages/web3-eth-accounts/src/common/enums.ts @@ -0,0 +1,105 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +export enum Chain { + Mainnet = 1, + Goerli = 5, + Sepolia = 11155111, +} + +export enum Hardfork { + Chainstart = 'chainstart', + Homestead = 'homestead', + Dao = 'dao', + TangerineWhistle = 'tangerineWhistle', + SpuriousDragon = 'spuriousDragon', + Byzantium = 'byzantium', + Constantinople = 'constantinople', + Petersburg = 'petersburg', + Istanbul = 'istanbul', + MuirGlacier = 'muirGlacier', + Berlin = 'berlin', + London = 'london', + ArrowGlacier = 'arrowGlacier', + GrayGlacier = 'grayGlacier', + MergeForkIdTransition = 'mergeForkIdTransition', + Merge = 'merge', + Shanghai = 'shanghai', + ShardingForkDev = 'shardingFork', +} + +export enum ConsensusType { + ProofOfStake = 'pos', + ProofOfWork = 'pow', + ProofOfAuthority = 'poa', +} + +export enum ConsensusAlgorithm { + Ethash = 'ethash', + Clique = 'clique', + Casper = 'casper', +} + +export enum CustomChain { + /** + * Polygon (Matic) Mainnet + * + * - [Documentation](https://docs.matic.network/docs/develop/network-details/network) + */ + PolygonMainnet = 'polygon-mainnet', + + /** + * Polygon (Matic) Mumbai Testnet + * + * - [Documentation](https://docs.matic.network/docs/develop/network-details/network) + */ + PolygonMumbai = 'polygon-mumbai', + + /** + * Arbitrum Rinkeby Testnet + * + * - [Documentation](https://developer.offchainlabs.com/docs/public_testnet) + */ + ArbitrumRinkebyTestnet = 'arbitrum-rinkeby-testnet', + + /** + * Arbitrum One - mainnet for Arbitrum roll-up + * + * - [Documentation](https://developer.offchainlabs.com/public-chains) + */ + ArbitrumOne = 'arbitrum-one', + + /** + * xDai EVM sidechain with a native stable token + * + * - [Documentation](https://www.xdaichain.com/) + */ + xDaiChain = 'x-dai-chain', + + /** + * Optimistic Kovan - testnet for Optimism roll-up + * + * - [Documentation](https://community.optimism.io/docs/developers/tutorials.html) + */ + OptimisticKovan = 'optimistic-kovan', + + /** + * Optimistic Ethereum - mainnet for Optimism roll-up + * + * - [Documentation](https://community.optimism.io/docs/developers/tutorials.html) + */ + OptimisticEthereum = 'optimistic-ethereum', +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/arrowGlacier.json b/packages/web3-eth-accounts/src/common/hardforks/arrowGlacier.json new file mode 100644 index 00000000000..7c0148920a1 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/arrowGlacier.json @@ -0,0 +1,11 @@ +{ + "name": "arrowGlacier", + "comment": "HF to delay the difficulty bomb", + "url": "https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/arrow-glacier.md", + "status": "Final", + "eips": [4345], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/berlin.json b/packages/web3-eth-accounts/src/common/hardforks/berlin.json new file mode 100644 index 00000000000..09b731f14fa --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/berlin.json @@ -0,0 +1,7 @@ +{ + "name": "berlin", + "comment": "HF targeted for July 2020 following the Muir Glacier HF", + "url": "https://eips.ethereum.org/EIPS/eip-2070", + "status": "Final", + "eips": [2565, 2929, 2718, 2930] +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/byzantium.json b/packages/web3-eth-accounts/src/common/hardforks/byzantium.json new file mode 100644 index 00000000000..80a3f70f1d6 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/byzantium.json @@ -0,0 +1,56 @@ +{ + "name": "byzantium", + "comment": "Hardfork with new precompiles, instructions and other protocol changes", + "url": "https://eips.ethereum.org/EIPS/eip-609", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "modexpGquaddivisor": { + "v": 20, + "d": "Gquaddivisor from modexp precompile for gas calculation" + }, + "ecAdd": { + "v": 500, + "d": "Gas costs for curve addition precompile" + }, + "ecMul": { + "v": 40000, + "d": "Gas costs for curve multiplication precompile" + }, + "ecPairing": { + "v": 100000, + "d": "Base gas costs for curve pairing precompile" + }, + "ecPairingWord": { + "v": 80000, + "d": "Gas costs regarding curve pairing precompile input length" + }, + "revert": { + "v": 0, + "d": "Base fee of the REVERT opcode" + }, + "staticcall": { + "v": 700, + "d": "Base fee of the STATICCALL opcode" + }, + "returndatasize": { + "v": 2, + "d": "Base fee of the RETURNDATASIZE opcode" + }, + "returndatacopy": { + "v": 3, + "d": "Base fee of the RETURNDATACOPY opcode" + } + }, + "vm": {}, + "pow": { + "minerReward": { + "v": "3000000000000000000", + "d": "the amount a miner get rewarded for mining a block" + }, + "difficultyBombDelay": { + "v": 3000000, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/chainstart.json b/packages/web3-eth-accounts/src/common/hardforks/chainstart.json new file mode 100644 index 00000000000..0e58d2e326b --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/chainstart.json @@ -0,0 +1,438 @@ +{ + "name": "chainstart", + "comment": "Start of the Ethereum main chain", + "url": "", + "status": "", + "gasConfig": { + "minGasLimit": { + "v": 5000, + "d": "Minimum the gas limit may ever be" + }, + "gasLimitBoundDivisor": { + "v": 1024, + "d": "The bound divisor of the gas limit, used in update calculations" + }, + "maxRefundQuotient": { + "v": 2, + "d": "Maximum refund quotient; max tx refund is min(tx.gasUsed/maxRefundQuotient, tx.gasRefund)" + } + }, + "gasPrices": { + "base": { + "v": 2, + "d": "Gas base cost, used e.g. for ChainID opcode (Istanbul)" + }, + "tierStep": { + "v": [0, 2, 3, 5, 8, 10, 20], + "d": "Once per operation, for a selection of them" + }, + "exp": { + "v": 10, + "d": "Base fee of the EXP opcode" + }, + "expByte": { + "v": 10, + "d": "Times ceil(log256(exponent)) for the EXP instruction" + }, + "sha3": { + "v": 30, + "d": "Base fee of the SHA3 opcode" + }, + "sha3Word": { + "v": 6, + "d": "Once per word of the SHA3 operation's data" + }, + "sload": { + "v": 50, + "d": "Base fee of the SLOAD opcode" + }, + "sstoreSet": { + "v": 20000, + "d": "Once per SSTORE operation if the zeroness changes from zero" + }, + "sstoreReset": { + "v": 5000, + "d": "Once per SSTORE operation if the zeroness does not change from zero" + }, + "sstoreRefund": { + "v": 15000, + "d": "Once per SSTORE operation if the zeroness changes to zero" + }, + "jumpdest": { + "v": 1, + "d": "Base fee of the JUMPDEST opcode" + }, + "log": { + "v": 375, + "d": "Base fee of the LOG opcode" + }, + "logData": { + "v": 8, + "d": "Per byte in a LOG* operation's data" + }, + "logTopic": { + "v": 375, + "d": "Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas" + }, + "create": { + "v": 32000, + "d": "Base fee of the CREATE opcode" + }, + "call": { + "v": 40, + "d": "Base fee of the CALL opcode" + }, + "callStipend": { + "v": 2300, + "d": "Free gas given at beginning of call" + }, + "callValueTransfer": { + "v": 9000, + "d": "Paid for CALL when the value transfor is non-zero" + }, + "callNewAccount": { + "v": 25000, + "d": "Paid for CALL when the destination address didn't exist prior" + }, + "selfdestructRefund": { + "v": 24000, + "d": "Refunded following a selfdestruct operation" + }, + "memory": { + "v": 3, + "d": "Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL" + }, + "quadCoeffDiv": { + "v": 512, + "d": "Divisor for the quadratic particle of the memory cost equation" + }, + "createData": { + "v": 200, + "d": "" + }, + "tx": { + "v": 21000, + "d": "Per transaction. NOTE: Not payable on data of calls between transactions" + }, + "txCreation": { + "v": 32000, + "d": "The cost of creating a contract via tx" + }, + "txDataZero": { + "v": 4, + "d": "Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions" + }, + "txDataNonZero": { + "v": 68, + "d": "Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions" + }, + "copy": { + "v": 3, + "d": "Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added" + }, + "ecRecover": { + "v": 3000, + "d": "" + }, + "sha256": { + "v": 60, + "d": "" + }, + "sha256Word": { + "v": 12, + "d": "" + }, + "ripemd160": { + "v": 600, + "d": "" + }, + "ripemd160Word": { + "v": 120, + "d": "" + }, + "identity": { + "v": 15, + "d": "" + }, + "identityWord": { + "v": 3, + "d": "" + }, + "stop": { + "v": 0, + "d": "Base fee of the STOP opcode" + }, + "add": { + "v": 3, + "d": "Base fee of the ADD opcode" + }, + "mul": { + "v": 5, + "d": "Base fee of the MUL opcode" + }, + "sub": { + "v": 3, + "d": "Base fee of the SUB opcode" + }, + "div": { + "v": 5, + "d": "Base fee of the DIV opcode" + }, + "sdiv": { + "v": 5, + "d": "Base fee of the SDIV opcode" + }, + "mod": { + "v": 5, + "d": "Base fee of the MOD opcode" + }, + "smod": { + "v": 5, + "d": "Base fee of the SMOD opcode" + }, + "addmod": { + "v": 8, + "d": "Base fee of the ADDMOD opcode" + }, + "mulmod": { + "v": 8, + "d": "Base fee of the MULMOD opcode" + }, + "signextend": { + "v": 5, + "d": "Base fee of the SIGNEXTEND opcode" + }, + "lt": { + "v": 3, + "d": "Base fee of the LT opcode" + }, + "gt": { + "v": 3, + "d": "Base fee of the GT opcode" + }, + "slt": { + "v": 3, + "d": "Base fee of the SLT opcode" + }, + "sgt": { + "v": 3, + "d": "Base fee of the SGT opcode" + }, + "eq": { + "v": 3, + "d": "Base fee of the EQ opcode" + }, + "iszero": { + "v": 3, + "d": "Base fee of the ISZERO opcode" + }, + "and": { + "v": 3, + "d": "Base fee of the AND opcode" + }, + "or": { + "v": 3, + "d": "Base fee of the OR opcode" + }, + "xor": { + "v": 3, + "d": "Base fee of the XOR opcode" + }, + "not": { + "v": 3, + "d": "Base fee of the NOT opcode" + }, + "byte": { + "v": 3, + "d": "Base fee of the BYTE opcode" + }, + "address": { + "v": 2, + "d": "Base fee of the ADDRESS opcode" + }, + "balance": { + "v": 20, + "d": "Base fee of the BALANCE opcode" + }, + "origin": { + "v": 2, + "d": "Base fee of the ORIGIN opcode" + }, + "caller": { + "v": 2, + "d": "Base fee of the CALLER opcode" + }, + "callvalue": { + "v": 2, + "d": "Base fee of the CALLVALUE opcode" + }, + "calldataload": { + "v": 3, + "d": "Base fee of the CALLDATALOAD opcode" + }, + "calldatasize": { + "v": 2, + "d": "Base fee of the CALLDATASIZE opcode" + }, + "calldatacopy": { + "v": 3, + "d": "Base fee of the CALLDATACOPY opcode" + }, + "codesize": { + "v": 2, + "d": "Base fee of the CODESIZE opcode" + }, + "codecopy": { + "v": 3, + "d": "Base fee of the CODECOPY opcode" + }, + "gasprice": { + "v": 2, + "d": "Base fee of the GASPRICE opcode" + }, + "extcodesize": { + "v": 20, + "d": "Base fee of the EXTCODESIZE opcode" + }, + "extcodecopy": { + "v": 20, + "d": "Base fee of the EXTCODECOPY opcode" + }, + "blockhash": { + "v": 20, + "d": "Base fee of the BLOCKHASH opcode" + }, + "coinbase": { + "v": 2, + "d": "Base fee of the COINBASE opcode" + }, + "timestamp": { + "v": 2, + "d": "Base fee of the TIMESTAMP opcode" + }, + "number": { + "v": 2, + "d": "Base fee of the NUMBER opcode" + }, + "difficulty": { + "v": 2, + "d": "Base fee of the DIFFICULTY opcode" + }, + "gaslimit": { + "v": 2, + "d": "Base fee of the GASLIMIT opcode" + }, + "pop": { + "v": 2, + "d": "Base fee of the POP opcode" + }, + "mload": { + "v": 3, + "d": "Base fee of the MLOAD opcode" + }, + "mstore": { + "v": 3, + "d": "Base fee of the MSTORE opcode" + }, + "mstore8": { + "v": 3, + "d": "Base fee of the MSTORE8 opcode" + }, + "sstore": { + "v": 0, + "d": "Base fee of the SSTORE opcode" + }, + "jump": { + "v": 8, + "d": "Base fee of the JUMP opcode" + }, + "jumpi": { + "v": 10, + "d": "Base fee of the JUMPI opcode" + }, + "pc": { + "v": 2, + "d": "Base fee of the PC opcode" + }, + "msize": { + "v": 2, + "d": "Base fee of the MSIZE opcode" + }, + "gas": { + "v": 2, + "d": "Base fee of the GAS opcode" + }, + "push": { + "v": 3, + "d": "Base fee of the PUSH opcode" + }, + "dup": { + "v": 3, + "d": "Base fee of the DUP opcode" + }, + "swap": { + "v": 3, + "d": "Base fee of the SWAP opcode" + }, + "callcode": { + "v": 40, + "d": "Base fee of the CALLCODE opcode" + }, + "return": { + "v": 0, + "d": "Base fee of the RETURN opcode" + }, + "invalid": { + "v": 0, + "d": "Base fee of the INVALID opcode" + }, + "selfdestruct": { + "v": 0, + "d": "Base fee of the SELFDESTRUCT opcode" + } + }, + "vm": { + "stackLimit": { + "v": 1024, + "d": "Maximum size of VM stack allowed" + }, + "callCreateDepth": { + "v": 1024, + "d": "Maximum depth of call/create stack" + }, + "maxExtraDataSize": { + "v": 32, + "d": "Maximum size extra data may be after Genesis" + } + }, + "pow": { + "minimumDifficulty": { + "v": 131072, + "d": "The minimum that the difficulty may ever be" + }, + "difficultyBoundDivisor": { + "v": 2048, + "d": "The bound divisor of the difficulty, used in the update calculations" + }, + "durationLimit": { + "v": 13, + "d": "The decision boundary on the blocktime duration used to determine whether difficulty should go up or not" + }, + "epochDuration": { + "v": 30000, + "d": "Duration between proof-of-work epochs" + }, + "timebombPeriod": { + "v": 100000, + "d": "Exponential difficulty timebomb period" + }, + "minerReward": { + "v": "5000000000000000000", + "d": "the amount a miner get rewarded for mining a block" + }, + "difficultyBombDelay": { + "v": 0, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/constantinople.json b/packages/web3-eth-accounts/src/common/hardforks/constantinople.json new file mode 100644 index 00000000000..bb4ca964728 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/constantinople.json @@ -0,0 +1,68 @@ +{ + "name": "constantinople", + "comment": "Postponed hardfork including EIP-1283 (SSTORE gas metering changes)", + "url": "https://eips.ethereum.org/EIPS/eip-1013", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "netSstoreNoopGas": { + "v": 200, + "d": "Once per SSTORE operation if the value doesn't change" + }, + "netSstoreInitGas": { + "v": 20000, + "d": "Once per SSTORE operation from clean zero" + }, + "netSstoreCleanGas": { + "v": 5000, + "d": "Once per SSTORE operation from clean non-zero" + }, + "netSstoreDirtyGas": { + "v": 200, + "d": "Once per SSTORE operation from dirty" + }, + "netSstoreClearRefund": { + "v": 15000, + "d": "Once per SSTORE operation for clearing an originally existing storage slot" + }, + "netSstoreResetRefund": { + "v": 4800, + "d": "Once per SSTORE operation for resetting to the original non-zero value" + }, + "netSstoreResetClearRefund": { + "v": 19800, + "d": "Once per SSTORE operation for resetting to the original zero value" + }, + "shl": { + "v": 3, + "d": "Base fee of the SHL opcode" + }, + "shr": { + "v": 3, + "d": "Base fee of the SHR opcode" + }, + "sar": { + "v": 3, + "d": "Base fee of the SAR opcode" + }, + "extcodehash": { + "v": 400, + "d": "Base fee of the EXTCODEHASH opcode" + }, + "create2": { + "v": 32000, + "d": "Base fee of the CREATE2 opcode" + } + }, + "vm": {}, + "pow": { + "minerReward": { + "v": "2000000000000000000", + "d": "The amount a miner gets rewarded for mining a block" + }, + "difficultyBombDelay": { + "v": 5000000, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/dao.json b/packages/web3-eth-accounts/src/common/hardforks/dao.json new file mode 100644 index 00000000000..6558fce0662 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/dao.json @@ -0,0 +1,10 @@ +{ + "name": "dao", + "comment": "DAO rescue hardfork", + "url": "https://eips.ethereum.org/EIPS/eip-779", + "status": "Final", + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/grayGlacier.json b/packages/web3-eth-accounts/src/common/hardforks/grayGlacier.json new file mode 100644 index 00000000000..778b1b9860e --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/grayGlacier.json @@ -0,0 +1,11 @@ +{ + "name": "grayGlacier", + "comment": "Delaying the difficulty bomb to Mid September 2022", + "url": "https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/gray-glacier.md", + "status": "Draft", + "eips": [5133], + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/homestead.json b/packages/web3-eth-accounts/src/common/hardforks/homestead.json new file mode 100644 index 00000000000..20e5403cfd0 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/homestead.json @@ -0,0 +1,15 @@ +{ + "name": "homestead", + "comment": "Homestead hardfork with protocol and network changes", + "url": "https://eips.ethereum.org/EIPS/eip-606", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "delegatecall": { + "v": 40, + "d": "Base fee of the DELEGATECALL opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/index.ts b/packages/web3-eth-accounts/src/common/hardforks/index.ts new file mode 100644 index 00000000000..3e60dc742e1 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/index.ts @@ -0,0 +1,53 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import chainstart from './chainstart.json'; +import dao from './dao.json'; +import homestead from './homestead.json'; +import tangerineWhistle from './tangerineWhistle.json'; +import spuriousDragon from './spuriousDragon.json'; +import byzantium from './byzantium.json'; +import constantinople from './constantinople.json'; +import petersburg from './petersburg.json'; +import istanbul from './istanbul.json'; +import muirGlacier from './muirGlacier.json'; +import berlin from './berlin.json'; +import london from './london.json'; +import shanghai from './shanghai.json'; +import arrowGlacier from './arrowGlacier.json'; +import grayGlacier from './grayGlacier.json'; +import mergeForkIdTransition from './mergeForkIdTransition.json'; +import merge from './merge.json'; + +export const hardforks: { [key: string]: any } = { + chainstart, + homestead, + dao, + tangerineWhistle, + spuriousDragon, + byzantium, + constantinople, + petersburg, + istanbul, + muirGlacier, + berlin, + london, + shanghai, + arrowGlacier, + grayGlacier, + mergeForkIdTransition, + merge, +}; diff --git a/packages/web3-eth-accounts/src/common/hardforks/istanbul.json b/packages/web3-eth-accounts/src/common/hardforks/istanbul.json new file mode 100644 index 00000000000..41696b11487 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/istanbul.json @@ -0,0 +1,87 @@ +{ + "name": "istanbul", + "comment": "HF targeted for December 2019 following the Constantinople/Petersburg HF", + "url": "https://eips.ethereum.org/EIPS/eip-1679", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "blake2Round": { + "v": 1, + "d": "Gas cost per round for the Blake2 F precompile" + }, + "ecAdd": { + "v": 150, + "d": "Gas costs for curve addition precompile" + }, + "ecMul": { + "v": 6000, + "d": "Gas costs for curve multiplication precompile" + }, + "ecPairing": { + "v": 45000, + "d": "Base gas costs for curve pairing precompile" + }, + "ecPairingWord": { + "v": 34000, + "d": "Gas costs regarding curve pairing precompile input length" + }, + "txDataNonZero": { + "v": 16, + "d": "Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions" + }, + "sstoreSentryGasEIP2200": { + "v": 2300, + "d": "Minimum gas required to be present for an SSTORE call, not consumed" + }, + "sstoreNoopGasEIP2200": { + "v": 800, + "d": "Once per SSTORE operation if the value doesn't change" + }, + "sstoreDirtyGasEIP2200": { + "v": 800, + "d": "Once per SSTORE operation if a dirty value is changed" + }, + "sstoreInitGasEIP2200": { + "v": 20000, + "d": "Once per SSTORE operation from clean zero to non-zero" + }, + "sstoreInitRefundEIP2200": { + "v": 19200, + "d": "Once per SSTORE operation for resetting to the original zero value" + }, + "sstoreCleanGasEIP2200": { + "v": 5000, + "d": "Once per SSTORE operation from clean non-zero to something else" + }, + "sstoreCleanRefundEIP2200": { + "v": 4200, + "d": "Once per SSTORE operation for resetting to the original non-zero value" + }, + "sstoreClearRefundEIP2200": { + "v": 15000, + "d": "Once per SSTORE operation for clearing an originally existing storage slot" + }, + "balance": { + "v": 700, + "d": "Base fee of the BALANCE opcode" + }, + "extcodehash": { + "v": 700, + "d": "Base fee of the EXTCODEHASH opcode" + }, + "chainid": { + "v": 2, + "d": "Base fee of the CHAINID opcode" + }, + "selfbalance": { + "v": 5, + "d": "Base fee of the SELFBALANCE opcode" + }, + "sload": { + "v": 800, + "d": "Base fee of the SLOAD opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/london.json b/packages/web3-eth-accounts/src/common/hardforks/london.json new file mode 100644 index 00000000000..6e11ad49526 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/london.json @@ -0,0 +1,7 @@ +{ + "name": "london", + "comment": "HF targeted for July 2021 following the Berlin fork", + "url": "https://github.com/ethereum/eth1.0-specs/blob/master/network-upgrades/mainnet-upgrades/london.md", + "status": "Final", + "eips": [1559, 3198, 3529, 3541] +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/merge.json b/packages/web3-eth-accounts/src/common/hardforks/merge.json new file mode 100644 index 00000000000..06c2eea8f06 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/merge.json @@ -0,0 +1,12 @@ +{ + "name": "merge", + "comment": "Hardfork to upgrade the consensus mechanism to Proof-of-Stake", + "url": "https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/merge.md", + "status": "Final", + "consensus": { + "type": "pos", + "algorithm": "casper", + "casper": {} + }, + "eips": [3675, 4399] +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/mergeForkIdTransition.json b/packages/web3-eth-accounts/src/common/hardforks/mergeForkIdTransition.json new file mode 100644 index 00000000000..50bf3269fe1 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/mergeForkIdTransition.json @@ -0,0 +1,7 @@ +{ + "name": "mergeForkIdTransition", + "comment": "Pre-merge hardfork to fork off non-upgraded clients", + "url": "https://eips.ethereum.org/EIPS/eip-3675", + "status": "Draft", + "eips": [] +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/muirGlacier.json b/packages/web3-eth-accounts/src/common/hardforks/muirGlacier.json new file mode 100644 index 00000000000..dbed924bfb4 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/muirGlacier.json @@ -0,0 +1,15 @@ +{ + "name": "muirGlacier", + "comment": "HF to delay the difficulty bomb", + "url": "https://eips.ethereum.org/EIPS/eip-2384", + "status": "Final", + "gasConfig": {}, + "gasPrices": {}, + "vm": {}, + "pow": { + "difficultyBombDelay": { + "v": 9000000, + "d": "the amount of blocks to delay the difficulty bomb with" + } + } +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/petersburg.json b/packages/web3-eth-accounts/src/common/hardforks/petersburg.json new file mode 100644 index 00000000000..105b3697f13 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/petersburg.json @@ -0,0 +1,39 @@ +{ + "name": "petersburg", + "comment": "Aka constantinopleFix, removes EIP-1283, activate together with or after constantinople", + "url": "https://eips.ethereum.org/EIPS/eip-1716", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "netSstoreNoopGas": { + "v": null, + "d": "Removed along EIP-1283" + }, + "netSstoreInitGas": { + "v": null, + "d": "Removed along EIP-1283" + }, + "netSstoreCleanGas": { + "v": null, + "d": "Removed along EIP-1283" + }, + "netSstoreDirtyGas": { + "v": null, + "d": "Removed along EIP-1283" + }, + "netSstoreClearRefund": { + "v": null, + "d": "Removed along EIP-1283" + }, + "netSstoreResetRefund": { + "v": null, + "d": "Removed along EIP-1283" + }, + "netSstoreResetClearRefund": { + "v": null, + "d": "Removed along EIP-1283" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/shanghai.json b/packages/web3-eth-accounts/src/common/hardforks/shanghai.json new file mode 100644 index 00000000000..f14dd289fed --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/shanghai.json @@ -0,0 +1,7 @@ +{ + "name": "shanghai", + "comment": "Next feature hardfork after the merge hardfork having withdrawals, warm coinbase, push0, limit/meter initcode", + "url": "https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md", + "status": "Final", + "eips": [3651, 3855, 3860, 4895] +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/sharding.json b/packages/web3-eth-accounts/src/common/hardforks/sharding.json new file mode 100644 index 00000000000..f6ff72e7a3b --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/sharding.json @@ -0,0 +1,7 @@ +{ + "name": "shardingFork", + "comment": "Internal hardfork to test proto-danksharding (do not use in production)", + "url": "https://eips.ethereum.org/EIPS/eip-4844", + "status": "Experimental", + "eips": [4844] +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/spuriousDragon.json b/packages/web3-eth-accounts/src/common/hardforks/spuriousDragon.json new file mode 100644 index 00000000000..bfbf53e0031 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/spuriousDragon.json @@ -0,0 +1,20 @@ +{ + "name": "spuriousDragon", + "comment": "HF with EIPs for simple replay attack protection, EXP cost increase, state trie clearing, contract code size limit", + "url": "https://eips.ethereum.org/EIPS/eip-607", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "expByte": { + "v": 50, + "d": "Times ceil(log256(exponent)) for the EXP instruction" + } + }, + "vm": { + "maxCodeSize": { + "v": 24576, + "d": "Maximum length of contract code" + } + }, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/hardforks/tangerineWhistle.json b/packages/web3-eth-accounts/src/common/hardforks/tangerineWhistle.json new file mode 100644 index 00000000000..08fc65d6fff --- /dev/null +++ b/packages/web3-eth-accounts/src/common/hardforks/tangerineWhistle.json @@ -0,0 +1,43 @@ +{ + "name": "tangerineWhistle", + "comment": "Hardfork with gas cost changes for IO-heavy operations", + "url": "https://eips.ethereum.org/EIPS/eip-608", + "status": "Final", + "gasConfig": {}, + "gasPrices": { + "sload": { + "v": 200, + "d": "Once per SLOAD operation" + }, + "call": { + "v": 700, + "d": "Once per CALL operation & message call transaction" + }, + "extcodesize": { + "v": 700, + "d": "Base fee of the EXTCODESIZE opcode" + }, + "extcodecopy": { + "v": 700, + "d": "Base fee of the EXTCODECOPY opcode" + }, + "balance": { + "v": 400, + "d": "Base fee of the BALANCE opcode" + }, + "delegatecall": { + "v": 700, + "d": "Base fee of the DELEGATECALL opcode" + }, + "callcode": { + "v": 700, + "d": "Base fee of the CALLCODE opcode" + }, + "selfdestruct": { + "v": 5000, + "d": "Base fee of the SELFDESTRUCT opcode" + } + }, + "vm": {}, + "pow": {} +} diff --git a/packages/web3-eth-accounts/src/common/index.ts b/packages/web3-eth-accounts/src/common/index.ts new file mode 100644 index 00000000000..577682d164a --- /dev/null +++ b/packages/web3-eth-accounts/src/common/index.ts @@ -0,0 +1,21 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +// @ethereumjs/common version 3.1.1 +export * from './common'; +export * from './enums'; +export * from './types'; +export * from './utils'; diff --git a/packages/web3-eth-accounts/src/common/types.ts b/packages/web3-eth-accounts/src/common/types.ts new file mode 100644 index 00000000000..4994e886bb0 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/types.ts @@ -0,0 +1,209 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import type { Chain, ConsensusAlgorithm, ConsensusType, Hardfork } from './enums'; + +export interface ChainName { + [chainId: string]: string; +} + +export type CliqueConfig = { + period: number; + epoch: number; +}; + +export type EthashConfig = Record; + +export type CasperConfig = Record; + +export interface GenesisBlockConfig { + timestamp?: string; + gasLimit: number; + difficulty: number; + nonce: string; + extraData: string; + baseFeePerGas?: string; +} + +export interface HardforkConfig { + name: Hardfork | string; + // eslint-disable-next-line @typescript-eslint/ban-types + block: number | null; // null is used for hardforks that should not be applied -- since `undefined` isn't a valid value in JSON + ttd?: bigint | string; + timestamp?: number | string; + // eslint-disable-next-line @typescript-eslint/ban-types + forkHash?: string | null; +} + +export interface BootstrapNodeConfig { + ip: string; + port: number | string; + network?: string; + chainId?: number; + id: string; + location: string; + comment: string; +} + +export interface ChainConfig { + name: string; + chainId: number | bigint; + networkId: number | bigint; + defaultHardfork?: string; + comment?: string; + url?: string; + genesis: GenesisBlockConfig; + hardforks: HardforkConfig[]; + bootstrapNodes?: BootstrapNodeConfig[]; + dnsNetworks?: string[]; + consensus: { + type: ConsensusType | string; + algorithm: ConsensusAlgorithm | string; + clique?: CliqueConfig; + ethash?: EthashConfig; + casper?: CasperConfig; + }; +} +export interface ChainsConfig { + [key: string]: ChainConfig | ChainName; +} + +interface BaseOpts { + /** + * String identifier ('byzantium') for hardfork or {@link Hardfork} enum. + * + * Default: Hardfork.London + */ + hardfork?: string | Hardfork; + /** + * Selected EIPs which can be activated, please use an array for instantiation + * (e.g. `eips: [ 2537, ]`) + * + * Currently supported: + * + * - [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) - BLS12-381 precompiles + */ + eips?: number[]; +} + +/** + * Options for instantiating a {@link Common} instance. + */ +export interface CommonOpts extends BaseOpts { + /** + * Chain name ('mainnet'), id (1), or {@link Chain} enum, + * either from a chain directly supported or a custom chain + * passed in via {@link CommonOpts.customChains}. + */ + chain: string | number | Chain | bigint | object; + /** + * Initialize (in addition to the supported chains) with the selected + * custom chains. Custom genesis state should be passed to the Blockchain class if used. + * + * Usage (directly with the respective chain initialization via the {@link CommonOpts.chain} option): + * + * ```javascript + * import myCustomChain1 from '[PATH_TO_MY_CHAINS]/myCustomChain1.json' + * const common = new Common({ chain: 'myCustomChain1', customChains: [ myCustomChain1 ]}) + * ``` + */ + customChains?: ChainConfig[]; +} + +/** + * Options to be used with the {@link Common.custom} static constructor. + */ +export interface CustomCommonOpts extends BaseOpts { + /** + * The name (`mainnet`), id (`1`), or {@link Chain} enum of + * a standard chain used to base the custom chain params on. + */ + baseChain?: string | number | Chain | bigint; +} + +export interface GethConfigOpts extends BaseOpts { + chain?: string; + genesisHash?: Buffer; + mergeForkIdPostMerge?: boolean; +} +/* + * A type that represents an object that has a `toBuffer()` method. + */ +export interface TransformableToBuffer { + toBuffer(): Buffer; + toArray?(): Uint8Array; +} + +/* + * A type that represents a `0x`-prefixed hex string. + */ +export type PrefixedHexString = string; + +/* + * A type that represents an input that can be converted to a Buffer. + */ +export type BufferLike = + | Buffer + | Uint8Array + | number[] + | number + | bigint + | TransformableToBuffer + | PrefixedHexString; + +/* + * A type that represents an input that can be converted to a BigInt. + */ +export type BigIntLike = bigint | PrefixedHexString | number | Buffer; + +/* + * A type that represents an object that has a `toArray()` method. + */ +export interface TransformableToArray { + toArray(): Uint8Array; + toBuffer?(): Buffer; +} + +export type NestedUint8Array = Array; +export type NestedBufferArray = Array; +/** + * Type output options + */ +export enum TypeOutput { + Number, + BigInt, + Buffer, + PrefixedHexString, +} + +export type TypeOutputReturnType = { + [TypeOutput.Number]: number; + [TypeOutput.BigInt]: bigint; + [TypeOutput.Buffer]: Buffer; + [TypeOutput.PrefixedHexString]: PrefixedHexString; +}; +export type ToBufferInputTypes = + | PrefixedHexString + | number + | bigint + | Buffer + | Uint8Array + | number[] + | TransformableToArray + | TransformableToBuffer + // eslint-disable-next-line @typescript-eslint/ban-types + | null + | undefined; diff --git a/packages/web3-eth-accounts/src/common/utils.ts b/packages/web3-eth-accounts/src/common/utils.ts new file mode 100644 index 00000000000..6b87225fb60 --- /dev/null +++ b/packages/web3-eth-accounts/src/common/utils.ts @@ -0,0 +1,619 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { isHexPrefixed, isHexString } from 'web3-validator'; +import { recoverPublicKey } from 'ethereum-cryptography/secp256k1'; +import { Hardfork } from './enums'; +import { + NestedBufferArray, + ToBufferInputTypes, + TypeOutput, + TypeOutputReturnType, + NestedUint8Array, +} from './types'; + +type ConfigHardfork = + // eslint-disable-next-line @typescript-eslint/ban-types + | { name: string; block: null; timestamp: number } + | { name: string; block: number; timestamp?: number }; + +/** + * Removes '0x' from a given `String` if present + * @param str the string value + * @returns the string without 0x prefix + */ +export const stripHexPrefix = (str: string): string => { + if (typeof str !== 'string') + throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`); + + return isHexPrefixed(str) ? str.slice(2) : str; +}; +/** + * Transforms Geth formatted nonce (i.e. hex string) to 8 byte 0x-prefixed string used internally + * @param nonce string parsed from the Geth genesis file + * @returns nonce as a 0x-prefixed 8 byte string + */ +function formatNonce(nonce: string): string { + if (!nonce || nonce === '0x0') { + return '0x0000000000000000'; + } + if (isHexPrefixed(nonce)) { + return `0x${stripHexPrefix(nonce).padStart(16, '0')}`; + } + return `0x${nonce.padStart(16, '0')}`; +} + +/** + * Converts a `Number` into a hex `String` + * @param {Number} i + * @return {String} + */ +const intToHex = function (i: number) { + if (!Number.isSafeInteger(i) || i < 0) { + throw new Error(`Received an invalid integer type: ${i}`); + } + return `0x${i.toString(16)}`; +}; + +/** + * Converts Geth genesis parameters to an EthereumJS compatible `CommonOpts` object + * @param json object representing the Geth genesis file + * @param optional mergeForkIdPostMerge which clarifies the placement of MergeForkIdTransition + * hardfork, which by default is post merge as with the merged eth networks but could also come + * before merge like in kiln genesis + * @returns genesis parameters in a `CommonOpts` compliant object + */ +function parseGethParams(json: any, mergeForkIdPostMerge = true) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { + name, + config, + difficulty, + mixHash, + gasLimit, + coinbase, + baseFeePerGas, + }: { + name: string; + config: any; + difficulty: string; + mixHash: string; + gasLimit: string; + coinbase: string; + baseFeePerGas: string; + } = json; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + let { extraData, timestamp, nonce }: { extraData: string; timestamp: string; nonce: string } = + json; + const genesisTimestamp = Number(timestamp); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { chainId }: { chainId: number } = config; + + // geth is not strictly putting empty fields with a 0x prefix + if (extraData === '') { + extraData = '0x'; + } + // geth may use number for timestamp + if (!isHexPrefixed(timestamp)) { + // eslint-disable-next-line radix + timestamp = intToHex(parseInt(timestamp)); + } + // geth may not give us a nonce strictly formatted to an 8 byte hex string + if (nonce.length !== 18) { + nonce = formatNonce(nonce); + } + + // EIP155 and EIP158 are both part of Spurious Dragon hardfork and must occur at the same time + // but have different configuration parameters in geth genesis parameters + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (config.eip155Block !== config.eip158Block) { + throw new Error( + 'EIP155 block number must equal EIP 158 block number since both are part of SpuriousDragon hardfork and the client only supports activating the full hardfork', + ); + } + + const params = { + name, + chainId, + networkId: chainId, + genesis: { + timestamp, + // eslint-disable-next-line radix + gasLimit: parseInt(gasLimit), // geth gasLimit and difficulty are hex strings while ours are `number`s + // eslint-disable-next-line radix + difficulty: parseInt(difficulty), + nonce, + extraData, + mixHash, + coinbase, + baseFeePerGas, + }, + hardfork: undefined as string | undefined, + hardforks: [] as ConfigHardfork[], + bootstrapNodes: [], + consensus: + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + config.clique !== undefined + ? { + type: 'poa', + algorithm: 'clique', + clique: { + // The recent geth genesis seems to be using blockperiodseconds + // and epochlength for clique specification + // see: https://hackmd.io/PqZgMpnkSWCWv5joJoFymQ + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + period: config.clique.period ?? config.clique.blockperiodseconds, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + epoch: config.clique.epoch ?? config.clique.epochlength, + }, + } + : { + type: 'pow', + algorithm: 'ethash', + ethash: {}, + }, + }; + + const forkMap: { [key: string]: { name: string; postMerge?: boolean; isTimestamp?: boolean } } = + { + [Hardfork.Homestead]: { name: 'homesteadBlock' }, + [Hardfork.Dao]: { name: 'daoForkBlock' }, + [Hardfork.TangerineWhistle]: { name: 'eip150Block' }, + [Hardfork.SpuriousDragon]: { name: 'eip155Block' }, + [Hardfork.Byzantium]: { name: 'byzantiumBlock' }, + [Hardfork.Constantinople]: { name: 'constantinopleBlock' }, + [Hardfork.Petersburg]: { name: 'petersburgBlock' }, + [Hardfork.Istanbul]: { name: 'istanbulBlock' }, + [Hardfork.MuirGlacier]: { name: 'muirGlacierBlock' }, + [Hardfork.Berlin]: { name: 'berlinBlock' }, + [Hardfork.London]: { name: 'londonBlock' }, + [Hardfork.MergeForkIdTransition]: { + name: 'mergeForkBlock', + postMerge: mergeForkIdPostMerge, + }, + [Hardfork.Shanghai]: { name: 'shanghaiTime', postMerge: true, isTimestamp: true }, + [Hardfork.ShardingForkDev]: { + name: 'shardingForkTime', + postMerge: true, + isTimestamp: true, + }, + }; + + // forkMapRev is the map from config field name to Hardfork + const forkMapRev = Object.keys(forkMap).reduce<{ [key: string]: string }>((acc, elem) => { + acc[forkMap[elem].name] = elem; + return acc; + }, {}); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const configHardforkNames = Object.keys(config).filter( + // eslint-disable-next-line no-null/no-null, @typescript-eslint/no-unsafe-member-access + key => forkMapRev[key] !== undefined && config[key] !== undefined && config[key] !== null, + ); + + params.hardforks = configHardforkNames + .map(nameBlock => ({ + name: forkMapRev[nameBlock], + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + block: + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + forkMap[forkMapRev[nameBlock]].isTimestamp === true || + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + typeof config[nameBlock] !== 'number' + ? // eslint-disable-next-line no-null/no-null + null + : // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + config[nameBlock], + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + timestamp: + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + forkMap[forkMapRev[nameBlock]].isTimestamp === true && + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + typeof config[nameBlock] === 'number' + ? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + config[nameBlock] + : undefined, + })) + // eslint-disable-next-line no-null/no-null + .filter(fork => fork.block !== null || fork.timestamp !== undefined) as ConfigHardfork[]; + + params.hardforks.sort( + (a: ConfigHardfork, b: ConfigHardfork) => (a.block ?? Infinity) - (b.block ?? Infinity), + ); + + params.hardforks.sort( + (a: ConfigHardfork, b: ConfigHardfork) => + (a.timestamp ?? genesisTimestamp) - (b.timestamp ?? genesisTimestamp), + ); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (config.terminalTotalDifficulty !== undefined) { + // Following points need to be considered for placement of merge hf + // - Merge hardfork can't be placed at genesis + // - Place merge hf before any hardforks that require CL participation for e.g. withdrawals + // - Merge hardfork has to be placed just after genesis if any of the genesis hardforks make CL + // necessary for e.g. withdrawals + const mergeConfig = { + name: Hardfork.Merge, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + ttd: config.terminalTotalDifficulty, + // eslint-disable-next-line no-null/no-null + block: null, + }; + + // Merge hardfork has to be placed before first hardfork that is dependent on merge + const postMergeIndex = params.hardforks.findIndex( + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + (hf: any) => forkMap[hf.name]?.postMerge === true, + ); + if (postMergeIndex !== -1) { + params.hardforks.splice(postMergeIndex, 0, mergeConfig as unknown as ConfigHardfork); + } else { + params.hardforks.push(mergeConfig as unknown as ConfigHardfork); + } + } + + const latestHardfork = params.hardforks.length > 0 ? params.hardforks.slice(-1)[0] : undefined; + params.hardfork = latestHardfork?.name; + params.hardforks.unshift({ name: Hardfork.Chainstart, block: 0 }); + + return params; +} + +/** + * Parses a genesis.json exported from Geth into parameters for Common instance + * @param json representing the Geth genesis file + * @param name optional chain name + * @returns parsed params + */ +export function parseGethGenesis(json: any, name?: string, mergeForkIdPostMerge?: boolean) { + try { + if (['config', 'difficulty', 'gasLimit', 'alloc'].some(field => !(field in json))) { + throw new Error('Invalid format, expected geth genesis fields missing'); + } + if (name !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-param-reassign + json.name = name; + } + return parseGethParams(json, mergeForkIdPostMerge); + } catch (e: any) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions + throw new Error(`Error parsing parameters file: ${e.message}`); + } +} + +/** + * Pads a `String` to have an even length + * @param value + * @return output + */ +export function padToEven(value: string): string { + let a = value; + + if (typeof a !== 'string') { + throw new Error(`[padToEven] value must be type 'string', received ${typeof a}`); + } + + if (a.length % 2) a = `0${a}`; + + return a; +} + +/** + * Converts an `Number` to a `Buffer` + * @param {Number} i + * @return {Buffer} + */ +export const intToBuffer = function (i: number) { + const hex = intToHex(i); + return Buffer.from(padToEven(hex.slice(2)), 'hex'); +}; + +/** + * Attempts to turn a value into a `Buffer`. + * Inputs supported: `Buffer`, `String` (hex-prefixed), `Number`, null/undefined, `BigInt` and other objects + * with a `toArray()` or `toBuffer()` method. + * @param v the value + */ +export const toBuffer = function (v: ToBufferInputTypes): Buffer { + // eslint-disable-next-line no-null/no-null + if (v === null || v === undefined) { + return Buffer.allocUnsafe(0); + } + + if (Buffer.isBuffer(v)) { + return Buffer.from(v); + } + + if (Array.isArray(v) || v instanceof Uint8Array) { + return Buffer.from(v as Uint8Array); + } + + if (typeof v === 'string') { + if (!isHexString(v)) { + throw new Error( + `Cannot convert string to buffer. toBuffer only supports 0x-prefixed hex strings and this string was given: ${v}`, + ); + } + return Buffer.from(padToEven(stripHexPrefix(v)), 'hex'); + } + + if (typeof v === 'number') { + return intToBuffer(v); + } + + if (typeof v === 'bigint') { + if (v < BigInt(0)) { + throw new Error(`Cannot convert negative bigint to buffer. Given: ${v}`); + } + let n = v.toString(16); + if (n.length % 2) n = `0${n}`; + return Buffer.from(n, 'hex'); + } + + if (v.toArray) { + // converts a BN to a Buffer + return Buffer.from(v.toArray()); + } + + if (v.toBuffer) { + return Buffer.from(v.toBuffer()); + } + + throw new Error('invalid type'); +}; + +/** + * Converts a `Buffer` into a `0x`-prefixed hex `String`. + * @param buf `Buffer` object to convert + */ +export const bufferToHex = function (_buf: Buffer): string { + const buf = toBuffer(_buf); + return `0x${buf.toString('hex')}`; +}; + +/** + * Converts a {@link Buffer} to a {@link bigint} + */ +export function bufferToBigInt(buf: Buffer) { + const hex = bufferToHex(buf); + if (hex === '0x') { + return BigInt(0); + } + return BigInt(hex); +} + +/** + * Converts a {@link bigint} to a {@link Buffer} + */ +export function bigIntToBuffer(num: bigint) { + return toBuffer(`0x${num.toString(16)}`); +} + +/** + * Returns a buffer filled with 0s. + * @param bytes the number of bytes the buffer should be + */ +export const zeros = function (bytes: number): Buffer { + return Buffer.allocUnsafe(bytes).fill(0); +}; + +/** + * Pads a `Buffer` with zeros till it has `length` bytes. + * Truncates the beginning or end of input if its length exceeds `length`. + * @param msg the value to pad (Buffer) + * @param length the number of bytes the output should be + * @param right whether to start padding form the left or right + * @return (Buffer) + */ +const setLength = function (msg: Buffer, length: number, right: boolean) { + const buf = zeros(length); + if (right) { + if (msg.length < length) { + msg.copy(buf); + return buf; + } + return msg.subarray(0, length); + } + if (msg.length < length) { + msg.copy(buf, length - msg.length); + return buf; + } + return msg.subarray(-length); +}; + +/** + * Throws if input is not a buffer + * @param {Buffer} input value to check + */ +export const assertIsBuffer = function (input: Buffer): void { + if (!Buffer.isBuffer(input)) { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + const msg = `This method only supports Buffer but input was: ${input}`; + throw new Error(msg); + } +}; +/** + * Left Pads a `Buffer` with leading zeros till it has `length` bytes. + * Or it truncates the beginning if it exceeds. + * @param msg the value to pad (Buffer) + * @param length the number of bytes the output should be + * @return (Buffer) + */ +export const setLengthLeft = function (msg: Buffer, length: number) { + assertIsBuffer(msg); + return setLength(msg, length, false); +}; + +/** + * Trims leading zeros from a `Buffer`, `String` or `Number[]`. + * @param a (Buffer|Array|String) + * @return (Buffer|Array|String) + */ +const stripZeros = function (a: any): Buffer | number[] | string { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment + let first = a[0]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call + while (a.length > 0 && first.toString() === '0') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, prefer-destructuring, @typescript-eslint/no-unsafe-call, no-param-reassign + a = a.slice(1); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, prefer-destructuring, @typescript-eslint/no-unsafe-member-access + first = a[0]; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return a; +}; + +/** + * Trims leading zeros from a `Buffer`. + * @param a (Buffer) + * @return (Buffer) + */ +export const unpadBuffer = function (a: Buffer): Buffer { + assertIsBuffer(a); + return stripZeros(a) as Buffer; +}; + +/** + * Converts a {@link Uint8Array} or {@link NestedUint8Array} to {@link Buffer} or {@link NestedBufferArray} + */ +export function arrToBufArr(arr: Uint8Array): Buffer; +export function arrToBufArr(arr: NestedUint8Array): NestedBufferArray; +export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | NestedBufferArray; +export function arrToBufArr(arr: Uint8Array | NestedUint8Array): Buffer | NestedBufferArray { + if (!Array.isArray(arr)) { + return Buffer.from(arr); + } + return arr.map(a => arrToBufArr(a)); +} + +/** + * Converts a {@link bigint} to a `0x` prefixed hex string + */ +export const bigIntToHex = (num: bigint) => `0x${num.toString(16)}`; + +/** + * Convert value from bigint to an unpadded Buffer + * (useful for RLP transport) + * @param value value to convert + */ +export function bigIntToUnpaddedBuffer(value: bigint): Buffer { + return unpadBuffer(bigIntToBuffer(value)); +} + +/** + * Converts a {@link Buffer} or {@link NestedBufferArray} to {@link Uint8Array} or {@link NestedUint8Array} + */ +export function bufArrToArr(arr: Buffer): Uint8Array; +export function bufArrToArr(arr: NestedBufferArray): NestedUint8Array; +export function bufArrToArr(arr: Buffer | NestedBufferArray): Uint8Array | NestedUint8Array; +export function bufArrToArr(arr: Buffer | NestedBufferArray): Uint8Array | NestedUint8Array { + if (!Array.isArray(arr)) { + return Uint8Array.from(arr ?? []); + } + return arr.map(a => bufArrToArr(a)); +} + +function calculateSigRecovery(v: bigint, chainId?: bigint): bigint { + if (v === BigInt(0) || v === BigInt(1)) return v; + + if (chainId === undefined) { + return v - BigInt(27); + } + return v - (chainId * BigInt(2) + BigInt(35)); +} + +function isValidSigRecovery(recovery: bigint): boolean { + return recovery === BigInt(0) || recovery === BigInt(1); +} + +/** + * ECDSA public key recovery from signature. + * NOTE: Accepts `v === 0 | v === 1` for EIP1559 transactions + * @returns Recovered public key + */ +export const ecrecover = function ( + msgHash: Buffer, + v: bigint, + r: Buffer, + s: Buffer, + chainId?: bigint, +): Buffer { + const signature = Buffer.concat([setLengthLeft(r, 32), setLengthLeft(s, 32)], 64); + const recovery = calculateSigRecovery(v, chainId); + if (!isValidSigRecovery(recovery)) { + throw new Error('Invalid signature v value'); + } + + const senderPubKey = recoverPublicKey(msgHash, signature, Number(recovery)); + return Buffer.from(senderPubKey.slice(1)); +}; + +/** + * Convert an input to a specified type. + * Input of null/undefined returns null/undefined regardless of the output type. + * @param input value to convert + * @param outputType type to output + */ +// eslint-disable-next-line @typescript-eslint/ban-types +export function toType(input: null, outputType: T): null; +export function toType(input: undefined, outputType: T): undefined; +export function toType( + input: ToBufferInputTypes, + outputType: T, +): TypeOutputReturnType[T]; +export function toType( + input: ToBufferInputTypes, + outputType: T, + // eslint-disable-next-line @typescript-eslint/ban-types +): TypeOutputReturnType[T] | undefined | null { + // eslint-disable-next-line no-null/no-null + if (input === null) { + // eslint-disable-next-line no-null/no-null + return null; + } + if (input === undefined) { + return undefined; + } + + if (typeof input === 'string' && !isHexString(input)) { + throw new Error(`A string must be provided with a 0x-prefix, given: ${input}`); + } else if (typeof input === 'number' && !Number.isSafeInteger(input)) { + throw new Error( + 'The provided number is greater than MAX_SAFE_INTEGER (please use an alternative input type)', + ); + } + + const output = toBuffer(input); + + switch (outputType) { + case TypeOutput.Buffer: + return output as TypeOutputReturnType[T]; + case TypeOutput.BigInt: + return bufferToBigInt(output) as TypeOutputReturnType[T]; + case TypeOutput.Number: { + const bigInt = bufferToBigInt(output); + if (bigInt > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error( + 'The provided number is greater than MAX_SAFE_INTEGER (please use an alternative output type)', + ); + } + return Number(bigInt) as TypeOutputReturnType[T]; + } + case TypeOutput.PrefixedHexString: + return bufferToHex(output) as TypeOutputReturnType[T]; + default: + throw new Error('unknown outputType'); + } +} diff --git a/packages/web3-eth-accounts/src/index.ts b/packages/web3-eth-accounts/src/index.ts index 70589073e02..8f4a57b8575 100644 --- a/packages/web3-eth-accounts/src/index.ts +++ b/packages/web3-eth-accounts/src/index.ts @@ -41,3 +41,5 @@ export * from './wallet'; export * from './account'; export * from './types'; export * from './schemas'; +export * from './common'; +export * from './tx'; diff --git a/packages/web3-eth-accounts/src/tx/address.ts b/packages/web3-eth-accounts/src/tx/address.ts new file mode 100644 index 00000000000..b697e30adf3 --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/address.ts @@ -0,0 +1,85 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Point } from 'ethereum-cryptography/secp256k1'; +import { keccak256 } from 'ethereum-cryptography/keccak'; +import { assertIsBuffer, zeros } from '../common/utils'; + +export class Address { + public readonly buf: Buffer; + + public constructor(buf: Buffer) { + if (buf.length !== 20) { + throw new Error('Invalid address length'); + } + this.buf = buf; + } + + /** + * Returns the zero address. + */ + public static zero(): Address { + return new Address(zeros(20)); + } + + /** + * Is address equal to another. + */ + public equals(address: Address): boolean { + return this.buf.equals(address.buf); + } + + /** + * Is address zero. + */ + public isZero(): boolean { + return this.equals(Address.zero()); + } + + /** + * Returns hex encoding of address. + */ + public toString(): string { + return `0x${this.buf.toString('hex')}`; + } + + /** + * Returns Buffer representation of address. + */ + public toBuffer(): Buffer { + return Buffer.from(this.buf); + } + + /** + * Returns the ethereum address of a given public key. + * Accepts "Ethereum public keys" and SEC1 encoded keys. + * @param pubKey The two points of an uncompressed key, unless sanitize is enabled + * @param sanitize Accept public keys in other formats + */ + public static publicToAddress(_pubKey: Buffer, sanitize = false): Buffer { + let pubKey = _pubKey; + assertIsBuffer(pubKey); + if (sanitize && pubKey.length !== 64) { + pubKey = Buffer.from(Point.fromHex(pubKey).toRawBytes(false).slice(1)); + } + if (pubKey.length !== 64) { + throw new Error('Expected pubKey to be of length 64'); + } + // Only take the lower 160bits of the hash + // eslint-disable-next-line deprecation/deprecation + return Buffer.from(keccak256(pubKey)).slice(-20); + } +} diff --git a/packages/web3-eth-accounts/src/tx/baseTransaction.ts b/packages/web3-eth-accounts/src/tx/baseTransaction.ts new file mode 100644 index 00000000000..3edcdc9683b --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/baseTransaction.ts @@ -0,0 +1,567 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { Numbers } from 'web3-types'; +import { signSync } from 'ethereum-cryptography/secp256k1'; +import { MAX_INTEGER, MAX_UINT64, SECP256K1_ORDER_DIV_2 } from './constants'; +import { + Chain, + Common, + Hardfork, + bufferToBigInt, + bufferToHex, + toBuffer, + unpadBuffer, +} from '../common'; +import type { + AccessListEIP2930TxData, + AccessListEIP2930ValuesArray, + FeeMarketEIP1559TxData, + FeeMarketEIP1559ValuesArray, + JsonTx, + TxData, + TxOptions, + TxValuesArray, +} from './types'; +import { Capability, ECDSASignature } from './types'; +import { Address } from './address'; +import { checkMaxInitCodeSize } from './utils'; + +interface TransactionCache { + hash: Buffer | undefined; + dataFee?: { + value: bigint; + hardfork: string | Hardfork; + }; +} + +/** + * This base class will likely be subject to further + * refactoring along the introduction of additional tx types + * on the Ethereum network. + * + * It is therefore not recommended to use directly. + */ +export abstract class BaseTransaction { + private readonly _type: number; + + public readonly nonce: bigint; + public readonly gasLimit: bigint; + public readonly to?: Address; + public readonly value: bigint; + public readonly data: Buffer; + + public readonly v?: bigint; + public readonly r?: bigint; + public readonly s?: bigint; + + public readonly common!: Common; + + protected cache: TransactionCache = { + hash: undefined, + dataFee: undefined, + }; + + protected readonly txOptions: TxOptions; + + /** + * List of tx type defining EIPs, + * e.g. 1559 (fee market) and 2930 (access lists) + * for FeeMarketEIP1559Transaction objects + */ + protected activeCapabilities: number[] = []; + + /** + * The default chain the tx falls back to if no Common + * is provided and if the chain can't be derived from + * a passed in chainId (only EIP-2718 typed txs) or + * EIP-155 signature (legacy txs). + * + * @hidden + */ + protected DEFAULT_CHAIN = Chain.Mainnet; + + /** + * The default HF if the tx type is active on that HF + * or the first greater HF where the tx is active. + * + * @hidden + */ + protected DEFAULT_HARDFORK: string | Hardfork = Hardfork.Merge; + + public constructor( + txData: TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData, + opts: TxOptions, + ) { + const { nonce, gasLimit, to, value, data, v, r, s, type } = txData; + this._type = Number(bufferToBigInt(toBuffer(type))); + + this.txOptions = opts; + + const toB = toBuffer(to === '' ? '0x' : to); + const vB = toBuffer(v === '' ? '0x' : v); + const rB = toBuffer(r === '' ? '0x' : r); + const sB = toBuffer(s === '' ? '0x' : s); + + this.nonce = bufferToBigInt(toBuffer(nonce === '' ? '0x' : nonce)); + this.gasLimit = bufferToBigInt(toBuffer(gasLimit === '' ? '0x' : gasLimit)); + this.to = toB.length > 0 ? new Address(toB) : undefined; + this.value = bufferToBigInt(toBuffer(value === '' ? '0x' : value)); + this.data = toBuffer(data === '' ? '0x' : data); + + this.v = vB.length > 0 ? bufferToBigInt(vB) : undefined; + this.r = rB.length > 0 ? bufferToBigInt(rB) : undefined; + this.s = sB.length > 0 ? bufferToBigInt(sB) : undefined; + + this._validateCannotExceedMaxInteger({ value: this.value, r: this.r, s: this.s }); + + // geth limits gasLimit to 2^64-1 + this._validateCannotExceedMaxInteger({ gasLimit: this.gasLimit }, 64); + + // EIP-2681 limits nonce to 2^64-1 (cannot equal 2^64-1) + this._validateCannotExceedMaxInteger({ nonce: this.nonce }, 64, true); + // eslint-disable-next-line no-null/no-null + const createContract = this.to === undefined || this.to === null; + const allowUnlimitedInitCodeSize = opts.allowUnlimitedInitCodeSize ?? false; + const common = opts.common ?? this._getCommon(); + if (createContract && common.isActivatedEIP(3860) && !allowUnlimitedInitCodeSize) { + checkMaxInitCodeSize(common, this.data.length); + } + } + + /** + * Returns the transaction type. + * + * Note: legacy txs will return tx type `0`. + */ + public get type() { + return this._type; + } + + /** + * Checks if a tx type defining capability is active + * on a tx, for example the EIP-1559 fee market mechanism + * or the EIP-2930 access list feature. + * + * Note that this is different from the tx type itself, + * so EIP-2930 access lists can very well be active + * on an EIP-1559 tx for example. + * + * This method can be useful for feature checks if the + * tx type is unknown (e.g. when instantiated with + * the tx factory). + * + * See `Capabilites` in the `types` module for a reference + * on all supported capabilities. + */ + public supports(capability: Capability) { + return this.activeCapabilities.includes(capability); + } + + /** + * Checks if the transaction has the minimum amount of gas required + * (DataFee + TxFee + Creation Fee). + */ + public validate(): boolean; + public validate(stringError: false): boolean; + public validate(stringError: true): string[]; + public validate(stringError = false): boolean | string[] { + const errors = []; + + if (this.getBaseFee() > this.gasLimit) { + errors.push( + `gasLimit is too low. given ${this.gasLimit}, need at least ${this.getBaseFee()}`, + ); + } + + if (this.isSigned() && !this.verifySignature()) { + errors.push('Invalid Signature'); + } + + return stringError ? errors : errors.length === 0; + } + + protected _validateYParity() { + const { v } = this; + if (v !== undefined && v !== BigInt(0) && v !== BigInt(1)) { + const msg = this._errorMsg('The y-parity of the transaction should either be 0 or 1'); + throw new Error(msg); + } + } + + /** + * EIP-2: All transaction signatures whose s-value is greater than secp256k1n/2are considered invalid. + * Reasoning: https://ethereum.stackexchange.com/a/55728 + */ + protected _validateHighS() { + const { s } = this; + if (this.common.gteHardfork('homestead') && s !== undefined && s > SECP256K1_ORDER_DIV_2) { + const msg = this._errorMsg( + 'Invalid Signature: s-values greater than secp256k1n/2 are considered invalid', + ); + throw new Error(msg); + } + } + + /** + * The minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee) + */ + public getBaseFee(): bigint { + const txFee = this.common.param('gasPrices', 'tx'); + let fee = this.getDataFee(); + if (txFee) fee += txFee; + if (this.common.gteHardfork('homestead') && this.toCreationAddress()) { + const txCreationFee = this.common.param('gasPrices', 'txCreation'); + if (txCreationFee) fee += txCreationFee; + } + return fee; + } + + /** + * The amount of gas paid for the data in this tx + */ + public getDataFee(): bigint { + const txDataZero = this.common.param('gasPrices', 'txDataZero'); + const txDataNonZero = this.common.param('gasPrices', 'txDataNonZero'); + + let cost = BigInt(0); + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < this.data.length; i += 1) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions, no-unused-expressions + this.data[i] === 0 ? (cost += txDataZero) : (cost += txDataNonZero); + } + // eslint-disable-next-line no-null/no-null + if ((this.to === undefined || this.to === null) && this.common.isActivatedEIP(3860)) { + const dataLength = BigInt(Math.ceil(this.data.length / 32)); + const initCodeCost = this.common.param('gasPrices', 'initCodeWordCost') * dataLength; + cost += initCodeCost; + } + + return cost; + } + + /** + * The up front amount that an account must have for this transaction to be valid + */ + public abstract getUpfrontCost(): bigint; + + /** + * If the tx's `to` is to the creation address + */ + public toCreationAddress(): boolean { + return this.to === undefined || this.to.buf.length === 0; + } + + /** + * Returns a Buffer Array of the raw Buffers of this transaction, in order. + * + * Use {@link BaseTransaction.serialize} to add a transaction to a block + * with {@link Block.fromValuesArray}. + * + * For an unsigned tx this method uses the empty Buffer values for the + * signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant + * representation for external signing use {@link BaseTransaction.getMessageToSign}. + */ + public abstract raw(): + | TxValuesArray + | AccessListEIP2930ValuesArray + | FeeMarketEIP1559ValuesArray; + + /** + * Returns the encoding of the transaction. + */ + public abstract serialize(): Buffer; + + // Returns the unsigned tx (hashed or raw), which is used to sign the transaction. + // + // Note: do not use code docs here since VS Studio is then not able to detect the + // comments from the inherited methods + public abstract getMessageToSign(hashMessage: false): Buffer | Buffer[]; + public abstract getMessageToSign(hashMessage?: true): Buffer; + + public abstract hash(): Buffer; + + public abstract getMessageToVerifySignature(): Buffer; + + public isSigned(): boolean { + const { v, r, s } = this; + if (v === undefined || r === undefined || s === undefined) { + return false; + } + return true; + } + + /** + * Determines if the signature is valid + */ + public verifySignature(): boolean { + try { + // Main signature verification is done in `getSenderPublicKey()` + const publicKey = this.getSenderPublicKey(); + return unpadBuffer(publicKey).length !== 0; + } catch (e: any) { + return false; + } + } + + /** + * Returns the sender's address + */ + public getSenderAddress(): Address { + return new Address(Address.publicToAddress(this.getSenderPublicKey())); + } + + /** + * Returns the public key of the sender + */ + public abstract getSenderPublicKey(): Buffer; + + /** + * Signs a transaction. + * + * Note that the signed tx is returned as a new object, + * use as follows: + * ```javascript + * const signedTx = tx.sign(privateKey) + * ``` + */ + public sign(privateKey: Buffer): TransactionObject { + if (privateKey.length !== 32) { + const msg = this._errorMsg('Private key must be 32 bytes in length.'); + throw new Error(msg); + } + + // Hack for the constellation that we have got a legacy tx after spuriousDragon with a non-EIP155 conforming signature + // and want to recreate a signature (where EIP155 should be applied) + // Leaving this hack lets the legacy.spec.ts -> sign(), verifySignature() test fail + // 2021-06-23 + let hackApplied = false; + if ( + this.type === 0 && + this.common.gteHardfork('spuriousDragon') && + !this.supports(Capability.EIP155ReplayProtection) + ) { + this.activeCapabilities.push(Capability.EIP155ReplayProtection); + hackApplied = true; + } + + const msgHash = this.getMessageToSign(true); + const { v, r, s } = this._ecsign(msgHash, privateKey); + const tx = this._processSignature(v, r, s); + + // Hack part 2 + if (hackApplied) { + const index = this.activeCapabilities.indexOf(Capability.EIP155ReplayProtection); + if (index > -1) { + this.activeCapabilities.splice(index, 1); + } + } + + return tx; + } + + /** + * Returns an object with the JSON representation of the transaction + */ + public abstract toJSON(): JsonTx; + + // Accept the v,r,s values from the `sign` method, and convert this into a TransactionObject + protected abstract _processSignature(v: bigint, r: Buffer, s: Buffer): TransactionObject; + + /** + * Does chain ID checks on common and returns a common + * to be used on instantiation + * @hidden + * + * @param common - {@link Common} instance from tx options + * @param chainId - Chain ID from tx options (typed txs) or signature (legacy tx) + */ + protected _getCommon(common?: Common, chainId?: Numbers) { + // Chain ID provided + if (chainId !== undefined) { + const chainIdBigInt = bufferToBigInt(toBuffer(chainId)); + if (common) { + if (common.chainId() !== chainIdBigInt) { + const msg = this._errorMsg( + 'The chain ID does not match the chain ID of Common', + ); + throw new Error(msg); + } + // Common provided, chain ID does match + // -> Return provided Common + return common.copy(); + } + if (Common.isSupportedChainId(chainIdBigInt)) { + // No Common, chain ID supported by Common + // -> Instantiate Common with chain ID + return new Common({ chain: chainIdBigInt, hardfork: this.DEFAULT_HARDFORK }); + } + // No Common, chain ID not supported by Common + // -> Instantiate custom Common derived from DEFAULT_CHAIN + return Common.custom( + { + name: 'custom-chain', + networkId: chainIdBigInt, + chainId: chainIdBigInt, + }, + { baseChain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK }, + ); + } + // No chain ID provided + // -> return Common provided or create new default Common + return ( + common?.copy() ?? + new Common({ chain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK }) + ); + } + + /** + * Validates that an object with BigInt values cannot exceed the specified bit limit. + * @param values Object containing string keys and BigInt values + * @param bits Number of bits to check (64 or 256) + * @param cannotEqual Pass true if the number also cannot equal one less the maximum value + */ + protected _validateCannotExceedMaxInteger( + values: { [key: string]: bigint | undefined }, + bits = 256, + cannotEqual = false, + ) { + for (const [key, value] of Object.entries(values)) { + switch (bits) { + case 64: + if (cannotEqual) { + if (value !== undefined && value >= MAX_UINT64) { + const msg = this._errorMsg( + `${key} cannot equal or exceed MAX_UINT64 (2^64-1), given ${value}`, + ); + throw new Error(msg); + } + } else if (value !== undefined && value > MAX_UINT64) { + const msg = this._errorMsg( + `${key} cannot exceed MAX_UINT64 (2^64-1), given ${value}`, + ); + throw new Error(msg); + } + break; + case 256: + if (cannotEqual) { + if (value !== undefined && value >= MAX_INTEGER) { + const msg = this._errorMsg( + `${key} cannot equal or exceed MAX_INTEGER (2^256-1), given ${value}`, + ); + throw new Error(msg); + } + } else if (value !== undefined && value > MAX_INTEGER) { + const msg = this._errorMsg( + `${key} cannot exceed MAX_INTEGER (2^256-1), given ${value}`, + ); + throw new Error(msg); + } + break; + default: { + const msg = this._errorMsg('unimplemented bits value'); + throw new Error(msg); + } + } + } + } + + protected static _validateNotArray(values: { [key: string]: any }) { + const txDataKeys = [ + 'nonce', + 'gasPrice', + 'gasLimit', + 'to', + 'value', + 'data', + 'v', + 'r', + 's', + 'type', + 'baseFee', + 'maxFeePerGas', + 'chainId', + ]; + for (const [key, value] of Object.entries(values)) { + if (txDataKeys.includes(key)) { + if (Array.isArray(value)) { + throw new Error(`${key} cannot be an array`); + } + } + } + } + + /** + * Return a compact error string representation of the object + */ + public abstract errorStr(): string; + + /** + * Internal helper function to create an annotated error message + * + * @param msg Base error message + * @hidden + */ + protected abstract _errorMsg(msg: string): string; + + /** + * Returns the shared error postfix part for _error() method + * tx type implementations. + */ + protected _getSharedErrorPostfix() { + let hash = ''; + try { + hash = this.isSigned() ? bufferToHex(this.hash()) : 'not available (unsigned)'; + } catch (e: any) { + hash = 'error'; + } + let isSigned = ''; + try { + isSigned = this.isSigned().toString(); + } catch (e: any) { + hash = 'error'; + } + let hf = ''; + try { + hf = this.common.hardfork(); + } catch (e: any) { + hf = 'error'; + } + + let postfix = `tx type=${this.type} hash=${hash} nonce=${this.nonce} value=${this.value} `; + postfix += `signed=${isSigned} hf=${hf}`; + + return postfix; + } + // eslint-disable-next-line class-methods-use-this + private _ecsign(msgHash: Buffer, privateKey: Buffer, chainId?: bigint): ECDSASignature { + const [signature, recovery] = signSync(msgHash, privateKey, { + recovered: true, + der: false, + }); + + const r = Buffer.from(signature.slice(0, 32)); + const s = Buffer.from(signature.slice(32, 64)); + + const v = + chainId === undefined + ? BigInt(recovery + 27) + : BigInt(recovery + 35) + BigInt(chainId) * BigInt(2); + + return { r, s, v }; + } +} diff --git a/packages/web3-eth-accounts/src/tx/constants.ts b/packages/web3-eth-accounts/src/tx/constants.ts new file mode 100644 index 00000000000..3a71e5fdf9d --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/constants.ts @@ -0,0 +1,32 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { CURVE } from 'ethereum-cryptography/secp256k1'; + +/** + * 2^64-1 + */ +export const MAX_UINT64 = BigInt('0xffffffffffffffff'); + +/** + * The max integer that the evm can handle (2^256-1) + */ +export const MAX_INTEGER = BigInt( + '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', +); + +export const SECP256K1_ORDER = CURVE.n; +export const SECP256K1_ORDER_DIV_2 = CURVE.n / BigInt(2); diff --git a/packages/web3-eth-accounts/src/tx/eip1559Transaction.ts b/packages/web3-eth-accounts/src/tx/eip1559Transaction.ts new file mode 100644 index 00000000000..5b04744930f --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/eip1559Transaction.ts @@ -0,0 +1,450 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { keccak256 } from 'ethereum-cryptography/keccak'; +import { validateNoLeadingZeroes } from 'web3-validator'; +import { RLP } from '@ethereumjs/rlp'; +import { MAX_INTEGER } from './constants'; +import { BaseTransaction } from './baseTransaction'; +import { getAccessListData, getAccessListJSON, getDataFeeEIP2930, verifyAccessList } from './utils'; +import { + arrToBufArr, + bigIntToHex, + bigIntToUnpaddedBuffer, + bufArrToArr, + bufferToBigInt, + toBuffer, + ecrecover, +} from '../common/utils'; +import type { + AccessList, + AccessListBuffer, + FeeMarketEIP1559TxData, + FeeMarketEIP1559ValuesArray, + JsonTx, + TxOptions, +} from './types'; +import type { Common } from '../common'; + +const TRANSACTION_TYPE = 2; +const TRANSACTION_TYPE_BUFFER = Buffer.from(TRANSACTION_TYPE.toString(16).padStart(2, '0'), 'hex'); + +/** + * Typed transaction with a new gas fee market mechanism + * + * - TransactionType: 2 + * - EIP: [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) + */ +// eslint-disable-next-line no-use-before-define +export class FeeMarketEIP1559Transaction extends BaseTransaction { + public readonly chainId: bigint; + public readonly accessList: AccessListBuffer; + public readonly AccessListJSON: AccessList; + public readonly maxPriorityFeePerGas: bigint; + public readonly maxFeePerGas: bigint; + + public readonly common: Common; + + /** + * The default HF if the tx type is active on that HF + * or the first greater HF where the tx is active. + * + * @hidden + */ + protected DEFAULT_HARDFORK = 'london'; + + /** + * Instantiate a transaction from a data dictionary. + * + * Format: { chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, + * accessList, v, r, s } + * + * Notes: + * - `chainId` will be set automatically if not provided + * - All parameters are optional and have some basic default values + */ + public static fromTxData(txData: FeeMarketEIP1559TxData, opts: TxOptions = {}) { + return new FeeMarketEIP1559Transaction(txData, opts); + } + + /** + * Instantiate a transaction from the serialized tx. + * + * Format: `0x02 || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, + * accessList, signatureYParity, signatureR, signatureS])` + */ + public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {}) { + if (!serialized.subarray(0, 1).equals(TRANSACTION_TYPE_BUFFER)) { + throw new Error( + `Invalid serialized tx input: not an EIP-1559 transaction (wrong tx type, expected: ${TRANSACTION_TYPE}, received: ${serialized + .subarray(0, 1) + .toString('hex')}`, + ); + } + const values = arrToBufArr(RLP.decode(serialized.subarray(1))); + + if (!Array.isArray(values)) { + throw new Error('Invalid serialized tx input: must be array'); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return FeeMarketEIP1559Transaction.fromValuesArray(values as any, opts); + } + + /** + * Create a transaction from a values array. + * + * Format: `[chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, + * accessList, signatureYParity, signatureR, signatureS]` + */ + public static fromValuesArray(values: FeeMarketEIP1559ValuesArray, opts: TxOptions = {}) { + if (values.length !== 9 && values.length !== 12) { + throw new Error( + 'Invalid EIP-1559 transaction. Only expecting 9 values (for unsigned tx) or 12 values (for signed tx).', + ); + } + + const [ + chainId, + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + to, + value, + data, + accessList, + v, + r, + s, + ] = values; + + this._validateNotArray({ chainId, v }); + validateNoLeadingZeroes({ + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + value, + v, + r, + s, + }); + + return new FeeMarketEIP1559Transaction( + { + chainId: bufferToBigInt(chainId), + nonce, + maxPriorityFeePerGas, + maxFeePerGas, + gasLimit, + to, + value, + data, + accessList: accessList ?? [], + v: v !== undefined ? bufferToBigInt(v) : undefined, // EIP2930 supports v's with value 0 (empty Buffer) + r, + s, + }, + opts, + ); + } + + /** + * This constructor takes the values, validates them, assigns them and freezes the object. + * + * It is not recommended to use this constructor directly. Instead use + * the static factory methods to assist in creating a Transaction object from + * varying data types. + */ + public constructor(txData: FeeMarketEIP1559TxData, opts: TxOptions = {}) { + super({ ...txData, type: TRANSACTION_TYPE }, opts); + const { chainId, accessList, maxFeePerGas, maxPriorityFeePerGas } = txData; + + this.common = this._getCommon(opts.common, chainId); + this.chainId = this.common.chainId(); + + if (!this.common.isActivatedEIP(1559)) { + throw new Error('EIP-1559 not enabled on Common'); + } + this.activeCapabilities = this.activeCapabilities.concat([1559, 2718, 2930]); + + // Populate the access list fields + const accessListData = getAccessListData(accessList ?? []); + this.accessList = accessListData.accessList; + this.AccessListJSON = accessListData.AccessListJSON; + // Verify the access list format. + verifyAccessList(this.accessList); + + this.maxFeePerGas = bufferToBigInt(toBuffer(maxFeePerGas === '' ? '0x' : maxFeePerGas)); + this.maxPriorityFeePerGas = bufferToBigInt( + toBuffer(maxPriorityFeePerGas === '' ? '0x' : maxPriorityFeePerGas), + ); + + this._validateCannotExceedMaxInteger({ + maxFeePerGas: this.maxFeePerGas, + maxPriorityFeePerGas: this.maxPriorityFeePerGas, + }); + + BaseTransaction._validateNotArray(txData); + + if (this.gasLimit * this.maxFeePerGas > MAX_INTEGER) { + const msg = this._errorMsg( + 'gasLimit * maxFeePerGas cannot exceed MAX_INTEGER (2^256-1)', + ); + throw new Error(msg); + } + + if (this.maxFeePerGas < this.maxPriorityFeePerGas) { + const msg = this._errorMsg( + 'maxFeePerGas cannot be less than maxPriorityFeePerGas (The total must be the larger of the two)', + ); + throw new Error(msg); + } + + this._validateYParity(); + this._validateHighS(); + + const freeze = opts?.freeze ?? true; + if (freeze) { + Object.freeze(this); + } + } + + /** + * The amount of gas paid for the data in this tx + */ + public getDataFee(): bigint { + if (this.cache.dataFee && this.cache.dataFee.hardfork === this.common.hardfork()) { + return this.cache.dataFee.value; + } + + let cost = super.getDataFee(); + cost += BigInt(getDataFeeEIP2930(this.accessList, this.common)); + + if (Object.isFrozen(this)) { + this.cache.dataFee = { + value: cost, + hardfork: this.common.hardfork(), + }; + } + + return cost; + } + + /** + * The up front amount that an account must have for this transaction to be valid + * @param baseFee The base fee of the block (will be set to 0 if not provided) + */ + public getUpfrontCost(baseFee = BigInt(0)): bigint { + const prio = this.maxPriorityFeePerGas; + const maxBase = this.maxFeePerGas - baseFee; + const inclusionFeePerGas = prio < maxBase ? prio : maxBase; + const gasPrice = inclusionFeePerGas + baseFee; + return this.gasLimit * gasPrice + this.value; + } + + /** + * Returns a Buffer Array of the raw Buffers of the EIP-1559 transaction, in order. + * + * Format: `[chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, + * accessList, signatureYParity, signatureR, signatureS]` + * + * Use {@link FeeMarketEIP1559Transaction.serialize} to add a transaction to a block + * with {@link Block.fromValuesArray}. + * + * For an unsigned tx this method uses the empty Buffer values for the + * signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant + * representation for external signing use {@link FeeMarketEIP1559Transaction.getMessageToSign}. + */ + public raw(): FeeMarketEIP1559ValuesArray { + return [ + bigIntToUnpaddedBuffer(this.chainId), + bigIntToUnpaddedBuffer(this.nonce), + bigIntToUnpaddedBuffer(this.maxPriorityFeePerGas), + bigIntToUnpaddedBuffer(this.maxFeePerGas), + bigIntToUnpaddedBuffer(this.gasLimit), + this.to !== undefined ? this.to.buf : Buffer.from([]), + bigIntToUnpaddedBuffer(this.value), + this.data, + this.accessList, + this.v !== undefined ? bigIntToUnpaddedBuffer(this.v) : Buffer.from([]), + this.r !== undefined ? bigIntToUnpaddedBuffer(this.r) : Buffer.from([]), + this.s !== undefined ? bigIntToUnpaddedBuffer(this.s) : Buffer.from([]), + ]; + } + + /** + * Returns the serialized encoding of the EIP-1559 transaction. + * + * Format: `0x02 || rlp([chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, + * accessList, signatureYParity, signatureR, signatureS])` + * + * Note that in contrast to the legacy tx serialization format this is not + * valid RLP any more due to the raw tx type preceding and concatenated to + * the RLP encoding of the values. + */ + public serialize(): Buffer { + const base = this.raw(); + return Buffer.concat([ + TRANSACTION_TYPE_BUFFER, + Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), + ]); + } + + /** + * Returns the serialized unsigned tx (hashed or raw), which can be used + * to sign the transaction (e.g. for sending to a hardware wallet). + * + * Note: in contrast to the legacy tx the raw message format is already + * serialized and doesn't need to be RLP encoded any more. + * + * ```javascript + * const serializedMessage = tx.getMessageToSign(false) // use this for the HW wallet input + * ``` + * + * @param hashMessage - Return hashed message if set to true (default: true) + */ + public getMessageToSign(hashMessage = true): Buffer { + const base = this.raw().slice(0, 9); + const message = Buffer.concat([ + TRANSACTION_TYPE_BUFFER, + Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), + ]); + if (hashMessage) { + return Buffer.from(keccak256(message)); + } + return message; + } + + /** + * Computes a sha3-256 hash of the serialized tx. + * + * This method can only be used for signed txs (it throws otherwise). + * Use {@link FeeMarketEIP1559Transaction.getMessageToSign} to get a tx hash for the purpose of signing. + */ + public hash(): Buffer { + if (!this.isSigned()) { + const msg = this._errorMsg('Cannot call hash method if transaction is not signed'); + throw new Error(msg); + } + + if (Object.isFrozen(this)) { + if (!this.cache.hash) { + this.cache.hash = Buffer.from(keccak256(this.serialize())); + } + return this.cache.hash; + } + + return Buffer.from(keccak256(this.serialize())); + } + + /** + * Computes a sha3-256 hash which can be used to verify the signature + */ + public getMessageToVerifySignature(): Buffer { + return this.getMessageToSign(); + } + + /** + * Returns the public key of the sender + */ + public getSenderPublicKey(): Buffer { + if (!this.isSigned()) { + const msg = this._errorMsg('Cannot call this method if transaction is not signed'); + throw new Error(msg); + } + + const msgHash = this.getMessageToVerifySignature(); + const { v, r, s } = this; + + this._validateHighS(); + + try { + return ecrecover( + msgHash, + v! + BigInt(27), // Recover the 27 which was stripped from ecsign + bigIntToUnpaddedBuffer(r!), + bigIntToUnpaddedBuffer(s!), + ); + } catch (e: any) { + const msg = this._errorMsg('Invalid Signature'); + throw new Error(msg); + } + } + + public _processSignature(v: bigint, r: Buffer, s: Buffer) { + const opts = { ...this.txOptions, common: this.common }; + + return FeeMarketEIP1559Transaction.fromTxData( + { + chainId: this.chainId, + nonce: this.nonce, + maxPriorityFeePerGas: this.maxPriorityFeePerGas, + maxFeePerGas: this.maxFeePerGas, + gasLimit: this.gasLimit, + to: this.to, + value: this.value, + data: this.data, + accessList: this.accessList, + v: v - BigInt(27), // This looks extremely hacky: /util actually adds 27 to the value, the recovery bit is either 0 or 1. + r: bufferToBigInt(r), + s: bufferToBigInt(s), + }, + opts, + ); + } + + /** + * Returns an object with the JSON representation of the transaction + */ + public toJSON(): JsonTx { + const accessListJSON = getAccessListJSON(this.accessList); + + return { + chainId: bigIntToHex(this.chainId), + nonce: bigIntToHex(this.nonce), + maxPriorityFeePerGas: bigIntToHex(this.maxPriorityFeePerGas), + maxFeePerGas: bigIntToHex(this.maxFeePerGas), + gasLimit: bigIntToHex(this.gasLimit), + to: this.to !== undefined ? this.to.toString() : undefined, + value: bigIntToHex(this.value), + data: `0x${this.data.toString('hex')}`, + accessList: accessListJSON, + v: this.v !== undefined ? bigIntToHex(this.v) : undefined, + r: this.r !== undefined ? bigIntToHex(this.r) : undefined, + s: this.s !== undefined ? bigIntToHex(this.s) : undefined, + }; + } + + /** + * Return a compact error string representation of the object + */ + public errorStr() { + let errorStr = this._getSharedErrorPostfix(); + errorStr += ` maxFeePerGas=${this.maxFeePerGas} maxPriorityFeePerGas=${this.maxPriorityFeePerGas}`; + return errorStr; + } + + /** + * Internal helper function to create an annotated error message + * + * @param msg Base error message + * @hidden + */ + protected _errorMsg(msg: string) { + return `${msg} (${this.errorStr()})`; + } +} diff --git a/packages/web3-eth-accounts/src/tx/eip2930Transaction.ts b/packages/web3-eth-accounts/src/tx/eip2930Transaction.ts new file mode 100644 index 00000000000..5c973dbfda1 --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/eip2930Transaction.ts @@ -0,0 +1,412 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { keccak256 } from 'ethereum-cryptography/keccak'; +import { validateNoLeadingZeroes } from 'web3-validator'; +import { RLP } from '@ethereumjs/rlp'; +import { MAX_INTEGER } from './constants'; +import { getAccessListData, verifyAccessList, getAccessListJSON, getDataFeeEIP2930 } from './utils'; +import { + arrToBufArr, + bigIntToHex, + bigIntToUnpaddedBuffer, + bufArrToArr, + bufferToBigInt, + toBuffer, + ecrecover, +} from '../common/utils'; +import { BaseTransaction } from './baseTransaction'; +import type { + AccessList, + AccessListBuffer, + AccessListEIP2930TxData, + AccessListEIP2930ValuesArray, + JsonTx, + TxOptions, +} from './types'; +import type { Common } from '../common'; + +const TRANSACTION_TYPE = 1; +const TRANSACTION_TYPE_BUFFER = Buffer.from(TRANSACTION_TYPE.toString(16).padStart(2, '0'), 'hex'); + +/** + * Typed transaction with optional access lists + * + * - TransactionType: 1 + * - EIP: [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) + */ +// eslint-disable-next-line no-use-before-define +export class AccessListEIP2930Transaction extends BaseTransaction { + public readonly chainId: bigint; + public readonly accessList: AccessListBuffer; + public readonly AccessListJSON: AccessList; + public readonly gasPrice: bigint; + + public readonly common: Common; + + /** + * The default HF if the tx type is active on that HF + * or the first greater HF where the tx is active. + * + * @hidden + */ + protected DEFAULT_HARDFORK = 'berlin'; + + /** + * Instantiate a transaction from a data dictionary. + * + * Format: { chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, + * v, r, s } + * + * Notes: + * - `chainId` will be set automatically if not provided + * - All parameters are optional and have some basic default values + */ + public static fromTxData(txData: AccessListEIP2930TxData, opts: TxOptions = {}) { + return new AccessListEIP2930Transaction(txData, opts); + } + + /** + * Instantiate a transaction from the serialized tx. + * + * Format: `0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, + * signatureYParity (v), signatureR (r), signatureS (s)])` + */ + public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {}) { + if (!serialized.subarray(0, 1).equals(TRANSACTION_TYPE_BUFFER)) { + throw new Error( + `Invalid serialized tx input: not an EIP-2930 transaction (wrong tx type, expected: ${TRANSACTION_TYPE}, received: ${serialized + .subarray(0, 1) + .toString('hex')}`, + ); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument + const values = arrToBufArr(RLP.decode(Uint8Array.from(serialized.subarray(1)))); + + if (!Array.isArray(values)) { + throw new Error('Invalid serialized tx input: must be array'); + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + return AccessListEIP2930Transaction.fromValuesArray(values as any, opts); + } + + /** + * Create a transaction from a values array. + * + * Format: `[chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, + * signatureYParity (v), signatureR (r), signatureS (s)]` + */ + public static fromValuesArray(values: AccessListEIP2930ValuesArray, opts: TxOptions = {}) { + if (values.length !== 8 && values.length !== 11) { + throw new Error( + 'Invalid EIP-2930 transaction. Only expecting 8 values (for unsigned tx) or 11 values (for signed tx).', + ); + } + + const [chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, v, r, s] = values; + + this._validateNotArray({ chainId, v }); + validateNoLeadingZeroes({ nonce, gasPrice, gasLimit, value, v, r, s }); + + const emptyAccessList: AccessList = []; + + return new AccessListEIP2930Transaction( + { + chainId: bufferToBigInt(chainId), + nonce, + gasPrice, + gasLimit, + to, + value, + data, + accessList: accessList ?? emptyAccessList, + v: v !== undefined ? bufferToBigInt(v) : undefined, // EIP2930 supports v's with value 0 (empty Buffer) + r, + s, + }, + opts, + ); + } + + /** + * This constructor takes the values, validates them, assigns them and freezes the object. + * + * It is not recommended to use this constructor directly. Instead use + * the static factory methods to assist in creating a Transaction object from + * varying data types. + */ + public constructor(txData: AccessListEIP2930TxData, opts: TxOptions = {}) { + super({ ...txData, type: TRANSACTION_TYPE }, opts); + const { chainId, accessList, gasPrice } = txData; + + this.common = this._getCommon(opts.common, chainId); + this.chainId = this.common.chainId(); + + // EIP-2718 check is done in Common + if (!this.common.isActivatedEIP(2930)) { + throw new Error('EIP-2930 not enabled on Common'); + } + this.activeCapabilities = this.activeCapabilities.concat([2718, 2930]); + + // Populate the access list fields + const accessListData = getAccessListData(accessList ?? []); + this.accessList = accessListData.accessList; + this.AccessListJSON = accessListData.AccessListJSON; + // Verify the access list format. + verifyAccessList(this.accessList); + + this.gasPrice = bufferToBigInt(toBuffer(gasPrice === '' ? '0x' : gasPrice)); + + this._validateCannotExceedMaxInteger({ + gasPrice: this.gasPrice, + }); + + BaseTransaction._validateNotArray(txData); + + if (this.gasPrice * this.gasLimit > MAX_INTEGER) { + const msg = this._errorMsg('gasLimit * gasPrice cannot exceed MAX_INTEGER'); + throw new Error(msg); + } + + this._validateYParity(); + this._validateHighS(); + + const freeze = opts?.freeze ?? true; + if (freeze) { + Object.freeze(this); + } + } + + /** + * The amount of gas paid for the data in this tx + */ + public getDataFee(): bigint { + if (this.cache.dataFee && this.cache.dataFee.hardfork === this.common.hardfork()) { + return this.cache.dataFee.value; + } + + let cost = super.getDataFee(); + cost += BigInt(getDataFeeEIP2930(this.accessList, this.common)); + + if (Object.isFrozen(this)) { + this.cache.dataFee = { + value: cost, + hardfork: this.common.hardfork(), + }; + } + + return cost; + } + + /** + * The up front amount that an account must have for this transaction to be valid + */ + public getUpfrontCost(): bigint { + return this.gasLimit * this.gasPrice + this.value; + } + + /** + * Returns a Buffer Array of the raw Buffers of the EIP-2930 transaction, in order. + * + * Format: `[chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, + * signatureYParity (v), signatureR (r), signatureS (s)]` + * + * Use {@link AccessListEIP2930Transaction.serialize} to add a transaction to a block + * with {@link Block.fromValuesArray}. + * + * For an unsigned tx this method uses the empty Buffer values for the + * signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant + * representation for external signing use {@link AccessListEIP2930Transaction.getMessageToSign}. + */ + public raw(): AccessListEIP2930ValuesArray { + return [ + bigIntToUnpaddedBuffer(this.chainId), + bigIntToUnpaddedBuffer(this.nonce), + bigIntToUnpaddedBuffer(this.gasPrice), + bigIntToUnpaddedBuffer(this.gasLimit), + this.to !== undefined ? this.to.buf : Buffer.from([]), + bigIntToUnpaddedBuffer(this.value), + this.data, + this.accessList, + this.v !== undefined ? bigIntToUnpaddedBuffer(this.v) : Buffer.from([]), + this.r !== undefined ? bigIntToUnpaddedBuffer(this.r) : Buffer.from([]), + this.s !== undefined ? bigIntToUnpaddedBuffer(this.s) : Buffer.from([]), + ]; + } + + /** + * Returns the serialized encoding of the EIP-2930 transaction. + * + * Format: `0x01 || rlp([chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, + * signatureYParity (v), signatureR (r), signatureS (s)])` + * + * Note that in contrast to the legacy tx serialization format this is not + * valid RLP any more due to the raw tx type preceding and concatenated to + * the RLP encoding of the values. + */ + public serialize(): Buffer { + const base = this.raw(); + return Buffer.concat([ + TRANSACTION_TYPE_BUFFER, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument + Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), + ]); + } + + /** + * Returns the serialized unsigned tx (hashed or raw), which can be used + * to sign the transaction (e.g. for sending to a hardware wallet). + * + * Note: in contrast to the legacy tx the raw message format is already + * serialized and doesn't need to be RLP encoded any more. + * + * ```javascript + * const serializedMessage = tx.getMessageToSign(false) // use this for the HW wallet input + * ``` + * + * @param hashMessage - Return hashed message if set to true (default: true) + */ + public getMessageToSign(hashMessage = true): Buffer { + const base = this.raw().slice(0, 8); + const message = Buffer.concat([ + TRANSACTION_TYPE_BUFFER, + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-argument + Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), + ]); + if (hashMessage) { + return Buffer.from(keccak256(message)); + } + return message; + } + + /** + * Computes a sha3-256 hash of the serialized tx. + * + * This method can only be used for signed txs (it throws otherwise). + * Use {@link AccessListEIP2930Transaction.getMessageToSign} to get a tx hash for the purpose of signing. + */ + public hash(): Buffer { + if (!this.isSigned()) { + const msg = this._errorMsg('Cannot call hash method if transaction is not signed'); + throw new Error(msg); + } + + if (Object.isFrozen(this)) { + if (!this.cache.hash) { + this.cache.hash = Buffer.from(keccak256(this.serialize())); + } + return this.cache.hash; + } + + return Buffer.from(keccak256(this.serialize())); + } + + /** + * Computes a sha3-256 hash which can be used to verify the signature + */ + public getMessageToVerifySignature(): Buffer { + return this.getMessageToSign(); + } + + /** + * Returns the public key of the sender + */ + public getSenderPublicKey(): Buffer { + if (!this.isSigned()) { + const msg = this._errorMsg('Cannot call this method if transaction is not signed'); + throw new Error(msg); + } + + const msgHash = this.getMessageToVerifySignature(); + const { v, r, s } = this; + + this._validateHighS(); + + try { + return ecrecover( + msgHash, + v! + BigInt(27), // Recover the 27 which was stripped from ecsign + bigIntToUnpaddedBuffer(r!), + bigIntToUnpaddedBuffer(s!), + ); + } catch (e: any) { + const msg = this._errorMsg('Invalid Signature'); + throw new Error(msg); + } + } + + public _processSignature(v: bigint, r: Buffer, s: Buffer) { + const opts = { ...this.txOptions, common: this.common }; + + return AccessListEIP2930Transaction.fromTxData( + { + chainId: this.chainId, + nonce: this.nonce, + gasPrice: this.gasPrice, + gasLimit: this.gasLimit, + to: this.to, + value: this.value, + data: this.data, + accessList: this.accessList, + v: v - BigInt(27), // This looks extremely hacky: /util actually adds 27 to the value, the recovery bit is either 0 or 1. + r: bufferToBigInt(r), + s: bufferToBigInt(s), + }, + opts, + ); + } + + /** + * Returns an object with the JSON representation of the transaction + */ + public toJSON(): JsonTx { + const accessListJSON = getAccessListJSON(this.accessList); + + return { + chainId: bigIntToHex(this.chainId), + nonce: bigIntToHex(this.nonce), + gasPrice: bigIntToHex(this.gasPrice), + gasLimit: bigIntToHex(this.gasLimit), + to: this.to !== undefined ? this.to.toString() : undefined, + value: bigIntToHex(this.value), + data: `0x${this.data.toString('hex')}`, + accessList: accessListJSON, + v: this.v !== undefined ? bigIntToHex(this.v) : undefined, + r: this.r !== undefined ? bigIntToHex(this.r) : undefined, + s: this.s !== undefined ? bigIntToHex(this.s) : undefined, + }; + } + + /** + * Return a compact error string representation of the object + */ + public errorStr() { + let errorStr = this._getSharedErrorPostfix(); + // Keep ? for this.accessList since this otherwise causes Hardhat E2E tests to fail + errorStr += ` gasPrice=${this.gasPrice} accessListCount=${this.accessList?.length ?? 0}`; + return errorStr; + } + + /** + * Internal helper function to create an annotated error message + * + * @param msg Base error message + * @hidden + */ + protected _errorMsg(msg: string) { + return `${msg} (${this.errorStr()})`; + } +} diff --git a/packages/web3-eth-accounts/src/tx/index.ts b/packages/web3-eth-accounts/src/tx/index.ts new file mode 100644 index 00000000000..0b5d3ab5628 --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/index.ts @@ -0,0 +1,23 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +// @ethereumjs/tx version 4.1.1 +export { FeeMarketEIP1559Transaction } from './eip1559Transaction'; +export { AccessListEIP2930Transaction } from './eip2930Transaction'; +export { Transaction } from './legacyTransaction'; +export { TransactionFactory } from './transactionFactory'; +export * from './types'; diff --git a/packages/web3-eth-accounts/src/tx/legacyTransaction.ts b/packages/web3-eth-accounts/src/tx/legacyTransaction.ts new file mode 100644 index 00000000000..b40d5f08d07 --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/legacyTransaction.ts @@ -0,0 +1,439 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { keccak256 } from 'ethereum-cryptography/keccak'; +import { validateNoLeadingZeroes } from 'web3-validator'; +import { RLP } from '@ethereumjs/rlp'; +import { MAX_INTEGER } from './constants'; +import { + arrToBufArr, + bigIntToHex, + bigIntToUnpaddedBuffer, + bufArrToArr, + bufferToBigInt, + toBuffer, + ecrecover, + unpadBuffer, +} from '../common/utils'; + +import { BaseTransaction } from './baseTransaction'; + +import type { JsonTx, TxData, TxOptions, TxValuesArray } from './types'; +import { Capability } from './types'; +import type { Common } from '../common'; + +const TRANSACTION_TYPE = 0; + +function meetsEIP155(_v: bigint, chainId: bigint) { + const v = Number(_v); + const chainIdDoubled = Number(chainId) * 2; + return v === chainIdDoubled + 35 || v === chainIdDoubled + 36; +} + +/** + * An Ethereum non-typed (legacy) transaction + */ +// eslint-disable-next-line no-use-before-define +export class Transaction extends BaseTransaction { + public readonly gasPrice: bigint; + + public readonly common: Common; + + /** + * Instantiate a transaction from a data dictionary. + * + * Format: { nonce, gasPrice, gasLimit, to, value, data, v, r, s } + * + * Notes: + * - All parameters are optional and have some basic default values + */ + public static fromTxData(txData: TxData, opts: TxOptions = {}) { + return new Transaction(txData, opts); + } + + /** + * Instantiate a transaction from the serialized tx. + * + * Format: `rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s])` + */ + public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {}) { + const values = arrToBufArr(RLP.decode(Uint8Array.from(serialized))) as Buffer[]; + + if (!Array.isArray(values)) { + throw new Error('Invalid serialized tx input. Must be array'); + } + + return this.fromValuesArray(values, opts); + } + + /** + * Create a transaction from a values array. + * + * Format: `[nonce, gasPrice, gasLimit, to, value, data, v, r, s]` + */ + public static fromValuesArray(values: TxValuesArray, opts: TxOptions = {}) { + // If length is not 6, it has length 9. If v/r/s are empty Buffers, it is still an unsigned transaction + // This happens if you get the RLP data from `raw()` + if (values.length !== 6 && values.length !== 9) { + throw new Error( + 'Invalid transaction. Only expecting 6 values (for unsigned tx) or 9 values (for signed tx).', + ); + } + + const [nonce, gasPrice, gasLimit, to, value, data, v, r, s] = values; + + validateNoLeadingZeroes({ nonce, gasPrice, gasLimit, value, v, r, s }); + + return new Transaction( + { + nonce, + gasPrice, + gasLimit, + to, + value, + data, + v, + r, + s, + }, + opts, + ); + } + + /** + * This constructor takes the values, validates them, assigns them and freezes the object. + * + * It is not recommended to use this constructor directly. Instead use + * the static factory methods to assist in creating a Transaction object from + * varying data types. + */ + public constructor(txData: TxData, opts: TxOptions = {}) { + super({ ...txData, type: TRANSACTION_TYPE }, opts); + + this.common = this._validateTxV(this.v, opts.common); + + this.gasPrice = bufferToBigInt(toBuffer(txData.gasPrice === '' ? '0x' : txData.gasPrice)); + + if (this.gasPrice * this.gasLimit > MAX_INTEGER) { + const msg = this._errorMsg('gas limit * gasPrice cannot exceed MAX_INTEGER (2^256-1)'); + throw new Error(msg); + } + this._validateCannotExceedMaxInteger({ gasPrice: this.gasPrice }); + BaseTransaction._validateNotArray(txData); + + if (this.common.gteHardfork('spuriousDragon')) { + if (!this.isSigned()) { + this.activeCapabilities.push(Capability.EIP155ReplayProtection); + } else { + // EIP155 spec: + // If block.number >= 2,675,000 and v = CHAIN_ID * 2 + 35 or v = CHAIN_ID * 2 + 36 + // then when computing the hash of a transaction for purposes of signing or recovering + // instead of hashing only the first six elements (i.e. nonce, gasprice, startgas, to, value, data) + // hash nine elements, with v replaced by CHAIN_ID, r = 0 and s = 0. + // v and chain ID meet EIP-155 conditions + // eslint-disable-next-line no-lonely-if + if (meetsEIP155(this.v!, this.common.chainId())) { + this.activeCapabilities.push(Capability.EIP155ReplayProtection); + } + } + } + + const freeze = opts?.freeze ?? true; + if (freeze) { + Object.freeze(this); + } + } + + /** + * Returns a Buffer Array of the raw Buffers of the legacy transaction, in order. + * + * Format: `[nonce, gasPrice, gasLimit, to, value, data, v, r, s]` + * + * For legacy txs this is also the correct format to add transactions + * to a block with {@link Block.fromValuesArray} (use the `serialize()` method + * for typed txs). + * + * For an unsigned tx this method returns the empty Buffer values + * for the signature parameters `v`, `r` and `s`. For an EIP-155 compliant + * representation have a look at {@link Transaction.getMessageToSign}. + */ + public raw(): TxValuesArray { + return [ + bigIntToUnpaddedBuffer(this.nonce), + bigIntToUnpaddedBuffer(this.gasPrice), + bigIntToUnpaddedBuffer(this.gasLimit), + this.to !== undefined ? this.to.buf : Buffer.from([]), + bigIntToUnpaddedBuffer(this.value), + this.data, + this.v !== undefined ? bigIntToUnpaddedBuffer(this.v) : Buffer.from([]), + this.r !== undefined ? bigIntToUnpaddedBuffer(this.r) : Buffer.from([]), + this.s !== undefined ? bigIntToUnpaddedBuffer(this.s) : Buffer.from([]), + ]; + } + + /** + * Returns the serialized encoding of the legacy transaction. + * + * Format: `rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s])` + * + * For an unsigned tx this method uses the empty Buffer values for the + * signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant + * representation for external signing use {@link Transaction.getMessageToSign}. + */ + public serialize(): Buffer { + return Buffer.from(RLP.encode(bufArrToArr(this.raw()))); + } + + private _getMessageToSign() { + const values = [ + bigIntToUnpaddedBuffer(this.nonce), + bigIntToUnpaddedBuffer(this.gasPrice), + bigIntToUnpaddedBuffer(this.gasLimit), + this.to !== undefined ? this.to.buf : Buffer.from([]), + bigIntToUnpaddedBuffer(this.value), + this.data, + ]; + + if (this.supports(Capability.EIP155ReplayProtection)) { + values.push(toBuffer(this.common.chainId())); + values.push(unpadBuffer(toBuffer(0))); + values.push(unpadBuffer(toBuffer(0))); + } + + return values; + } + + /** + * Returns the unsigned tx (hashed or raw), which can be used + * to sign the transaction (e.g. for sending to a hardware wallet). + * + * Note: the raw message message format for the legacy tx is not RLP encoded + * and you might need to do yourself with: + * + * ```javascript + * import { bufArrToArr } from '../util' + * import { RLP } from '../rlp' + * const message = tx.getMessageToSign(false) + * const serializedMessage = Buffer.from(RLP.encode(bufArrToArr(message))) // use this for the HW wallet input + * ``` + * + * @param hashMessage - Return hashed message if set to true (default: true) + */ + public getMessageToSign(hashMessage: false): Buffer[]; + public getMessageToSign(hashMessage?: true): Buffer; + public getMessageToSign(hashMessage = true) { + const message = this._getMessageToSign(); + if (hashMessage) { + return Buffer.from(keccak256(RLP.encode(bufArrToArr(message)))); + } + return message; + } + + /** + * The amount of gas paid for the data in this tx + */ + public getDataFee(): bigint { + if (this.cache.dataFee && this.cache.dataFee.hardfork === this.common.hardfork()) { + return this.cache.dataFee.value; + } + + if (Object.isFrozen(this)) { + this.cache.dataFee = { + value: super.getDataFee(), + hardfork: this.common.hardfork(), + }; + } + + return super.getDataFee(); + } + + /** + * The up front amount that an account must have for this transaction to be valid + */ + public getUpfrontCost(): bigint { + return this.gasLimit * this.gasPrice + this.value; + } + + /** + * Computes a sha3-256 hash of the serialized tx. + * + * This method can only be used for signed txs (it throws otherwise). + * Use {@link Transaction.getMessageToSign} to get a tx hash for the purpose of signing. + */ + public hash(): Buffer { + if (!this.isSigned()) { + const msg = this._errorMsg('Cannot call hash method if transaction is not signed'); + throw new Error(msg); + } + + if (Object.isFrozen(this)) { + if (!this.cache.hash) { + this.cache.hash = Buffer.from(keccak256(RLP.encode(bufArrToArr(this.raw())))); + } + return this.cache.hash; + } + + return Buffer.from(keccak256(RLP.encode(bufArrToArr(this.raw())))); + } + + /** + * Computes a sha3-256 hash which can be used to verify the signature + */ + public getMessageToVerifySignature() { + if (!this.isSigned()) { + const msg = this._errorMsg('This transaction is not signed'); + throw new Error(msg); + } + const message = this._getMessageToSign(); + // eslint + return Buffer.from(keccak256(RLP.encode(bufArrToArr(message)))); + } + + /** + * Returns the public key of the sender + */ + public getSenderPublicKey(): Buffer { + const msgHash = this.getMessageToVerifySignature(); + + const { v, r, s } = this; + + this._validateHighS(); + + try { + return ecrecover( + msgHash, + v!, + bigIntToUnpaddedBuffer(r!), + bigIntToUnpaddedBuffer(s!), + this.supports(Capability.EIP155ReplayProtection) + ? this.common.chainId() + : undefined, + ); + } catch (e: any) { + const msg = this._errorMsg('Invalid Signature'); + throw new Error(msg); + } + } + + /** + * Process the v, r, s values from the `sign` method of the base transaction. + */ + protected _processSignature(_v: bigint, r: Buffer, s: Buffer) { + let v = _v; + if (this.supports(Capability.EIP155ReplayProtection)) { + v += this.common.chainId() * BigInt(2) + BigInt(8); + } + + const opts = { ...this.txOptions, common: this.common }; + + return Transaction.fromTxData( + { + nonce: this.nonce, + gasPrice: this.gasPrice, + gasLimit: this.gasLimit, + to: this.to, + value: this.value, + data: this.data, + v, + r: bufferToBigInt(r), + s: bufferToBigInt(s), + }, + opts, + ); + } + + /** + * Returns an object with the JSON representation of the transaction. + */ + public toJSON(): JsonTx { + return { + nonce: bigIntToHex(this.nonce), + gasPrice: bigIntToHex(this.gasPrice), + gasLimit: bigIntToHex(this.gasLimit), + to: this.to !== undefined ? this.to.toString() : undefined, + value: bigIntToHex(this.value), + data: `0x${this.data.toString('hex')}`, + v: this.v !== undefined ? bigIntToHex(this.v) : undefined, + r: this.r !== undefined ? bigIntToHex(this.r) : undefined, + s: this.s !== undefined ? bigIntToHex(this.s) : undefined, + }; + } + + /** + * Validates tx's `v` value + */ + private _validateTxV(_v?: bigint, common?: Common): Common { + let chainIdBigInt; + const v = _v !== undefined ? Number(_v) : undefined; + // Check for valid v values in the scope of a signed legacy tx + if (v !== undefined) { + // v is 1. not matching the EIP-155 chainId included case and... + // v is 2. not matching the classic v=27 or v=28 case + if (v < 37 && v !== 27 && v !== 28) { + throw new Error( + `Legacy txs need either v = 27/28 or v >= 37 (EIP-155 replay protection), got v = ${v}`, + ); + } + } + + // No unsigned tx and EIP-155 activated and chain ID included + if ( + v !== undefined && + v !== 0 && + (!common || common.gteHardfork('spuriousDragon')) && + v !== 27 && + v !== 28 + ) { + if (common) { + if (!meetsEIP155(BigInt(v), common.chainId())) { + throw new Error( + `Incompatible EIP155-based V ${v} and chain id ${common.chainId()}. See the Common parameter of the Transaction constructor to set the chain id.`, + ); + } + } else { + // Derive the original chain ID + let numSub; + if ((v - 35) % 2 === 0) { + numSub = 35; + } else { + numSub = 36; + } + // Use derived chain ID to create a proper Common + chainIdBigInt = BigInt(v - numSub) / BigInt(2); + } + } + return this._getCommon(common, chainIdBigInt); + } + + /** + * Return a compact error string representation of the object + */ + public errorStr() { + let errorStr = this._getSharedErrorPostfix(); + errorStr += ` gasPrice=${this.gasPrice}`; + return errorStr; + } + + /** + * Internal helper function to create an annotated error message + * + * @param msg Base error message + * @hidden + */ + protected _errorMsg(msg: string) { + return `${msg} (${this.errorStr()})`; + } +} diff --git a/packages/web3-eth-accounts/src/tx/transactionFactory.ts b/packages/web3-eth-accounts/src/tx/transactionFactory.ts new file mode 100644 index 00000000000..1bfcfad181a --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/transactionFactory.ts @@ -0,0 +1,108 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { bufferToBigInt, toBuffer } from '../common/utils'; +import { FeeMarketEIP1559Transaction } from './eip1559Transaction'; +import { AccessListEIP2930Transaction } from './eip2930Transaction'; +import { Transaction } from './legacyTransaction'; +import type { TypedTransaction } from '../types'; + +import type { AccessListEIP2930TxData, FeeMarketEIP1559TxData, TxData, TxOptions } from './types'; + +// eslint-disable-next-line @typescript-eslint/no-extraneous-class +export class TransactionFactory { + // It is not possible to instantiate a TransactionFactory object. + // eslint-disable-next-line @typescript-eslint/no-empty-function, no-useless-constructor + private constructor() {} + + /** + * Create a transaction from a `txData` object + * + * @param txData - The transaction data. The `type` field will determine which transaction type is returned (if undefined, creates a legacy transaction) + * @param txOptions - Options to pass on to the constructor of the transaction + */ + public static fromTxData( + txData: TxData | TypedTransaction, + txOptions: TxOptions = {}, + ): TypedTransaction { + if (!('type' in txData) || txData.type === undefined) { + // Assume legacy transaction + return Transaction.fromTxData(txData as TxData, txOptions); + } + const txType = Number(bufferToBigInt(toBuffer(txData.type))); + if (txType === 0) { + return Transaction.fromTxData(txData as TxData, txOptions); + } + if (txType === 1) { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return AccessListEIP2930Transaction.fromTxData( + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + txData, + txOptions, + ); + } + if (txType === 2) { + return FeeMarketEIP1559Transaction.fromTxData( + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + txData, + txOptions, + ); + } + throw new Error(`Tx instantiation with type ${txType} not supported`); + } + + /** + * This method tries to decode serialized data. + * + * @param data - The data Buffer + * @param txOptions - The transaction options + */ + public static fromSerializedData(data: Buffer, txOptions: TxOptions = {}): TypedTransaction { + if (data[0] <= 0x7f) { + // Determine the type. + switch (data[0]) { + case 1: + return AccessListEIP2930Transaction.fromSerializedTx(data, txOptions); + case 2: + return FeeMarketEIP1559Transaction.fromSerializedTx(data, txOptions); + default: + throw new Error(`TypedTransaction with ID ${data[0]} unknown`); + } + } else { + return Transaction.fromSerializedTx(data, txOptions); + } + } + + /** + * When decoding a BlockBody, in the transactions field, a field is either: + * A Buffer (a TypedTransaction - encoded as TransactionType || rlp(TransactionPayload)) + * A Buffer[] (Legacy Transaction) + * This method returns the right transaction. + * + * @param data - A Buffer or Buffer[] + * @param txOptions - The transaction options + */ + public static fromBlockBodyData(data: Buffer | Buffer[], txOptions: TxOptions = {}) { + if (Buffer.isBuffer(data)) { + return this.fromSerializedData(data, txOptions); + } + if (Array.isArray(data)) { + // It is a legacy transaction + return Transaction.fromValuesArray(data, txOptions); + } + throw new Error('Cannot decode transaction: unknown type input'); + } +} diff --git a/packages/web3-eth-accounts/src/tx/types.ts b/packages/web3-eth-accounts/src/tx/types.ts new file mode 100644 index 00000000000..dec6d4d9dd1 --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/types.ts @@ -0,0 +1,288 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import type { HexString, Numbers } from 'web3-types'; +import { Buffer } from 'buffer'; + +import type { Common } from '../common/common'; +import type { BufferLike, PrefixedHexString } from '../common/types'; +import { Address } from './address'; + +/** + * Can be used in conjunction with {@link Transaction.supports} + * to query on tx capabilities + */ +export enum Capability { + /** + * Tx supports EIP-155 replay protection + * See: [155](https://eips.ethereum.org/EIPS/eip-155) Replay Attack Protection EIP + */ + EIP155ReplayProtection = 155, + + /** + * Tx supports EIP-1559 gas fee market mechanism + * See: [1559](https://eips.ethereum.org/EIPS/eip-1559) Fee Market EIP + */ + EIP1559FeeMarket = 1559, + + /** + * Tx is a typed transaction as defined in EIP-2718 + * See: [2718](https://eips.ethereum.org/EIPS/eip-2718) Transaction Type EIP + */ + EIP2718TypedTransaction = 2718, + + /** + * Tx supports access list generation as defined in EIP-2930 + * See: [2930](https://eips.ethereum.org/EIPS/eip-2930) Access Lists EIP + */ + EIP2930AccessLists = 2930, +} + +/** + * The options for initializing a {@link Transaction}. + */ +export interface TxOptions { + /** + * A {@link Common} object defining the chain and hardfork for the transaction. + * + * Object will be internally copied so that tx behavior don't incidentally + * change on future HF changes. + * + * Default: {@link Common} object set to `mainnet` and the default hardfork as defined in the {@link Common} class. + * + * Current default hardfork: `istanbul` + */ + common?: Common; + /** + * A transaction object by default gets frozen along initialization. This gives you + * strong additional security guarantees on the consistency of the tx parameters. + * It also enables tx hash caching when the `hash()` method is called multiple times. + * + * If you need to deactivate the tx freeze - e.g. because you want to subclass tx and + * add additional properties - it is strongly encouraged that you do the freeze yourself + * within your code instead. + * + * Default: true + */ + freeze?: boolean; + + /** + * Allows unlimited contract code-size init while debugging. This (partially) disables EIP-3860. + * Gas cost for initcode size analysis will still be charged. Use with caution. + */ + allowUnlimitedInitCodeSize?: boolean; +} + +/* + * Access List types + */ + +export type AccessListItem = { + address: PrefixedHexString; + storageKeys: PrefixedHexString[]; +}; + +/* + * An Access List as a tuple of [address: Buffer, storageKeys: Buffer[]] + */ +export type AccessListBufferItem = [Buffer, Buffer[]]; +export type AccessListBuffer = AccessListBufferItem[]; +export type AccessList = AccessListItem[]; + +export function isAccessListBuffer( + input: AccessListBuffer | AccessList, +): input is AccessListBuffer { + if (input.length === 0) { + return true; + } + const firstItem = input[0]; + if (Array.isArray(firstItem)) { + return true; + } + return false; +} + +export function isAccessList(input: AccessListBuffer | AccessList): input is AccessList { + return !isAccessListBuffer(input); // This is exactly the same method, except the output is negated. +} + +export interface ECDSASignature { + v: bigint; + r: Buffer; + s: Buffer; +} + +/** + * Legacy {@link Transaction} Data + */ +export type TxData = { + /** + * The transaction's nonce. + */ + nonce?: Numbers | Buffer; + + /** + * The transaction's gas price. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + gasPrice?: Numbers | Buffer | null; + + /** + * The transaction's gas limit. + */ + gasLimit?: Numbers | Buffer; + + /** + * The transaction's the address is sent to. + */ + to?: Address | Buffer | HexString; + + /** + * The amount of Ether sent. + */ + value?: Numbers | Buffer; + + /** + * This will contain the data of the message or the init of a contract. + */ + data?: BufferLike; + + /** + * EC recovery ID. + */ + v?: Numbers | Buffer; + + /** + * EC signature parameter. + */ + r?: Numbers | Buffer; + + /** + * EC signature parameter. + */ + s?: Numbers | Buffer; + + /** + * The transaction type + */ + + type?: Numbers; +}; + +/** + * {@link AccessListEIP2930Transaction} data. + */ +export interface AccessListEIP2930TxData extends TxData { + /** + * The transaction's chain ID + */ + chainId?: Numbers; + + /** + * The access list which contains the addresses/storage slots which the transaction wishes to access + */ + // eslint-disable-next-line @typescript-eslint/ban-types + accessList?: AccessListBuffer | AccessList | null; +} + +/** + * {@link FeeMarketEIP1559Transaction} data. + */ +export interface FeeMarketEIP1559TxData extends AccessListEIP2930TxData { + /** + * The transaction's gas price, inherited from {@link Transaction}. This property is not used for EIP1559 + * transactions and should always be undefined for this specific transaction type. + */ + // eslint-disable-next-line @typescript-eslint/ban-types + gasPrice?: never | null; + /** + * The maximum inclusion fee per gas (this fee is given to the miner) + */ + maxPriorityFeePerGas?: Numbers | Buffer; + /** + * The maximum total fee + */ + maxFeePerGas?: Numbers | Buffer; +} + +/** + * Buffer values array for a legacy {@link Transaction} + */ +export type TxValuesArray = Buffer[]; + +/** + * Buffer values array for an {@link AccessListEIP2930Transaction} + */ +export type AccessListEIP2930ValuesArray = [ + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + AccessListBuffer, + Buffer?, + Buffer?, + Buffer?, +]; + +/** + * Buffer values array for a {@link FeeMarketEIP1559Transaction} + */ +export type FeeMarketEIP1559ValuesArray = [ + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + Buffer, + AccessListBuffer, + Buffer?, + Buffer?, + Buffer?, +]; + +type JsonAccessListItem = { address: string; storageKeys: string[] }; + +/** + * Generic interface for all tx types with a + * JSON representation of a transaction. + * + * Note that all values are marked as optional + * and not all the values are present on all tx types + * (an EIP1559 tx e.g. lacks a `gasPrice`). + */ +export interface JsonTx { + nonce?: string; + gasPrice?: string; + gasLimit?: string; + to?: string; + data?: string; + v?: string; + r?: string; + s?: string; + value?: string; + chainId?: string; + accessList?: JsonAccessListItem[]; + type?: string; + maxPriorityFeePerGas?: string; + maxFeePerGas?: string; + maxFeePerDataGas?: string; + versionedHashes?: string[]; +} diff --git a/packages/web3-eth-accounts/src/tx/utils.ts b/packages/web3-eth-accounts/src/tx/utils.ts new file mode 100644 index 00000000000..5c54085dcce --- /dev/null +++ b/packages/web3-eth-accounts/src/tx/utils.ts @@ -0,0 +1,149 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { HexString } from 'web3-types'; +import { bufferToHex, setLengthLeft, toBuffer } from '../common/utils'; +import type { AccessList, AccessListBuffer, AccessListItem } from './types'; +import { isAccessList } from './types'; + +import type { Common } from '../common/common'; + +export const checkMaxInitCodeSize = (common: Common, length: number) => { + const maxInitCodeSize = common.param('vm', 'maxInitCodeSize'); + if (maxInitCodeSize && BigInt(length) > maxInitCodeSize) { + throw new Error( + `the initcode size of this transaction is too large: it is ${length} while the max is ${common.param( + 'vm', + 'maxInitCodeSize', + )}`, + ); + } +}; + +export const getAccessListData = (accessList: AccessListBuffer | AccessList) => { + let AccessListJSON; + let bufferAccessList; + if (isAccessList(accessList)) { + AccessListJSON = accessList; + const newAccessList: AccessListBuffer = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < accessList.length; i += 1) { + const item: AccessListItem = accessList[i]; + const addressBuffer = toBuffer(item.address); + const storageItems: Buffer[] = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let index = 0; index < item.storageKeys.length; index += 1) { + storageItems.push(toBuffer(item.storageKeys[index])); + } + newAccessList.push([addressBuffer, storageItems]); + } + bufferAccessList = newAccessList; + } else { + bufferAccessList = accessList ?? []; + // build the JSON + const json: AccessList = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < bufferAccessList.length; i += 1) { + const data = bufferAccessList[i]; + const address = bufferToHex(data[0]); + const storageKeys: string[] = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let item = 0; item < data[1].length; item += 1) { + storageKeys.push(bufferToHex(data[1][item])); + } + const jsonItem: AccessListItem = { + address, + storageKeys, + }; + json.push(jsonItem); + } + AccessListJSON = json; + } + + return { + AccessListJSON, + accessList: bufferAccessList, + }; +}; + +export const verifyAccessList = (accessList: AccessListBuffer) => { + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let key = 0; key < accessList.length; key += 1) { + const accessListItem = accessList[key]; + const address = accessListItem[0]; + const storageSlots = accessListItem[1]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/consistent-type-assertions + if ((accessListItem)[2] !== undefined) { + throw new Error( + 'Access list item cannot have 3 elements. It can only have an address, and an array of storage slots.', + ); + } + if (address.length !== 20) { + throw new Error('Invalid EIP-2930 transaction: address length should be 20 bytes'); + } + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let storageSlot = 0; storageSlot < storageSlots.length; storageSlot += 1) { + if (storageSlots[storageSlot].length !== 32) { + throw new Error( + 'Invalid EIP-2930 transaction: storage slot length should be 32 bytes', + ); + } + } + } +}; + +export const getAccessListJSON = ( + accessList: AccessListBuffer, +): { + address: HexString; + storageKeys: HexString[]; +}[] => { + const accessListJSON: { address: HexString; storageKeys: HexString[] }[] = []; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let index = 0; index < accessList.length; index += 1) { + const item: any = accessList[index]; + const JSONItem: { address: HexString; storageKeys: HexString[] } = { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/consistent-type-assertions + address: `0x${setLengthLeft(item[0], 20).toString('hex')}`, + storageKeys: [], + }; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/prefer-optional-chain + const storageSlots: Buffer[] = item && item[1]; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let slot = 0; slot < storageSlots.length; slot += 1) { + const storageSlot = storageSlots[slot]; + JSONItem.storageKeys.push(`0x${setLengthLeft(storageSlot, 32).toString('hex')}`); + } + accessListJSON.push(JSONItem); + } + return accessListJSON; +}; + +export const getDataFeeEIP2930 = (accessList: AccessListBuffer, common: Common): number => { + const accessListStorageKeyCost = common.param('gasPrices', 'accessListStorageKeyCost'); + const accessListAddressCost = common.param('gasPrices', 'accessListAddressCost'); + + let slots = 0; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let index = 0; index < accessList.length; index += 1) { + const item = accessList[index]; + const storageSlots = item[1]; + slots += storageSlots.length; + } + + const addresses = accessList.length; + return addresses * Number(accessListAddressCost) + slots * Number(accessListStorageKeyCost); +}; diff --git a/packages/web3-eth-accounts/src/types.ts b/packages/web3-eth-accounts/src/types.ts index 4897f30f586..396ccfa9440 100644 --- a/packages/web3-eth-accounts/src/types.ts +++ b/packages/web3-eth-accounts/src/types.ts @@ -15,8 +15,9 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { FeeMarketEIP1559TxData, AccessListEIP2930TxData, TxData } from '@ethereumjs/tx'; import { Web3BaseWalletAccount, HexString } from 'web3-types'; +import { FeeMarketEIP1559TxData, AccessListEIP2930TxData, TxData } from './tx/types'; +import { AccessListEIP2930Transaction, FeeMarketEIP1559Transaction, Transaction } from './tx'; export type SignatureObject = { messageHash: string; @@ -86,3 +87,8 @@ export interface WebStorage { // eslint-disable-next-line @typescript-eslint/no-explicit-any [name: string]: any; } + +export type TypedTransaction = + | Transaction + | AccessListEIP2930Transaction + | FeeMarketEIP1559Transaction; diff --git a/packages/web3-eth-accounts/test/fixtures/account.ts b/packages/web3-eth-accounts/test/fixtures/account.ts index f12a05f3f0a..1c833a506e2 100644 --- a/packages/web3-eth-accounts/test/fixtures/account.ts +++ b/packages/web3-eth-accounts/test/fixtures/account.ts @@ -15,7 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { AccessListEIP2930TxData, FeeMarketEIP1559TxData, TxData } from '@ethereumjs/tx'; import { InvalidKdfError, InvalidPrivateKeyError, @@ -26,6 +25,7 @@ import { PBKDF2IterationsError, } from 'web3-errors'; import { CipherOptions, KeyStore } from 'web3-types'; +import { AccessListEIP2930TxData, FeeMarketEIP1559TxData, TxData } from '../../src/tx/types'; import { sign, signTransaction, encrypt } from '../../src/account'; export const validPrivateKeyToAddressData: [string, string][] = [ diff --git a/packages/web3-eth-accounts/test/fixtures/common/geth-genesis-kiln.json b/packages/web3-eth-accounts/test/fixtures/common/geth-genesis-kiln.json new file mode 100644 index 00000000000..ecaad9b82e2 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/geth-genesis-kiln.json @@ -0,0 +1,865 @@ +{ + "config": { + "chainId": 1337802, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeForkBlock": 1000, + "terminalTotalDifficulty": 20000000000000 + }, + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0xf97e180c050e5Ab072211Ad2C213Eb5AEE4DF134": { + "balance": "10000000000000000000000000" + }, + "0x2cA5F489CC1Fd1CEC24747B64E8dE0F4A6A850E1": { + "balance": "10000000000000000000000000" + }, + "0x7203bd333a874D9d329050ecE393820fCD501eaA": { + "balance": "10000000000000000000000000" + }, + "0xA51918aA40D78Ff8be939bf0E8404252875c6aDF": { + "balance": "10000000000000000000000000" + }, + "0xAA81078e6b2121dd7A846690DFdD6b10d7658d8B": { + "balance": "10000000000000000000000000" + }, + "0xFA2d31D8f21c1D1633E9BEB641dF77D21D63ccDd": { + "balance": "10000000000000000000000000" + }, + "0xf751C9c6d60614226fE57D2cAD6e10C856a2ddA3": { + "balance": "10000000000000000000000000" + }, + "0x9cD16887f6A808AEaa65D3c840f059EeA4ca1319": { + "balance": "10000000000000000000000000" + }, + "0x2E07043584F11BFF0AC39c927665DF6c6ebaffFB": { + "balance": "10000000000000000000000000" + }, + "0x60e771E5eCA8E26690920de669520Da210D64A9B": { + "balance": "10000000000000000000000000" + }, + "0xFC4db92C2Cf77CE02fBfd7Da0346d2CbFA66aD59": { + "balance": "10000000000000000000000000" + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x01", + "extraData": "", + "gasLimit": "0x400000", + "nonce": "0x1234", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0" +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/invalid-spurious-dragon.json b/packages/web3-eth-accounts/test/fixtures/common/invalid-spurious-dragon.json new file mode 100644 index 00000000000..f254e2e5ed5 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/invalid-spurious-dragon.json @@ -0,0 +1,32 @@ +{ + "config": { + "chainId": 5, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 1, + "byzantiumBlock": 2, + "constantinopleBlock": 3, + "petersburgBlock": 4, + "istanbulBlock": 5, + "berlinBlock": 6, + "londonBlock": 7, + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "nonce": "0x0", + "timestamp": "0x5c51a607", + "extraData": "0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0xa00000", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": null +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/merge/testnetMerge.json b/packages/web3-eth-accounts/test/fixtures/common/merge/testnetMerge.json new file mode 100644 index 00000000000..8f710633be5 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/merge/testnetMerge.json @@ -0,0 +1,81 @@ +{ + "name": "testnetMerge", + "chainId": 55555, + "networkId": 55555, + "defaultHardfork": "istanbul", + "consensus": { + "type": "poa", + "algorithm": "clique", + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "comment": "Private test network", + "url": "[TESTNET_URL]", + "genesis": { + "gasLimit": 1000000, + "difficulty": 1, + "nonce": "0xbb00000000000000", + "extraData": "0xcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0 + }, + { + "name": "homestead", + "block": 1 + }, + { + "name": "tangerineWhistle", + "block": 2 + }, + { + "name": "spuriousDragon", + "block": 3 + }, + { + "name": "istanbul", + "block": 8 + }, + { + "name": "muirGlacier", + "block": 10 + }, + { + "name": "berlin", + "block": 12 + }, + { + "name": "london", + "block": 14 + }, + { + "name": "merge", + "block": null, + "ttd": "5000" + }, + { + "name": "shanghai", + "block": null + } + ], + "bootstrapNodes": [ + { + "ip": "10.0.0.1", + "port": 30303, + "id": "11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + }, + { + "ip": "10.0.0.2", + "port": 30303, + "id": "22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + } + ] +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/merge/testnetPOS.json b/packages/web3-eth-accounts/test/fixtures/common/merge/testnetPOS.json new file mode 100644 index 00000000000..9ed75d0566d --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/merge/testnetPOS.json @@ -0,0 +1,46 @@ +{ + "name": "testnetPOS", + "chainId": 66666, + "networkId": 66666, + "defaultHardfork": "chainstart", + "consensus": { + "type": "pos", + "algorithm": "casper", + "casper": {} + }, + "comment": "Private test network (TODO: genesis block not constructed according to POS block rules yet)", + "url": "[TESTNET_URL]", + "genesis": { + "gasLimit": 1000000, + "difficulty": 1, + "nonce": "0xbb00000000000000", + "extraData": "0xcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0, + "ttd": "0" + }, + { + "name": "shanghai", + "block": 5 + } + ], + "bootstrapNodes": [ + { + "ip": "10.0.0.1", + "port": 30303, + "id": "11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + }, + { + "ip": "10.0.0.2", + "port": 30303, + "id": "22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + } + ] +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/no-extra-data.json b/packages/web3-eth-accounts/test/fixtures/common/no-extra-data.json new file mode 100644 index 00000000000..c7bbc4c5af4 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/no-extra-data.json @@ -0,0 +1,37 @@ +{ + "config": { + "chainId": 1, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + }, + "terminalTotalDifficulty": 0 + }, + "nonce": "0x42", + "timestamp": "16", + "extraData": "", + "gasLimit": "0x1C9C380", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x6d6172697573766477000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x7" +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/poa.json b/packages/web3-eth-accounts/test/fixtures/common/poa.json new file mode 100644 index 00000000000..68b5a3eaef8 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/poa.json @@ -0,0 +1,804 @@ +{ + "config": { + "chainId": 15470, + "homesteadBlock": 0, + "eip150Block": 20, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 40, + "eip158Block": 40, + "byzantiumBlock": 60, + "constantinopleBlock": 80, + "petersburgBlock": 100, + "istanbulBlock": 120, + "berlinBlock": 140, + "londonBlock": 160, + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "nonce": "0x0", + "timestamp": "0x61279291", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000728bb68502bfcd91ce4c7a692a0c0773ced5cff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x47b760", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000001": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000002": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000003": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000004": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000005": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000006": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000007": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000008": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000009": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000010": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000011": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000012": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000013": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000014": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000015": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000016": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000017": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000018": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000019": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000020": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000021": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000022": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000023": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000024": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000025": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000026": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000027": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000028": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000029": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000030": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000031": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000032": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000033": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000034": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000035": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000036": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000037": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000038": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000039": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000040": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000041": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000042": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000043": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000044": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000045": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000046": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000047": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000048": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000049": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000050": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000051": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000052": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000053": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000054": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000055": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000056": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000057": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000058": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000059": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000060": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000061": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000062": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000063": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000064": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000065": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000066": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000067": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000068": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000069": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000070": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000071": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000072": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000073": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000074": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000075": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000076": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000077": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000078": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000079": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000080": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000081": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000082": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000083": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000084": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000085": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000086": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000087": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000088": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000089": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000090": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000091": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000092": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000093": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000094": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000095": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000096": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000097": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000098": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000099": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009f": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000aa": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ab": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ac": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ad": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ae": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000af": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ba": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000be": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bf": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ca": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ce": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cf": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000da": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000db": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000dc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000dd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000de": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000df": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ea": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000eb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ec": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ed": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ee": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ef": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fa": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fe": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ff": { + "balance": "0x1" + }, + "728bb68502bfcd91ce4c7a692a0c0773ced5cff0": { + "balance": "0x200000000000000000000000000000000000000000000000000000000000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": null +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/post-merge-hardfork.json b/packages/web3-eth-accounts/test/fixtures/common/post-merge-hardfork.json new file mode 100644 index 00000000000..55748a721cd --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/post-merge-hardfork.json @@ -0,0 +1,44 @@ +{ + "config": { + "chainId": 1, + "homesteadBlock": 0, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "shanghaiTime": 8, + "clique": { + "period": 5, + "epoch": 30000 + }, + "terminalTotalDifficulty": 2, + "terminalTotalDifficultyPassed": true + }, + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x1C9C380", + "difficulty": "0x0", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x6d6172697573766477000000" + }, + "0x8A04d14125D0FDCDc742F4A05C051De07232EDa4": { + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a714610044578063228951181461008c578063621fd130146101a2578063c5f2892f1461022c575b600080fd5b34801561005057600080fd5b506100786004803603602081101561006757600080fd5b50356001600160e01b031916610253565b604080519115158252519081900360200190f35b6101a0600480360360808110156100a257600080fd5b8101906020810181356401000000008111156100bd57600080fd5b8201836020820111156100cf57600080fd5b803590602001918460018302840111640100000000831117156100f157600080fd5b91939092909160208101903564010000000081111561010f57600080fd5b82018360208201111561012157600080fd5b8035906020019184600183028401116401000000008311171561014357600080fd5b91939092909160208101903564010000000081111561016157600080fd5b82018360208201111561017357600080fd5b8035906020019184600183028401116401000000008311171561019557600080fd5b91935091503561028a565b005b3480156101ae57600080fd5b506101b7610ce6565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101f15781810151838201526020016101d9565b50505050905090810190601f16801561021e5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561023857600080fd5b50610241610cf8565b60408051918252519081900360200190f35b60006001600160e01b031982166301ffc9a760e01b148061028457506001600160e01b03198216638564090760e01b145b92915050565b603086146102c95760405162461bcd60e51b81526004018080602001828103825260268152602001806112516026913960400191505060405180910390fd5b602084146103085760405162461bcd60e51b81526004018080602001828103825260368152602001806111e86036913960400191505060405180910390fd5b606082146103475760405162461bcd60e51b81526004018080602001828103825260298152602001806112c46029913960400191505060405180910390fd5b670de0b6b3a764000034101561038e5760405162461bcd60e51b815260040180806020018281038252602681526020018061129e6026913960400191505060405180910390fd5b633b9aca003406156103d15760405162461bcd60e51b815260040180806020018281038252603381526020018061121e6033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff81111561041f5760405162461bcd60e51b81526004018080602001828103825260278152602001806112776027913960400191505060405180910390fd5b606061042a82610fc6565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a61045f602054610fc6565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f01601f191690910187810386528c815260200190508c8c808284376000838201819052601f909101601f191690920188810386528c5181528c51602091820193918e019250908190849084905b838110156104f65781810151838201526020016104de565b50505050905090810190601f1680156105235780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f909101601f19169092018881038452895181528951602091820193918b019250908190849084905b8381101561057f578181015183820152602001610567565b50505050905090810190601f1680156105ac5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284376fffffffffffffffffffffffffffffffff199094169190930190815260408051600f19818403018152601090920190819052815191955093508392506020850191508083835b602083106106415780518252601f199092019160209182019101610622565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610680573d6000803e3d6000fd5b5050506040513d602081101561069557600080fd5b5051905060006002806106ab6040848a8c61114a565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106107015780518252601f1990920191602091820191016106e2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610740573d6000803e3d6000fd5b5050506040513d602081101561075557600080fd5b50516002610766896040818d61114a565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106107c15780518252601f1990920191602091820191016107a2565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610800573d6000803e3d6000fd5b5050506040513d602081101561081557600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b6020831061086b5780518252601f19909201916020918201910161084c565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa1580156108aa573d6000803e3d6000fd5b5050506040513d60208110156108bf57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b6020831061092e5780518252601f19909201916020918201910161090f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa15801561096d573d6000803e3d6000fd5b5050506040513d602081101561098257600080fd5b50516040518651600291889160009188916020918201918291908601908083835b602083106109c25780518252601f1990920191602091820191016109a3565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610a495780518252601f199092019160209182019101610a2a565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610a88573d6000803e3d6000fd5b5050506040513d6020811015610a9d57600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610af35780518252601f199092019160209182019101610ad4565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610b32573d6000803e3d6000fd5b5050506040513d6020811015610b4757600080fd5b50519050858114610b895760405162461bcd60e51b81526004018080602001828103825260548152602001806111946054913960600191505060405180910390fd5b60205463ffffffff11610bcd5760405162461bcd60e51b81526004018080602001828103825260218152602001806111736021913960400191505060405180910390fd5b602080546001019081905560005b6020811015610cda578160011660011415610c0d578260008260208110610bfe57fe5b015550610cdd95505050505050565b600260008260208110610c1c57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610c745780518252601f199092019160209182019101610c55565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610cb3573d6000803e3d6000fd5b5050506040513d6020811015610cc857600080fd5b50519250600282049150600101610bdb565b50fe5b50505050505050565b6060610cf3602054610fc6565b905090565b6020546000908190815b6020811015610ea9578160011660011415610ddb57600260008260208110610d2657fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610d7e5780518252601f199092019160209182019101610d5f565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610dbd573d6000803e3d6000fd5b5050506040513d6020811015610dd257600080fd5b50519250610e9b565b60028360218360208110610deb57fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b60208310610e425780518252601f199092019160209182019101610e23565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610e81573d6000803e3d6000fd5b5050506040513d6020811015610e9657600080fd5b505192505b600282049150600101610d02565b50600282610eb8602054610fc6565b600060401b6040516020018084815260200183805190602001908083835b60208310610ef55780518252601f199092019160209182019101610ed6565b51815160209384036101000a600019018019909216911617905267ffffffffffffffff199590951692019182525060408051808303600719018152601890920190819052815191955093508392850191508083835b60208310610f695780518252601f199092019160209182019101610f4a565b51815160209384036101000a60001901801990921691161790526040519190930194509192505080830381855afa158015610fa8573d6000803e3d6000fd5b5050506040513d6020811015610fbd57600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b8260008151811061100057fe5b60200101906001600160f81b031916908160001a9053508060061a60f81b8260018151811061102b57fe5b60200101906001600160f81b031916908160001a9053508060051a60f81b8260028151811061105657fe5b60200101906001600160f81b031916908160001a9053508060041a60f81b8260038151811061108157fe5b60200101906001600160f81b031916908160001a9053508060031a60f81b826004815181106110ac57fe5b60200101906001600160f81b031916908160001a9053508060021a60f81b826005815181106110d757fe5b60200101906001600160f81b031916908160001a9053508060011a60f81b8260068151811061110257fe5b60200101906001600160f81b031916908160001a9053508060001a60f81b8260078151811061112d57fe5b60200101906001600160f81b031916908160001a90535050919050565b60008085851115611159578182fd5b83861115611165578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a164736f6c634300060b000a", + "balance": "0x0" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x7" +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/post-merge.json b/packages/web3-eth-accounts/test/fixtures/common/post-merge.json new file mode 100644 index 00000000000..8b5da63e3f7 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/post-merge.json @@ -0,0 +1,35 @@ +{ + "config": { + "chainId": 1, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "muirGlacierBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "clique": { + "period": 5, + "epoch": 30000 + }, + "terminalTotalDifficulty": 0 + }, + "nonce": "0x42", + "timestamp": "0x0", + "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x1C9C380", + "difficulty": "0x400000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { "balance": "0x6d6172697573766477000000" } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": "0x7" +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/shanghai-time.json b/packages/web3-eth-accounts/test/fixtures/common/shanghai-time.json new file mode 100644 index 00000000000..c5848d151a3 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/shanghai-time.json @@ -0,0 +1,853 @@ +{ + "config": { + "chainId": 1337803, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeForkBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 1668699476, + "terminalTotalDifficulty": 9 + }, + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0xE7c180eAdA8f60D63e9671867b2e0CA2649207A8": { + "balance": "1000000000000000000000000000" + }, + "0xD84044e7ba939A4a9b35aE427553F39c2B2f26A4": { + "balance": "1000000000000000000000000000" + }, + "0x90c91d6742113a07484cc1E2D4Ba1Fa3AB59aD16": { + "balance": "1000000000000000000000000000" + }, + "0xE0B1b0408471cb254a82B6367caB9c8C5A9B3795": { + "balance": "1000000000000000000000000000" + }, + "0x4ee57bc5947456eBB2E06Dd47e2614Cbed39b6Bc": { + "balance": "1000000000000000000000000000" + }, + "0x191db72a1700646167a40593e6DF44267Fd481Bf": { + "balance": "1000000000000000000000000000" + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x01", + "extraData": "", + "gasLimit": "0x400000", + "nonce": "0x1234", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "1668697340" +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/testnet.json b/packages/web3-eth-accounts/test/fixtures/common/testnet.json new file mode 100644 index 00000000000..5062cb7ab4e --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/testnet.json @@ -0,0 +1,56 @@ +{ + "name": "testnet", + "chainId": 12345, + "networkId": 12345, + "defaultHardfork": "byzantium", + "consensus": { + "type": "pow", + "algorithm": "ethash" + }, + "comment": "Private test network", + "url": "[TESTNET_URL]", + "genesis": { + "gasLimit": 1000000, + "difficulty": 1, + "nonce": "0xbb00000000000000", + "extraData": "0xcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0 + }, + { + "name": "homestead", + "block": 1 + }, + { + "name": "tangerineWhistle", + "block": 2 + }, + { + "name": "spuriousDragon", + "block": 3 + }, + { + "name": "byzantium", + "block": 4 + } + ], + "bootstrapNodes": [ + { + "ip": "10.0.0.1", + "port": 30303, + "id": "11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + }, + { + "ip": "10.0.0.2", + "port": 30303, + "id": "22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + } + ] +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/testnet2.json b/packages/web3-eth-accounts/test/fixtures/common/testnet2.json new file mode 100644 index 00000000000..44b5b2dab4d --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/testnet2.json @@ -0,0 +1,60 @@ +{ + "name": "testnet2", + "chainId": 22222, + "networkId": 22222, + "defaultHardfork": "istanbul", + "consensus": { + "type": "poa", + "algorithm": "clique", + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "comment": "Private test network", + "url": "[TESTNET_URL]", + "genesis": { + "gasLimit": 1000000, + "difficulty": 1, + "nonce": "0xbb00000000000000", + "extraData": "0xcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0 + }, + { + "name": "homestead", + "block": 1 + }, + { + "name": "tangerineWhistle", + "block": 2 + }, + { + "name": "spuriousDragon", + "block": 3 + }, + { + "name": "istanbul", + "block": 10 + } + ], + "bootstrapNodes": [ + { + "ip": "10.0.0.1", + "port": 30303, + "id": "11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + }, + { + "ip": "10.0.0.2", + "port": 30303, + "id": "22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + } + ] +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/testnet3.json b/packages/web3-eth-accounts/test/fixtures/common/testnet3.json new file mode 100644 index 00000000000..dafaa9c32e5 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/testnet3.json @@ -0,0 +1,60 @@ +{ + "name": "testnet3", + "chainId": 33333, + "networkId": 33333, + "defaultHardfork": "istanbul", + "consensus": { + "type": "poa", + "algorithm": "clique", + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "comment": "Private test network", + "url": "[TESTNET_URL]", + "genesis": { + "gasLimit": 1000000, + "difficulty": 1, + "nonce": "0xbb00000000000000", + "extraData": "0xcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + "hardforks": [ + { + "name": "chainstart", + "block": 0 + }, + { + "name": "homestead", + "block": 1 + }, + { + "name": "tangerineWhistle", + "block": 2 + }, + { + "name": "spuriousDragon", + "block": 3 + }, + { + "name": "istanbul", + "block": 10 + } + ], + "bootstrapNodes": [ + { + "ip": "10.0.0.1", + "port": 30303, + "id": "11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + }, + { + "ip": "10.0.0.2", + "port": 30303, + "id": "22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "location": "", + "comment": "" + } + ] +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/testnetValid.json b/packages/web3-eth-accounts/test/fixtures/common/testnetValid.json new file mode 100644 index 00000000000..522990e3d6d --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/testnetValid.json @@ -0,0 +1,814 @@ +{ + "config": { + "chainId": 5, + "homesteadBlock": 0, + "daoForkSupport": true, + "eip150Block": 0, + "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 1561651, + "berlinBlock": 4460644, + "londonBlock": 5062605, + "clique": { + "period": 15, + "epoch": 30000 + } + }, + "nonce": "0x042", + "timestamp": "0x5c51a607", + "extraData": "0x22466c6578692069732061207468696e6722202d204166726900000000000000e0a2bd4258d2768837baa26a28fe71dc079f84c70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0xa00000", + "difficulty": "0x1", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "alloc": { + "0000000000000000000000000000000000000000": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000001": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000002": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000003": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000004": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000005": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000006": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000007": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000008": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000009": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000000f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000010": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000011": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000012": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000013": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000014": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000015": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000016": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000017": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000018": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000019": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000001f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000020": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000021": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000022": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000023": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000024": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000025": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000026": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000027": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000028": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000029": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000002f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000030": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000031": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000032": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000033": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000034": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000035": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000036": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000037": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000038": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000039": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000003f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000040": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000041": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000042": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000043": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000044": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000045": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000046": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000047": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000048": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000049": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000004f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000050": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000051": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000052": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000053": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000054": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000055": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000056": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000057": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000058": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000059": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000005f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000060": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000061": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000062": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000063": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000064": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000065": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000066": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000067": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000068": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000069": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000006f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000070": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000071": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000072": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000073": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000074": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000075": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000076": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000077": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000078": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000079": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000007f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000080": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000081": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000082": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000083": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000084": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000085": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000086": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000087": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000088": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000089": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000008f": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000090": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000091": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000092": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000093": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000094": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000095": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000096": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000097": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000098": { + "balance": "0x1" + }, + "0000000000000000000000000000000000000099": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009a": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009b": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009c": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009d": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009e": { + "balance": "0x1" + }, + "000000000000000000000000000000000000009f": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000a9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000aa": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ab": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ac": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ad": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ae": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000af": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000b9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ba": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000be": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000bf": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000c9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ca": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ce": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000cf": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000d9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000da": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000db": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000dc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000dd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000de": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000df": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000e9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ea": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000eb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ec": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ed": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ee": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ef": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f0": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f1": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f2": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f3": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f4": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f5": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f6": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f7": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f8": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000f9": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fa": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fb": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fc": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fd": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000fe": { + "balance": "0x1" + }, + "00000000000000000000000000000000000000ff": { + "balance": "0x1" + }, + "4c2ae482593505f0163cdefc073e81c63cda4107": { + "balance": "0x152d02c7e14af6800000" + }, + "a8e8f14732658e4b51e8711931053a8a69baf2b1": { + "balance": "0x152d02c7e14af6800000" + }, + "d9a5179f091d85051d3c982785efd1455cec8699": { + "balance": "0x84595161401484a000000" + }, + "e0a2bd4258d2768837baa26a28fe71dc079f84c7": { + "balance": "0x4a47e3c12448f4ad000000" + } + }, + "number": "0x0", + "gasUsed": "0x0", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas": null +} diff --git a/packages/web3-eth-accounts/test/fixtures/common/withdrawals-devnet.json b/packages/web3-eth-accounts/test/fixtures/common/withdrawals-devnet.json new file mode 100644 index 00000000000..c5848d151a3 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/common/withdrawals-devnet.json @@ -0,0 +1,853 @@ +{ + "config": { + "chainId": 1337803, + "homesteadBlock": 0, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeForkBlock": 0, + "arrowGlacierBlock": 0, + "grayGlacierBlock": 0, + "shanghaiTime": 1668699476, + "terminalTotalDifficulty": 9 + }, + "alloc": { + "0x0000000000000000000000000000000000000000": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000001": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000002": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000003": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000004": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000005": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000006": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000007": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000008": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000009": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000000f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000010": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000011": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000012": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000013": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000014": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000015": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000016": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000017": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000018": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000019": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000001f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000020": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000021": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000022": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000023": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000024": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000025": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000026": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000027": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000028": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000029": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000002f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000030": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000031": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000032": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000033": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000034": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000035": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000036": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000037": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000038": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000039": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000003f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000040": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000041": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000042": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000043": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000044": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000045": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000046": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000047": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000048": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000049": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000004f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000050": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000051": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000052": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000053": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000054": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000055": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000056": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000057": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000058": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000059": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000005f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000060": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000061": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000062": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000063": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000064": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000065": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000066": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000067": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000068": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000069": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000006f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000070": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000071": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000072": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000073": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000074": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000075": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000076": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000077": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000078": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000079": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000007f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000080": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000081": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000082": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000083": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000084": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000085": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000086": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000087": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000088": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000089": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000008f": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000090": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000091": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000092": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000093": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000094": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000095": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000096": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000097": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000098": { + "balance": "1" + }, + "0x0000000000000000000000000000000000000099": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009a": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009b": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009c": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009d": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009e": { + "balance": "1" + }, + "0x000000000000000000000000000000000000009f": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000a9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000aa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ab": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ac": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ad": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ae": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000af": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000b9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ba": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000be": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000bf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000c9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ca": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ce": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000cf": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000d9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000da": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000db": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000dd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000de": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000df": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000e9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ea": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000eb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ec": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ed": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ee": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ef": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f0": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f1": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f2": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f3": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f4": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f5": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f6": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f7": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f8": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000f9": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fa": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fb": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fc": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fd": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000fe": { + "balance": "1" + }, + "0x00000000000000000000000000000000000000ff": { + "balance": "1" + }, + "0x4242424242424242424242424242424242424242": { + "balance": "0", + "code": "0x60806040526004361061003f5760003560e01c806301ffc9a71461004457806322895118146100a4578063621fd130146101ba578063c5f2892f14610244575b600080fd5b34801561005057600080fd5b506100906004803603602081101561006757600080fd5b50357fffffffff000000000000000000000000000000000000000000000000000000001661026b565b604080519115158252519081900360200190f35b6101b8600480360360808110156100ba57600080fd5b8101906020810181356401000000008111156100d557600080fd5b8201836020820111156100e757600080fd5b8035906020019184600183028401116401000000008311171561010957600080fd5b91939092909160208101903564010000000081111561012757600080fd5b82018360208201111561013957600080fd5b8035906020019184600183028401116401000000008311171561015b57600080fd5b91939092909160208101903564010000000081111561017957600080fd5b82018360208201111561018b57600080fd5b803590602001918460018302840111640100000000831117156101ad57600080fd5b919350915035610304565b005b3480156101c657600080fd5b506101cf6110b5565b6040805160208082528351818301528351919283929083019185019080838360005b838110156102095781810151838201526020016101f1565b50505050905090810190601f1680156102365780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561025057600080fd5b506102596110c7565b60408051918252519081900360200190f35b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a70000000000000000000000000000000000000000000000000000000014806102fe57507fffffffff0000000000000000000000000000000000000000000000000000000082167f8564090700000000000000000000000000000000000000000000000000000000145b92915050565b6030861461035d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118056026913960400191505060405180910390fd5b602084146103b6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252603681526020018061179c6036913960400191505060405180910390fd5b6060821461040f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260298152602001806118786029913960400191505060405180910390fd5b670de0b6b3a7640000341015610470576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260268152602001806118526026913960400191505060405180910390fd5b633b9aca003406156104cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260338152602001806117d26033913960400191505060405180910390fd5b633b9aca00340467ffffffffffffffff811115610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602781526020018061182b6027913960400191505060405180910390fd5b6060610540826114ba565b90507f649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c589898989858a8a6105756020546114ba565b6040805160a0808252810189905290819060208201908201606083016080840160c085018e8e80828437600083820152601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690910187810386528c815260200190508c8c808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01690920188810386528c5181528c51602091820193918e019250908190849084905b83811015610648578181015183820152602001610630565b50505050905090810190601f1680156106755780820380516001836020036101000a031916815260200191505b5086810383528881526020018989808284376000838201819052601f9091017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169092018881038452895181528951602091820193918b019250908190849084905b838110156106ef5781810151838201526020016106d7565b50505050905090810190601f16801561071c5780820380516001836020036101000a031916815260200191505b509d505050505050505050505050505060405180910390a1600060028a8a600060801b604051602001808484808284377fffffffffffffffffffffffffffffffff0000000000000000000000000000000090941691909301908152604080517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0818403018152601090920190819052815191955093508392506020850191508083835b602083106107fc57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016107bf565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610859573d6000803e3d6000fd5b5050506040513d602081101561086e57600080fd5b5051905060006002806108846040848a8c6116fe565b6040516020018083838082843780830192505050925050506040516020818303038152906040526040518082805190602001908083835b602083106108f857805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016108bb565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610955573d6000803e3d6000fd5b5050506040513d602081101561096a57600080fd5b5051600261097b896040818d6116fe565b60405160009060200180848480828437919091019283525050604080518083038152602092830191829052805190945090925082918401908083835b602083106109f457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe090920191602091820191016109b7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610a51573d6000803e3d6000fd5b5050506040513d6020811015610a6657600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610ada57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610a9d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610b37573d6000803e3d6000fd5b5050506040513d6020811015610b4c57600080fd5b50516040805160208101858152929350600092600292839287928f928f92018383808284378083019250505093505050506040516020818303038152906040526040518082805190602001908083835b60208310610bd957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610b9c565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610c36573d6000803e3d6000fd5b5050506040513d6020811015610c4b57600080fd5b50516040518651600291889160009188916020918201918291908601908083835b60208310610ca957805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610c6c565b6001836020036101000a0380198251168184511680821785525050505050509050018367ffffffffffffffff191667ffffffffffffffff1916815260180182815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310610d4e57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610d11565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610dab573d6000803e3d6000fd5b5050506040513d6020811015610dc057600080fd5b5051604080516020818101949094528082019290925280518083038201815260609092019081905281519192909182918401908083835b60208310610e3457805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610df7565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015610e91573d6000803e3d6000fd5b5050506040513d6020811015610ea657600080fd5b50519050858114610f02576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260548152602001806117486054913960600191505060405180910390fd5b60205463ffffffff11610f60576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260218152602001806117276021913960400191505060405180910390fd5b602080546001019081905560005b60208110156110a9578160011660011415610fa0578260008260208110610f9157fe5b0155506110ac95505050505050565b600260008260208110610faf57fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061102557805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101610fe8565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa158015611082573d6000803e3d6000fd5b5050506040513d602081101561109757600080fd5b50519250600282049150600101610f6e565b50fe5b50505050505050565b60606110c26020546114ba565b905090565b6020546000908190815b60208110156112f05781600116600114156111e6576002600082602081106110f557fe5b01548460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061116b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161112e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156111c8573d6000803e3d6000fd5b5050506040513d60208110156111dd57600080fd5b505192506112e2565b600283602183602081106111f657fe5b015460405160200180838152602001828152602001925050506040516020818303038152906040526040518082805190602001908083835b6020831061126b57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161122e565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa1580156112c8573d6000803e3d6000fd5b5050506040513d60208110156112dd57600080fd5b505192505b6002820491506001016110d1565b506002826112ff6020546114ba565b600060401b6040516020018084815260200183805190602001908083835b6020831061135a57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909201916020918201910161131d565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790527fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000095909516920191825250604080518083037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8018152601890920190819052815191955093508392850191508083835b6020831061143f57805182527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09092019160209182019101611402565b51815160209384036101000a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161790526040519190930194509192505080830381855afa15801561149c573d6000803e3d6000fd5b5050506040513d60208110156114b157600080fd5b50519250505090565b60408051600880825281830190925260609160208201818036833701905050905060c082901b8060071a60f81b826000815181106114f457fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060061a60f81b8260018151811061153757fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060051a60f81b8260028151811061157a57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060041a60f81b826003815181106115bd57fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060031a60f81b8260048151811061160057fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060021a60f81b8260058151811061164357fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060011a60f81b8260068151811061168657fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053508060001a60f81b826007815181106116c957fe5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050919050565b6000808585111561170d578182fd5b83861115611719578182fd5b505082019391909203915056fe4465706f736974436f6e74726163743a206d65726b6c6520747265652066756c6c4465706f736974436f6e74726163743a207265636f6e7374727563746564204465706f7369744461746120646f6573206e6f74206d6174636820737570706c696564206465706f7369745f646174615f726f6f744465706f736974436f6e74726163743a20696e76616c6964207769746864726177616c5f63726564656e7469616c73206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c7565206e6f74206d756c7469706c65206f6620677765694465706f736974436f6e74726163743a20696e76616c6964207075626b6579206c656e6774684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f20686967684465706f736974436f6e74726163743a206465706f7369742076616c756520746f6f206c6f774465706f736974436f6e74726163743a20696e76616c6964207369676e6174757265206c656e677468a26469706673582212201dd26f37a621703009abf16e77e69c93dc50c79db7f6cc37543e3e0e3decdc9764736f6c634300060b0033", + "storage": { + "0x0000000000000000000000000000000000000000000000000000000000000022": "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", + "0x0000000000000000000000000000000000000000000000000000000000000023": "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", + "0x0000000000000000000000000000000000000000000000000000000000000024": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", + "0x0000000000000000000000000000000000000000000000000000000000000025": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", + "0x0000000000000000000000000000000000000000000000000000000000000026": "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", + "0x0000000000000000000000000000000000000000000000000000000000000027": "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", + "0x0000000000000000000000000000000000000000000000000000000000000028": "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", + "0x0000000000000000000000000000000000000000000000000000000000000029": "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", + "0x000000000000000000000000000000000000000000000000000000000000002a": "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", + "0x000000000000000000000000000000000000000000000000000000000000002b": "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", + "0x000000000000000000000000000000000000000000000000000000000000002c": "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", + "0x000000000000000000000000000000000000000000000000000000000000002d": "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", + "0x000000000000000000000000000000000000000000000000000000000000002e": "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", + "0x000000000000000000000000000000000000000000000000000000000000002f": "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", + "0x0000000000000000000000000000000000000000000000000000000000000030": "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", + "0x0000000000000000000000000000000000000000000000000000000000000031": "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", + "0x0000000000000000000000000000000000000000000000000000000000000032": "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", + "0x0000000000000000000000000000000000000000000000000000000000000033": "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", + "0x0000000000000000000000000000000000000000000000000000000000000034": "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", + "0x0000000000000000000000000000000000000000000000000000000000000035": "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", + "0x0000000000000000000000000000000000000000000000000000000000000036": "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", + "0x0000000000000000000000000000000000000000000000000000000000000037": "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", + "0x0000000000000000000000000000000000000000000000000000000000000038": "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", + "0x0000000000000000000000000000000000000000000000000000000000000039": "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", + "0x000000000000000000000000000000000000000000000000000000000000003a": "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", + "0x000000000000000000000000000000000000000000000000000000000000003b": "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", + "0x000000000000000000000000000000000000000000000000000000000000003c": "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", + "0x000000000000000000000000000000000000000000000000000000000000003d": "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", + "0x000000000000000000000000000000000000000000000000000000000000003e": "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", + "0x000000000000000000000000000000000000000000000000000000000000003f": "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", + "0x0000000000000000000000000000000000000000000000000000000000000040": "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7" + } + }, + "0xE7c180eAdA8f60D63e9671867b2e0CA2649207A8": { + "balance": "1000000000000000000000000000" + }, + "0xD84044e7ba939A4a9b35aE427553F39c2B2f26A4": { + "balance": "1000000000000000000000000000" + }, + "0x90c91d6742113a07484cc1E2D4Ba1Fa3AB59aD16": { + "balance": "1000000000000000000000000000" + }, + "0xE0B1b0408471cb254a82B6367caB9c8C5A9B3795": { + "balance": "1000000000000000000000000000" + }, + "0x4ee57bc5947456eBB2E06Dd47e2614Cbed39b6Bc": { + "balance": "1000000000000000000000000000" + }, + "0x191db72a1700646167a40593e6DF44267Fd481Bf": { + "balance": "1000000000000000000000000000" + } + }, + "coinbase": "0x0000000000000000000000000000000000000000", + "difficulty": "0x01", + "extraData": "", + "gasLimit": "0x400000", + "nonce": "0x1234", + "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "1668697340" +} diff --git a/packages/web3-eth-accounts/test/fixtures/json/eip1559.json b/packages/web3-eth-accounts/test/fixtures/json/eip1559.json new file mode 100644 index 00000000000..3d0285b3fb5 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/eip1559.json @@ -0,0 +1,102 @@ +[ + { + "nonce": 819, + "value": 43203529, + "gasLimit": 35552, + "maxPriorityFeePerGas": 75853, + "maxFeePerGas": 121212, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87102f86e048203338301284d8301d97c828ae094000000000000000000000000000000000000aaaa8402933bc980c080a00f924cb68412c8f1cfd74d9b581c71eeaf94fff6abdde3e5b02ca6b2931dcf47a07dd1c50027c3e31f8b565e25ce68a5072110f61fce5eee81b195dd51273c2f83" + }, + { + "nonce": 353, + "value": 61901619, + "gasLimit": 32593, + "maxPriorityFeePerGas": 38850, + "maxFeePerGas": 136295, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87002f86d048201618297c283021467827f5194000000000000000000000000000000000000aaaa8403b08b3380c080a08caf712f72489da6f1a634b651b4b1c7d9be7d1e8d05ea76c1eccee3bdfb86a5a06aecc106f588ce51e112f5e9ea7aba3e089dc7511718821d0e0cd52f52af4e45" + }, + { + "nonce": 985, + "value": 32531825, + "gasLimit": 68541, + "maxPriorityFeePerGas": 66377, + "maxFeePerGas": 136097, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87202f86f048203d983010349830213a183010bbd94000000000000000000000000000000000000aaaa8401f0657180c001a08c03a86e85789ee9a1b42fa0a86d316fca262694f8c198df11f194678c2c2d35a028f8e7de02b35014a17b6d28ff8c7e7be6860e7265ac162fb721f1aeae75643c" + }, + { + "nonce": 623, + "value": 21649799, + "gasLimit": 57725, + "maxPriorityFeePerGas": 74140, + "maxFeePerGas": 81173, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87102f86e0482026f8301219c83013d1582e17d94000000000000000000000000000000000000aaaa84014a598780c001a0b87c4c8c505d2d692ac77ba466547e79dd60fe7ecd303d520bf6e8c7085e3182a06dc7d00f5e68c3f3ebe8ae35a90d46051afde620ac12e43cae9560a29b13e7fb" + }, + { + "nonce": 972, + "value": 94563383, + "gasLimit": 65254, + "maxPriorityFeePerGas": 42798, + "maxFeePerGas": 103466, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87002f86d048203cc82a72e8301942a82fee694000000000000000000000000000000000000aaaa8405a2ec3780c001a006cf07af78c187db104496c58d679f37fcd2d5790970cecf9a59fe4a5321b375a039f3faafc71479d283a5b1e66a86b19c4bdc516655d89dbe57d9747747c01dfe" + }, + { + "nonce": 588, + "value": 99359647, + "gasLimit": 37274, + "maxPriorityFeePerGas": 87890, + "maxFeePerGas": 130273, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87102f86e0482024c830157528301fce182919a94000000000000000000000000000000000000aaaa8405ec1b9f80c080a03e2f59ac9ca852034c2c1da35a742ca19fdd910aa5d2ed49ab8ad27a2fcb2b10a03ac1c29c26723c58f91400fb6dfb5f5b837467b1c377541b47dae474dddbe469" + }, + { + "nonce": 900, + "value": 30402257, + "gasLimit": 76053, + "maxPriorityFeePerGas": 8714, + "maxFeePerGas": 112705, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87102f86e0482038482220a8301b8418301291594000000000000000000000000000000000000aaaa8401cfe6d180c001a0f7ffc5bca2512860f8236360159bf303dcfab71546b6a0032df0306f3739d0c4a05d38fe2c4edebdc1edc157034f780c53a0e5ae089e57220745bd48bcb10cdf87" + }, + { + "nonce": 709, + "value": 6478043, + "gasLimit": 28335, + "maxPriorityFeePerGas": 86252, + "maxFeePerGas": 94636, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb87002f86d048202c5830150ec830171ac826eaf94000000000000000000000000000000000000aaaa8362d8db80c001a0a61a5710512f346c9996377f7b564ccb64c73a5fdb615499adb1250498f3e01aa002d10429572cecfaa911a58bbe05f2b26e4c3aee3402202153a93692849add11" + }, + { + "nonce": 939, + "value": 2782905, + "gasLimit": 45047, + "maxPriorityFeePerGas": 45216, + "maxFeePerGas": 91648, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb86f02f86c048203ab82b0a08301660082aff794000000000000000000000000000000000000aaaa832a76b980c001a0191f0f6667a20cefc0b454e344cc01108aafbdc4e4e5ed88fdd1b5d108495b31a020879042b0f8d3807609f18fe42a9820de53c8a0ea1d0a2d50f8f5e92a94f00d" + }, + { + "nonce": 119, + "value": 65456115, + "gasLimit": 62341, + "maxPriorityFeePerGas": 24721, + "maxFeePerGas": 107729, + "to": "0x000000000000000000000000000000000000aaaa", + "privateKey": "0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63", + "signedTransactionRLP": "0xb86e02f86b04778260918301a4d182f38594000000000000000000000000000000000000aaaa8403e6c7f380c001a05e40977f4064a2bc08785e422ed8a47b56aa219abe93251d2b3b4d0cf937b8c0a071e600cd15589c3607bd9627314b99e9b5976bd427b774aa685bd0d036b1771e" + } +] diff --git a/packages/web3-eth-accounts/test/fixtures/json/eip1559txs.json b/packages/web3-eth-accounts/test/fixtures/json/eip1559txs.json new file mode 100644 index 00000000000..38a0fa7b708 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/eip1559txs.json @@ -0,0 +1,52 @@ +[ + { + "privateKey": "e0a462586887362a18a318b128dbc1e3a0cae6d4b0739f5d0419ec25114bc722", + "sendersAddress": "d13d825eb15c87b247c4c26331d66f225a5f632e", + "type": "message", + "raw": [ + "0x01", + "0x", + "0x01", + "0x01", + "0x02625a00", + "0xcccccccccccccccccccccccccccccccccccccccc", + "0x0186a0", + "0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + [ + [ + "0x0000000000000000000000000000000000000101", + [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000060a7" + ] + ] + ], + "0x01", + "0xafb6e247b1c490e284053c87ab5f6b59e219d51f743f7a4d83e400782bc7e4b9", + "0x479a268e0e0acd4de3f1e28e4fac2a6b32a4195e8dfa9d19147abe8807aa6f64" + ], + "data": { + "data": "0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x02625a00", + "maxPriorityFeePerGas": "0x01", + "maxFeePerGas": "0x01", + "nonce": "0x", + "to": "0xcccccccccccccccccccccccccccccccccccccccc", + "value": "0x0186a0", + "v": "0x01", + "r": "0xafb6e247b1c490e284053c87ab5f6b59e219d51f743f7a4d83e400782bc7e4b9", + "s": "0x479a268e0e0acd4de3f1e28e4fac2a6b32a4195e8dfa9d19147abe8807aa6f64", + "chainId": "0x01", + "accessList": [ + { + "address": "0x0000000000000000000000000000000000000101", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000060a7" + ] + } + ], + "type": "0x02" + } + } +] diff --git a/packages/web3-eth-accounts/test/fixtures/json/eip2930blockRLP.json b/packages/web3-eth-accounts/test/fixtures/json/eip2930blockRLP.json new file mode 100644 index 00000000000..498ed5f7097 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/eip2930blockRLP.json @@ -0,0 +1,3 @@ +{ + "rlp": "f90319f90211a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0e6e49996c7ec59f7a23d22b83239a60151512c65613bf84a0d7da336399ebc4aa0cafe75574d59780665a97fbfd11365c7545aa8f1abf4e5e12e8243334ef7286bb901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000083020000820200832fefd882a410845506eb0796636f6f6c65737420626c6f636b206f6e20636861696ea0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4f90101f85f800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba09bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094fa08a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b1b89e01f89b01800a8301e24194095e7baea6a6c7c4c2dfeb977efac326af552d878080f838f7940000000000000000000000000000000000000001e1a0000000000000000000000000000000000000000000000000000000000000000001a03dbacc8d0259f2508625e97fdfc57cd85fdd16e5821bc2c10bdd1a52649e8335a0476e10695b183a87b0aa292a7f4b78ef0c3fbe62aa2c42c84e1d9c3da159ef14c0" +} diff --git a/packages/web3-eth-accounts/test/fixtures/json/eip2930txs.json b/packages/web3-eth-accounts/test/fixtures/json/eip2930txs.json new file mode 100644 index 00000000000..27dc624813b --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/eip2930txs.json @@ -0,0 +1,50 @@ +[ + { + "privateKey": "e0a462586887362a18a318b128dbc1e3a0cae6d4b0739f5d0419ec25114bc722", + "sendersAddress": "d13d825eb15c87b247c4c26331d66f225a5f632e", + "type": "message", + "raw": [ + "0x01", + "0x", + "0x01", + "0x02625a00", + "0xcccccccccccccccccccccccccccccccccccccccc", + "0x0186a0", + "0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + [ + [ + "0x0000000000000000000000000000000000000101", + [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000060a7" + ] + ] + ], + "0x01", + "0xafb6e247b1c490e284053c87ab5f6b59e219d51f743f7a4d83e400782bc7e4b9", + "0x479a268e0e0acd4de3f1e28e4fac2a6b32a4195e8dfa9d19147abe8807aa6f64" + ], + "data": { + "data": "0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "gasLimit": "0x02625a00", + "gasPrice": "0x01", + "nonce": "0x", + "to": "0xcccccccccccccccccccccccccccccccccccccccc", + "value": "0x0186a0", + "v": "0x01", + "r": "0xafb6e247b1c490e284053c87ab5f6b59e219d51f743f7a4d83e400782bc7e4b9", + "s": "0x479a268e0e0acd4de3f1e28e4fac2a6b32a4195e8dfa9d19147abe8807aa6f64", + "chainId": "0x01", + "accessList": [ + { + "address": "0x0000000000000000000000000000000000000101", + "storageKeys": [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000000000000000000000000000000000000000060a7" + ] + } + ], + "type": "0x01" + } + } +] diff --git a/packages/web3-eth-accounts/test/fixtures/json/rpcTx.json b/packages/web3-eth-accounts/test/fixtures/json/rpcTx.json new file mode 100644 index 00000000000..3ddd5cea98c --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/rpcTx.json @@ -0,0 +1,21 @@ +{ + "accessList": [], + "blockHash": "0x72c897034f7b99c69f66b3b86da59877c69fdf47367603f7abe1f0676b5e8ebe", + "blockNumber": "0xec738d", + "chainId": "0x1", + "from": "0x7b0f34615564cd976fea815d9691cc102f4058d6", + "gas": "0x5208", + "gasPrice": "0x3480a01a5", + "hash": "0xed1960aa7d0d7b567c946d94331dddb37a1c67f51f30bf51f256ea40db88cfb0", + "input": "0x", + "maxFeePerGas": "0x3c2152056", + "maxPriorityFeePerGas": "0x3b9aca00", + "nonce": "0x2", + "r": "0x2c4f99fdc33af2979df594c8683efe57c4012a21a0b438284fb24577a666444f", + "s": "0x472eefae0813ff0d7235210e2697228aca35e68987038b9529beb27a3cfa8552", + "to": "0xcad621da75a66c7a8f4ff86d30a2bf981bfc8fdd", + "transactionIndex": "0x1a", + "type": "0x2", + "v": "0x1", + "value": "0x3c305ddbcbc1f5" +} diff --git a/packages/web3-eth-accounts/test/fixtures/json/ttTransactionTestEip155VitaliksTests.json b/packages/web3-eth-accounts/test/fixtures/json/ttTransactionTestEip155VitaliksTests.json new file mode 100644 index 00000000000..1188b60d3e8 --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/ttTransactionTestEip155VitaliksTests.json @@ -0,0 +1,189 @@ +[ + { + "blocknumber": "3500000", + "hash": "e0be81f8d506dbe3a5549e720b51eb79492378d6638087740824f168667e5239", + "rlp": "0xf864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "sender": "f0f6f18bca1b28cd68e4357452947e021241e9ce", + "transaction": { + "data": "", + "gasLimit": "0x5208", + "gasPrice": "0x04a817c800", + "nonce": "0x", + "r": "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "s": "0x044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x00" + } + }, + { + "blocknumber": "3500000", + "hash": "50b6e7b58320c885ab7b2ee0d0b5813a697268bd2494a06de792790b13668c08", + "rlp": "0xf867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", + "sender": "9bddad43f934d313c2b79ca28a432dd2b7281029", + "transaction": { + "data": "", + "gasLimit": "0x02e248", + "gasPrice": "0x04a817c808", + "nonce": "0x08", + "r": "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12", + "s": "0x64b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x0200" + } + }, + { + "blocknumber": "3500000", + "hash": "24fd18c70146a2b002254810473fa26b744f7899258a1f32924cc73e7a8f4d4f", + "rlp": "0xf867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "sender": "3c24d7329e92f84f08556ceb6df1cdb0104ca49f", + "transaction": { + "data": "", + "gasLimit": "0x033450", + "gasPrice": "0x04a817c809", + "nonce": "0x09", + "r": "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "s": "0x52f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x02d9" + } + }, + { + "blocknumber": "3500000", + "hash": "42973b488dbb3aa237db3d1a3bad18a8d2148af795fb6cdbbbeef5c736df97b9", + "rlp": "0xf864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "sender": "23ef145a395ea3fa3deb533b8a9e1b4c6c25d112", + "transaction": { + "data": "", + "gasLimit": "0xa410", + "gasPrice": "0x04a817c801", + "nonce": "0x01", + "r": "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bca", + "s": "0x489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x01" + } + }, + { + "blocknumber": "3500000", + "hash": "e68afed5d359c7e60a0408093da23c57b63e84acb2e368ac7c47630518d6f4d9", + "rlp": "0xf864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "sender": "2e485e0c23b4c3c542628a5f672eeab0ad4888be", + "transaction": { + "data": "", + "gasLimit": "0xf618", + "gasPrice": "0x04a817c802", + "nonce": "0x02", + "r": "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "s": "0x2d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x08" + } + }, + { + "blocknumber": "3500000", + "hash": "bcb6f653e06c276a080e9d68e5a967847a896cf52a6dc81917dc2c57ae0a31ef", + "rlp": "0xf865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", + "sender": "82a88539669a3fd524d669e858935de5e5410cf0", + "transaction": { + "data": "", + "gasLimit": "0x014820", + "gasPrice": "0x04a817c803", + "nonce": "0x03", + "r": "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0", + "s": "0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x1b" + } + }, + { + "blocknumber": "3500000", + "hash": "244e4b57522352c3e9f93ad8ac8a47d1b46c3dcda6da2522caedad009ac9afb7", + "rlp": "0xf865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", + "sender": "f9358f2538fd5ccfeb848b64a96b743fcc930554", + "transaction": { + "data": "", + "gasLimit": "0x019a28", + "gasPrice": "0x04a817c804", + "nonce": "0x04", + "r": "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063", + "s": "0x13600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x40" + } + }, + { + "blocknumber": "3500000", + "hash": "581c0b79498b1cf1b8fa4f69bc5f21c0c60371cd08d4682b15c4334aac1cccfd", + "rlp": "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "sender": "a8f7aba377317440bc5b26198a363ad22af1f3a4", + "transaction": { + "data": "", + "gasLimit": "0x01ec30", + "gasPrice": "0x04a817c805", + "nonce": "0x05", + "r": "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "s": "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x7d" + } + }, + { + "blocknumber": "3500000", + "hash": "581c0b79498b1cf1b8fa4f69bc5f21c0c60371cd08d4682b15c4334aac1cccfd", + "rlp": "0xf865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "sender": "a8f7aba377317440bc5b26198a363ad22af1f3a4", + "transaction": { + "data": "", + "gasLimit": "0x01ec30", + "gasPrice": "0x04a817c805", + "nonce": "0x05", + "r": "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "s": "0x4eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x7d" + } + }, + { + "blocknumber": "3500000", + "hash": "678ae2053a840f5fe550a63d724d1c85420d2955a0ccc4f868dd59e27afdf279", + "rlp": "0xf866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", + "sender": "f1f571dc362a0e5b2696b8e775f8491d3e50de35", + "transaction": { + "data": "", + "gasLimit": "0x023e38", + "gasPrice": "0x04a817c806", + "nonce": "0x06", + "r": "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2f", + "s": "0x6455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0xd8" + } + }, + { + "blocknumber": "3500000", + "hash": "81aa03ada1474ff3ca4b86afb8e8c0f8b22791e156e706231a695ef8c51515ab", + "rlp": "0xf867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "sender": "d37922162ab7cea97c97a87551ed02c9a38b7332", + "transaction": { + "data": "", + "gasLimit": "0x029040", + "gasPrice": "0x04a817c807", + "nonce": "0x07", + "r": "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "s": "0x52f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", + "to": "0x3535353535353535353535353535353535353535", + "v": "0x25", + "value": "0x0157" + } + } +] diff --git a/packages/web3-eth-accounts/test/fixtures/json/txs.json b/packages/web3-eth-accounts/test/fixtures/json/txs.json new file mode 100644 index 00000000000..b80abe2e23a --- /dev/null +++ b/packages/web3-eth-accounts/test/fixtures/json/txs.json @@ -0,0 +1,142 @@ +[ + { + "privateKey": "164122e5d39e9814ca723a749253663bafb07f6af91704d9754c361eb315f0c1", + "sendersAddress": "1f36f546477cda21bf2296c50976f2740247906f", + "type": "contract", + "cost": 680, + "raw": [ + "0x", + "0x09184e72a000", + "0x2710", + "0x0000000000000000000000000000000000000000", + "0x", + "0x7f7465737432000000000000000000000000000000000000000000000000000000600057", + "0x1c", + "0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab", + "0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13" + ], + "data": { + "nonce": "0x", + "gasPrice": "0x09184e72a000", + "gasLimit": "0x2710", + "to": "0x0000000000000000000000000000000000000000", + "value": "0x", + "data": "0x7f7465737432000000000000000000000000000000000000000000000000000000600057", + "v": "0x1c", + "r": "0x5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab", + "s": "0x5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13" + } + }, + { + "privateKey": "4646464646464646464646464646464646464646464646464646464646464646", + "sendersAddress": "9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f", + "type": "message", + "cost": 500, + "raw": [ + "0x09", + "0x04a817c800", + "0x2710", + "0x3535353535353535353535353535353535353535", + "0x0de0b6b3a7640000", + "0x", + "0x25", + "0x28ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276", + "0x67cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83" + ], + "data": { + "nonce": "0x09", + "gasPrice": "0x04a817c800", + "gasLimit": "0x2710", + "to": "0x3535353535353535353535353535353535353535", + "value": "0x0de0b6b3a7640000", + "data": "0x", + "v": "0x25", + "r": "0x28ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276", + "s": "0x67cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83" + } + }, + { + "privateKey": "e0a462586887362a18a318b128dbc1e3a0cae6d4b0739f5d0419ec25114bc722", + "sendersAddress": "d13d825eb15c87b247c4c26331d66f225a5f632e", + "type": "message", + "cost": 500, + "raw": [ + "0x06", + "0x09184e72a000", + "0x01f4", + "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c", + "0x016345785d8a0000", + "0x", + "0x1c", + "0x24a484bfa7380860e9fa0a9f5e4b64b985e860ca31abd36e66583f9030c2e29d", + "0x4d5ef07d9e73fa2fbfdad059591b4f13d0aa79e7634a2bb00174c9200cabb04d" + ], + "data": { + "nonce": "0x06", + "gasPrice": "0x09184e72a000", + "gasLimit": "0x01f4", + "to": "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c", + "value": "0x016345785d8a0000", + "data": "0x", + "v": "0x1c", + "r": "0x24a484bfa7380860e9fa0a9f5e4b64b985e860ca31abd36e66583f9030c2e29d", + "s": "0x4d5ef07d9e73fa2fbfdad059591b4f13d0aa79e7634a2bb00174c9200cabb04d" + } + }, + { + "privateKey": "164122e5d39e9814ca723a749253663bafb07f6af91704d9754c361eb315f0c1", + "sendersAddress": "1f36f546477cda21bf2296c50976f2740247906f", + "type": "message", + "cost": 2420, + "raw": [ + "0x06", + "0x09184e72a000", + "0x0974", + "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c", + "0x016345785d8a0000", + "0x00000000000000000000000000000000000000000000000000000000000000ad000000000000000000000000000000000000000000000000000000000000fafa0000000000000000000000000000000000000000000000000000000000000dfa0000000000000000000000000000000000000000000000000000000000000dfa00000000000000000000000000000000000000000000000000000000000000ad000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000df000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000df000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000d", + "0x1c", + "0x5e9361ca27e14f3af0e6b28466406ad8be026d3b0f2ae56e3c064043fb73ec77", + "0x29ae9893dac4f9afb1af743e25fbb6a63f7879a61437203cb48c997b0fcefc3a" + ], + "data": { + "nonce": "0x06", + "gasPrice": "0x09184e72a000", + "gasLimit": "0x0974", + "to": "0xbe862ad9abfe6f22bcb087716c7d89a26051f74c", + "value": "0x016345785d8a0000", + "data": "0x00000000000000000000000000000000000000000000000000000000000000ad000000000000000000000000000000000000000000000000000000000000fafa0000000000000000000000000000000000000000000000000000000000000dfa0000000000000000000000000000000000000000000000000000000000000dfa00000000000000000000000000000000000000000000000000000000000000ad000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000df000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000df000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000d", + "v": "0x1c", + "r": "0x5e9361ca27e14f3af0e6b28466406ad8be026d3b0f2ae56e3c064043fb73ec77", + "s": "0x29ae9893dac4f9afb1af743e25fbb6a63f7879a61437203cb48c997b0fcefc3a" + } + }, + { + "privateKey": "not-available", + "sendersAddress": "TODO", + "type": "message", + "cost": 12312, + "raw": [ + "0x0b", + "0x051f4d5c00", + "0x5208", + "0x656e929d6fc0cac52d3d9526d288fe02dcd56fbd", + "0x2386f26fc10000", + "0x", + "0x26", + "0xef903f6bbcb7d6214d478df27db6591d857b1063954eade1bb24e69e58511f96", + "0x5433f8e1abf886cbec64891f38a2ea6fd9f9ffe078421f5e238b9fec03eea97a" + ], + "data": { + "nonce": "0x0b", + "gasPrice": "0x051f4d5c00", + "gasLimit": "0x5208", + "to": "0x656e929d6fc0cac52d3d9526d288fe02dcd56fbd", + "value": "0x2386f26fc10000", + "data": "0x", + "v": "0x26", + "r": "0xef903f6bbcb7d6214d478df27db6591d857b1063954eade1bb24e69e58511f96", + "s": "0x5433f8e1abf886cbec64891f38a2ea6fd9f9ffe078421f5e238b9fec03eea97a" + } + } +] diff --git a/packages/web3-eth-accounts/test/integration/account.test.ts b/packages/web3-eth-accounts/test/integration/account.test.ts index 33500068eae..06b703e496f 100644 --- a/packages/web3-eth-accounts/test/integration/account.test.ts +++ b/packages/web3-eth-accounts/test/integration/account.test.ts @@ -15,7 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import defaultImport, * as fullImport from '@ethereumjs/tx'; import { Address } from 'web3-types'; import { Web3ValidatorError, isHexStrict } from 'web3-validator'; import { @@ -30,6 +29,7 @@ import { sign, signTransaction, } from '../../src'; +import { TransactionFactory } from '../../src/tx/transactionFactory'; import { invalidDecryptData, invalidEncryptData, @@ -45,8 +45,6 @@ import { validPrivateKeyToAddressData, } from '../fixtures/account'; -const { TransactionFactory } = defaultImport || fullImport; - describe('accounts', () => { describe('create', () => { describe('valid cases', () => { @@ -96,6 +94,7 @@ describe('accounts', () => { const account = create(); const signedResult = await signTransaction( + // eslint-disable-next-line @typescript-eslint/no-unsafe-call TransactionFactory.fromTxData(txData), account.privateKey, ); @@ -112,6 +111,7 @@ describe('accounts', () => { const account = create(); const txObj = { ...txData, from: account.address }; const signedResult = await signTransaction( + // eslint-disable-next-line @typescript-eslint/no-unsafe-call TransactionFactory.fromTxData(txObj), account.privateKey, ); diff --git a/packages/web3-eth-accounts/test/unit/account.test.ts b/packages/web3-eth-accounts/test/unit/account.test.ts index 2e70ea33f60..3bccc516b71 100644 --- a/packages/web3-eth-accounts/test/unit/account.test.ts +++ b/packages/web3-eth-accounts/test/unit/account.test.ts @@ -15,7 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import defaultImport, * as fullImport from '@ethereumjs/tx'; import { Address } from 'web3-types'; import { Web3ValidatorError, isHexStrict } from 'web3-validator'; import { @@ -44,8 +43,8 @@ import { validPrivateKeytoAccountData, validPrivateKeyToAddressData, } from '../fixtures/account'; - -const { TransactionFactory } = defaultImport || fullImport; +import { TransactionFactory } from '../../src/tx/transactionFactory'; +import { TxData } from '../../src/tx/types'; describe('accounts', () => { describe('create', () => { @@ -97,7 +96,8 @@ describe('accounts', () => { const account = create(); const signedResult = await signTransaction( - TransactionFactory.fromTxData(txData), + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + TransactionFactory.fromTxData(txData as unknown as TxData), account.privateKey, ); expect(signedResult).toBeDefined(); @@ -113,6 +113,7 @@ describe('accounts', () => { const account = create(); const txObj = { ...txData, from: account.address }; const signedResult = await signTransaction( + // eslint-disable-next-line @typescript-eslint/no-unsafe-call TransactionFactory.fromTxData(txObj), account.privateKey, ); diff --git a/packages/web3-eth-accounts/test/unit/common/chains.test.ts b/packages/web3-eth-accounts/test/unit/common/chains.test.ts new file mode 100644 index 00000000000..750ffd1bc4c --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/chains.test.ts @@ -0,0 +1,112 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, ConsensusAlgorithm, ConsensusType, Hardfork } from '../../../src/common'; + +describe('[Common/Chains]: Initialization / Chain params', () => { + it('Should initialize with chain provided', () => { + let c = new Common({ chain: 'mainnet' }); + expect(c.chainName()).toBe('mainnet'); + expect(c.chainId()).toEqual(BigInt(1)); + expect(c.networkId()).toEqual(BigInt(1)); + expect(c.hardfork()).toEqual(Hardfork.Merge); + expect(c.hardfork()).toEqual(c.DEFAULT_HARDFORK); + + c = new Common({ chain: 1 }); + expect(c.chainName()).toBe('mainnet'); + }); + + it('Should initialize with chain provided by Chain enum', () => { + const c = new Common({ chain: Chain.Mainnet }); + expect(c.chainName()).toBe('mainnet'); + expect(c.chainId()).toEqual(BigInt(1)); + expect(c.networkId()).toEqual(BigInt(1)); + expect(c.hardfork()).toEqual(Hardfork.Merge); + expect(c.hardfork()).toEqual(c.DEFAULT_HARDFORK); + }); + + it('Should initialize with chain and hardfork provided', () => { + const c = new Common({ chain: 'mainnet', hardfork: 'byzantium' }); + expect(c.hardfork()).toBe('byzantium'); + }); + + it('Should initialize with chain and hardfork provided by Chain and Hardfork enums', () => { + const c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }); + expect(c.hardfork()).toBe('byzantium'); + }); + + it('Should handle initialization errors', () => { + let f = function () { + // eslint-disable-next-line no-new + new Common({ chain: 'chainnotexisting' }); + }; + expect(f).toThrow('not supported'); // eslint-disable-line no-new + + f = function () { + // eslint-disable-next-line no-new + new Common({ chain: 'mainnet', hardfork: 'hardforknotexisting' }); + }; + expect(f).toThrow('not supported'); // eslint-disable-line no-new + }); + + it('Should provide correct access to chain parameters', () => { + let c = new Common({ chain: 'mainnet', hardfork: 'chainstart' }); + expect(c.hardforks()[3]['block']).toBe(2463000); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfWork); + expect(c.consensusAlgorithm()).toEqual(ConsensusAlgorithm.Ethash); + expect(c.consensusConfig()).toEqual({}); + + c = new Common({ chain: 'goerli', hardfork: 'chainstart' }); + expect(c.hardforks()[3]['block']).toBe(0); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfAuthority); + expect(c.consensusAlgorithm()).toEqual(ConsensusAlgorithm.Clique); + expect(c.consensusConfig().epoch).toBe(30000); + }); + + it('Should provide DNS network information in a uniform way', () => { + const configs = ['mainnet', 'goerli']; + for (const network of configs) { + const c = new Common({ chain: network }); + const dnsNetworks = c.dnsNetworks(); + expect(Array.isArray(dnsNetworks)).toBe(true); + expect(typeof dnsNetworks[0]).toBe('string'); + } + }); +}); + +describe('[Common]: isSupportedChainId static method', () => { + it('Should return true for supported chainId', () => { + expect(Common.isSupportedChainId(BigInt(1))).toBe(true); + }); + + it('Should return false for unsupported chainId', () => { + expect(Common.isSupportedChainId(BigInt(0))).toBe(false); + }); +}); + +describe('[Common]: copy()', () => { + it('listener tests', () => { + const common = new Common({ chain: 'mainnet' }); + // Add two listeners + // eslint-disable-next-line @typescript-eslint/no-empty-function + common.on('hardforkChanged', () => {}); + // eslint-disable-next-line @typescript-eslint/no-empty-function + common.on('hardforkChanged', () => {}); + const commonCopy = common.copy(); + expect(common.listenerCount('hardforkChanged')).toBe(2); + expect(commonCopy.listenerCount('hardforkChanged')).toBe(0); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/customChains.test.ts b/packages/web3-eth-accounts/test/unit/common/customChains.test.ts new file mode 100644 index 00000000000..d11094e1ed6 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/customChains.test.ts @@ -0,0 +1,166 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, ConsensusType, CustomChain, Hardfork } from '../../../src/common'; + +import * as testnet from '../../fixtures/common/testnet.json'; +import * as testnet2 from '../../fixtures/common/testnet2.json'; +import * as testnet3 from '../../fixtures/common/testnet3.json'; + +describe('[Common]: Custom chains', () => { + it('chain -> object: should provide correct access to private network chain parameters', () => { + const c = new Common({ chain: testnet, hardfork: Hardfork.Byzantium }); + expect(c.chainName()).toBe('testnet'); + expect(c.chainId()).toEqual(BigInt(12345)); + expect(c.networkId()).toEqual(BigInt(12345)); + expect(c.hardforks()[3]['block']).toBe(3); + expect(c.bootstrapNodes()![1].ip).toBe('10.0.0.2'); + }); + + it('chain -> object: should handle custom chain parameters with missing field', () => { + const chainParams = { ...testnet }; + delete (chainParams as any)['hardforks']; + expect(() => { + // eslint-disable-next-line no-new + new Common({ chain: chainParams }); + }).toThrow('Missing required'); // eslint-disable-line no-new + }); + + it('custom() -> base functionality', () => { + const mainnetCommon = new Common({ chain: Chain.Mainnet }); + + const customChainParams = { name: 'custom', chainId: 123, networkId: 678 }; + const customChainCommon = Common.custom(customChainParams, { + hardfork: Hardfork.Byzantium, + }); + + // From custom chain params + expect(customChainCommon.chainName()).toEqual(customChainParams.name); + expect(customChainCommon.chainId()).toEqual(BigInt(customChainParams.chainId)); + expect(customChainCommon.networkId()).toEqual(BigInt(customChainParams.networkId)); + + // Fallback params from mainnet + expect(customChainCommon.genesis()).toEqual(mainnetCommon.genesis()); + expect(customChainCommon.bootstrapNodes()).toEqual(mainnetCommon.bootstrapNodes()); + expect(customChainCommon.hardforks()).toEqual(mainnetCommon.hardforks()); + + // Set only to this Common + expect(customChainCommon.hardfork()).toBe('byzantium'); + }); + + it('custom() -> behavior', () => { + let common = Common.custom({ chainId: 123 }); + expect(common.networkId()).toEqual(BigInt(1)); + expect(common.chainName()).toBe('custom-chain'); + + common = Common.custom(CustomChain.PolygonMumbai); + expect(common.networkId()).toEqual(BigInt(80001)); + for (const customChain of Object.values(CustomChain)) { + common = Common.custom(customChain); + expect(common.chainName()).toEqual(customChain); + } + + common = Common.custom(CustomChain.PolygonMumbai); + expect(common.hardfork()).toEqual(common.DEFAULT_HARDFORK); + + common = Common.custom(CustomChain.OptimisticEthereum, { hardfork: Hardfork.Byzantium }); + expect(common.hardfork()).toEqual(Hardfork.Byzantium); + + expect(() => { + // @ts-expect-error TypeScript complains, nevertheless do the test for JS behavior + Common.custom('this-chain-is-not-supported'); + }).toThrow('not supported'); + }); + + it('customChains parameter: initialization exception', () => { + expect(() => { + // eslint-disable-next-line no-new + new Common({ chain: testnet, customChains: [testnet] }); + }).toThrow( + 'Chain must be a string, number, or bigint when initialized with customChains passed in', + ); + }); + + it('customChains parameter: initialization', () => { + let c = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Byzantium, + customChains: [testnet], + }); + expect(c.chainName()).toBe('mainnet'); + expect(c.hardforkBlock()!).toEqual(BigInt(4370000)); + + c.setChain('testnet'); + expect(c.chainName()).toBe('testnet'); + expect(c.hardforkBlock()!).toEqual(BigInt(4)); + + c = new Common({ + chain: 'testnet', + hardfork: Hardfork.Byzantium, + customChains: [testnet], + }); + expect(c.chainName()).toBe('testnet'); + expect(c.hardforkBlock()!).toEqual(BigInt(4)); + + const customChains = [testnet, testnet2, testnet3]; + c = new Common({ + chain: 'testnet2', + hardfork: Hardfork.Istanbul, + customChains, + }); + expect(c.chainName()).toBe('testnet2'); + expect(c.hardforkBlock()!).toEqual(BigInt(10)); + + c.setChain('testnet'); + expect(c.chainName()).toBe('testnet'); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfWork); + }); +}); + +describe('custom chain setup with hardforks', () => { + const undefinedHardforks = [ + { + name: 'chainstart', + block: 0, + }, + { name: 'homestead' }, + // eslint-disable-next-line no-null/no-null + { name: 'byzantium', block: null }, + { name: 'tangerineWhistle', block: 10 }, + ]; + it('with undefined/null block numbers', () => { + expect( + // @ts-expect-error -- Disabling type check to verify that error is thrown + () => Common.custom({ hardforks: undefinedHardforks }), + ).toThrow(); + + const nullHardforks = [ + { + name: 'chainstart', + block: 0, + }, + // eslint-disable-next-line no-null/no-null + { name: 'homestead', block: null }, + { name: 'tangerineWhistle', block: 10 }, + ]; + + const common = Common.custom({ hardforks: nullHardforks }); + common.setHardforkByBlockNumber(10); + expect('tangerineWhistle').toEqual(common.hardfork()); + common.setHardforkByBlockNumber(3); + expect('chainstart').toEqual(common.hardfork()); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/eips.test.ts b/packages/web3-eth-accounts/test/unit/common/eips.test.ts new file mode 100644 index 00000000000..9266eb037b9 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/eips.test.ts @@ -0,0 +1,78 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { toBigInt } from 'web3-utils'; +import { Chain, Common, Hardfork } from '../../../src/common'; + +describe('[Common/EIPs]: Initialization / Chain params', () => { + it('Correct initialization', () => { + let eips = [2537, 2929]; + const c = new Common({ chain: Chain.Mainnet, eips }); + expect(c.eips()).toEqual(eips); + + eips = [2718, 2929, 2930]; + expect(() => { + // eslint-disable-next-line no-new + new Common({ chain: Chain.Mainnet, eips, hardfork: Hardfork.Istanbul }); + }).not.toThrow(); + + eips = [2930]; + expect(() => { + // eslint-disable-next-line no-new + new Common({ chain: Chain.Mainnet, eips, hardfork: Hardfork.Istanbul }); + }).toThrow(); + }); + + it('Initialization errors', () => { + const UNSUPPORTED_EIP = 1000000; + const eips = [UNSUPPORTED_EIP]; + expect(() => { + // eslint-disable-next-line no-new + new Common({ chain: Chain.Mainnet, eips }); + }).toThrow('not supported'); + + /* + // Manual test since no test triggering EIP config available + // TODO: recheck on addition of new EIP configs + // To run manually change minimumHardfork in EIP2537 config to petersburg + eips = [ 2537, ] + msg = 'should throw on not meeting minimum hardfork requirements' + f = () => { + new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium, eips }) + } + st.throws(f, /minimumHardfork/, msg) + */ + }); + + it('isActivatedEIP()', () => { + let c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Istanbul }); + expect(c.isActivatedEIP(2315)).toBe(false); + c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Istanbul, eips: [2315] }); + expect(c.isActivatedEIP(2315)).toBe(true); + c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Berlin }); + expect(c.isActivatedEIP(2929)).toBe(true); + expect(c.isActivatedEIP(2315)).toBe(false); + expect(c.isActivatedEIP(2537)).toBe(false); + }); + + it('eipBlock', () => { + const c = new Common({ chain: Chain.Mainnet }); + + expect(c.eipBlock(1559)! === toBigInt(12965000)).toBe(true); + + expect(c.eipBlock(0)).toBeNull(); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/hardforks.test.ts b/packages/web3-eth-accounts/test/unit/common/hardforks.test.ts new file mode 100644 index 00000000000..9c5603c4944 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/hardforks.test.ts @@ -0,0 +1,344 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, ConsensusAlgorithm, ConsensusType, Hardfork } from '../../../src/common'; +import gethGenesisKiln from '../../fixtures/common/geth-genesis-kiln.json'; + +describe('[Common]: Hardfork logic', () => { + it('Hardfork access', () => { + const supportedHardforks = [ + Hardfork.Chainstart, + Hardfork.Homestead, + Hardfork.Dao, + Hardfork.Chainstart, + Hardfork.SpuriousDragon, + Hardfork.Byzantium, + Hardfork.Constantinople, + Hardfork.Petersburg, + Hardfork.Istanbul, + Hardfork.Berlin, + Hardfork.London, + Hardfork.ArrowGlacier, + Hardfork.GrayGlacier, + Hardfork.Shanghai, + Hardfork.Merge, + ]; + let c; + + for (const hardfork of supportedHardforks) { + c = new Common({ chain: Chain.Mainnet, hardfork }); + expect(c.hardfork()).toEqual(hardfork); + } + }); + + it('getHardforkByBlockNumber() / setHardforkByBlockNumber()', () => { + let c = new Common({ chain: Chain.Mainnet }); + + expect(c.getHardforkByBlockNumber(0)).toEqual(Hardfork.Chainstart); + expect(c.getHardforkByBlockNumber(1149999)).toEqual(Hardfork.Chainstart); + expect(c.getHardforkByBlockNumber(1150000)).toEqual(Hardfork.Homestead); + expect(c.getHardforkByBlockNumber(1400000)).toEqual(Hardfork.Homestead); + expect(c.getHardforkByBlockNumber(9200000)).toEqual(Hardfork.MuirGlacier); + expect(c.getHardforkByBlockNumber(12244000)).toEqual(Hardfork.Berlin); + expect(c.getHardforkByBlockNumber(12965000)).toEqual(Hardfork.London); + expect(c.getHardforkByBlockNumber(13773000)).toEqual(Hardfork.ArrowGlacier); + expect(c.getHardforkByBlockNumber(15050000)).toEqual(Hardfork.GrayGlacier); + // merge is now specified at 15537394 in config + expect(c.getHardforkByBlockNumber(999999999999)).toEqual(Hardfork.Merge); + + expect(c.setHardforkByBlockNumber(0)).toEqual(Hardfork.Chainstart); + expect(c.setHardforkByBlockNumber(1149999)).toEqual(Hardfork.Chainstart); + expect(c.setHardforkByBlockNumber(1150000)).toEqual(Hardfork.Homestead); + expect(c.setHardforkByBlockNumber(1400000)).toEqual(Hardfork.Homestead); + expect(c.setHardforkByBlockNumber(12244000)).toEqual(Hardfork.Berlin); + expect(c.setHardforkByBlockNumber(12965000)).toEqual(Hardfork.London); + expect(c.setHardforkByBlockNumber(13773000)).toEqual(Hardfork.ArrowGlacier); + expect(c.setHardforkByBlockNumber(15050000)).toEqual(Hardfork.GrayGlacier); + // merge is now specified at 15537394 in config + expect(c.setHardforkByBlockNumber(999999999999)).toEqual(Hardfork.Merge); + + c = new Common({ chain: Chain.Sepolia }); + expect(c.setHardforkByBlockNumber(1735371)).toBe('mergeForkIdTransition'); + }); + + it('should throw if no hardfork qualifies', () => { + const hardforks = [ + { + name: 'homestead', + block: 3, + }, + { + name: 'tangerineWhistle', + block: 3, + }, + { + name: 'spuriousDragon', + block: 3, + }, + ]; + const c = Common.custom({ hardforks }, { baseChain: Chain.Sepolia }); + + expect(() => { + c.getHardforkByBlockNumber(0); + }).toThrow(); + + expect(c.setHardforkByBlockNumber(3)).toEqual(Hardfork.SpuriousDragon); + }); + + it('setHardfork(): hardforkChanged event', () => { + const c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }); + c.on('hardforkChanged', (hardfork: string) => { + expect(hardfork).toEqual(Hardfork.Byzantium); + }); + c.setHardfork(Hardfork.Byzantium); + }); + + it('hardforkBlock()', () => { + let c = new Common({ chain: Chain.Goerli }); + expect(c.hardforkBlock(Hardfork.Byzantium)!).toEqual(BigInt(0)); + + expect(c.hardforkBlock('thisHardforkDoesNotExist')).toBeNull(); + + c = new Common({ chain: Chain.Sepolia, hardfork: Hardfork.MergeForkIdTransition }); + expect(c.hardforkBlock()!).toEqual(BigInt(1735371)); + + c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }); + expect(c.hardforkBlock()!).toEqual(BigInt(9069000)); + + c = new Common({ chain: Chain.Mainnet }); + expect(c.hardforkBlock(Hardfork.Berlin)!).toEqual(BigInt(12244000)); + expect(c.hardforkBlock(Hardfork.Berlin)!).toEqual(BigInt(12244000)); + + // developer note: when Shanghai is set, + // update this test to next unscheduled hardfork. + expect(c.hardforkBlock(Hardfork.Shanghai)).toBeNull(); + expect(c.hardforkBlock(Hardfork.Shanghai)).toBeNull(); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.Shanghai)).toBeNull(); + }); + + it('isHardforkBlock()', () => { + let c = new Common({ chain: Chain.Sepolia }); + // eslint-disable-next-line deprecation/deprecation + expect(c.isHardforkBlock(1450409)).toBe(true); + // eslint-disable-next-line deprecation/deprecation + expect(c.isHardforkBlock(1735372)).toBe(false); + + c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }); + // eslint-disable-next-line deprecation/deprecation + expect(c.isHardforkBlock(4370000)).toBe(true); + // eslint-disable-next-line deprecation/deprecation + expect(c.isHardforkBlock(2463001)).toBe(false); + }); + + it('nextHardforkBlockOrTimestamp()', () => { + let c = new Common({ chain: Chain.Sepolia, hardfork: Hardfork.MergeForkIdTransition }); + expect(c.nextHardforkBlockOrTimestamp()!).toEqual(BigInt(1677557088)); + + expect(c.nextHardforkBlockOrTimestamp('mergeForkIdTransition')!).toEqual( + BigInt(1677557088), + ); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.Byzantium)!).toEqual(BigInt(1735371)); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.London)).toEqual(BigInt(1735371)); + c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Chainstart }); + expect(c.nextHardforkBlockOrTimestamp()!).toEqual(BigInt(1561651)); + }); + + it('isNextHardforkBlock()', () => { + const c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Istanbul }); + // eslint-disable-next-line deprecation/deprecation + expect(c.isNextHardforkBlock(4460644)).toBe(true); + // eslint-disable-next-line deprecation/deprecation + expect(c.isNextHardforkBlock(5062605, 'berlin')).toBe(true); + // eslint-disable-next-line deprecation/deprecation + expect(c.isNextHardforkBlock(5062605, Hardfork.Berlin)).toBe(true); + // eslint-disable-next-line deprecation/deprecation + expect(c.isNextHardforkBlock(13773000, Hardfork.Byzantium)).toBe(false); + // eslint-disable-next-line deprecation/deprecation + expect(c.isNextHardforkBlock(13773001, Hardfork.London)).toBe(false); + }); + + it('hardforkIsActiveOnBlock() / activeOnBlock()', () => { + let c = new Common({ chain: Chain.Goerli }); + expect(c.hardforkIsActiveOnBlock(Hardfork.Istanbul, 1561651)).toBe(true); + + expect(c.hardforkIsActiveOnBlock(Hardfork.London, 5062605)).toBe(true); + + expect(c.hardforkIsActiveOnBlock(Hardfork.Byzantium, 1699999)).toBe(false); + + c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.London }); + // eslint-disable-next-line no-null/no-null + expect(c.hardforkIsActiveOnBlock(null, 5062605)).toBe(true); + + expect(c.activeOnBlock(5062605)).toBe(true); + // eslint-disable-next-line no-null/no-null + expect(c.hardforkIsActiveOnBlock(null, 5062605)).toBe(true); + // eslint-disable-next-line no-null/no-null + expect(c.hardforkIsActiveOnBlock(null, 1699999)).toBe(false); + }); + + it('hardforkGteHardfork()', () => { + let c = new Common({ chain: Chain.Goerli }); + expect(c.hardforkGteHardfork(Hardfork.Constantinople, Hardfork.Byzantium)).toBe(true); + + expect(c.hardforkGteHardfork(Hardfork.Dao, Hardfork.Chainstart)).toBe(false); + + expect(c.hardforkGteHardfork(Hardfork.Byzantium, Hardfork.Byzantium)).toBe(true); + + expect(c.hardforkGteHardfork(Hardfork.SpuriousDragon, Hardfork.Byzantium)).toBe(false); + + c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Byzantium }); + // eslint-disable-next-line no-null/no-null + expect(c.hardforkGteHardfork(null, Hardfork.SpuriousDragon)).toBe(true); + + expect(c.gteHardfork(Hardfork.SpuriousDragon)).toBe(true); + // eslint-disable-next-line no-null/no-null + expect(c.hardforkGteHardfork(null, Hardfork.Byzantium)).toBe(true); + // eslint-disable-next-line no-null/no-null + expect(c.hardforkGteHardfork(null, Hardfork.Constantinople)).toBe(false); + }); + + it('hardforkGteHardfork() ropsten', () => { + const c = new Common({ chain: Chain.Goerli }); + expect(c.hardforkGteHardfork(Hardfork.SpuriousDragon, Hardfork.MuirGlacier)).toBe(false); + }); + + it('_calcForkHash()', () => { + const chains: [Chain, Buffer][] = [ + [ + Chain.Mainnet, + Buffer.from( + 'd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', + 'hex', + ), + ], + [ + Chain.Goerli, + Buffer.from( + 'bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a', + 'hex', + ), + ], + [ + Chain.Sepolia, + Buffer.from( + '25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9', + 'hex', + ), + ], + ]; + + let c = new Common({ chain: Chain.Mainnet }); + const mainnetGenesisHash = chains[0][1]; + expect(c._calcForkHash(Hardfork.Chainstart, mainnetGenesisHash)).toBe('0xfc64ec04'); + + expect(c._calcForkHash(Hardfork.Homestead, mainnetGenesisHash)).toBe('0x97c2c34c'); + + expect(c._calcForkHash(Hardfork.Byzantium, mainnetGenesisHash)).toBe('0xa00bc324'); + + for (const [chain, genesisHash] of chains) { + c = new Common({ chain }); + for (const hf of c.hardforks()) { + if (typeof hf.forkHash !== 'string') { + continue; + } + expect(c._calcForkHash(hf.name, genesisHash)).toEqual(hf.forkHash); + } + } + }); + + it('forkHash()', () => { + let c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }); + expect(c.forkHash()).toBe('0xa00bc324'); + expect(c.forkHash(Hardfork.SpuriousDragon)).toBe('0x3edd5b10'); + const genesisHash = Buffer.from( + 'd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', + 'hex', + ); + expect(c.forkHash(Hardfork.SpuriousDragon, genesisHash)).toBe('0x3edd5b10'); + + c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Shanghai }); + // unschedule shanghai on it to test + c.hardforks() + .filter(hf => hf.name === Hardfork.Shanghai) + // eslint-disable-next-line array-callback-return + .map(hf => { + // eslint-disable-next-line no-null/no-null, no-param-reassign + hf.block = null; + // eslint-disable-next-line no-param-reassign + hf.timestamp = undefined; + }); + expect(() => { + c.forkHash(Hardfork.Shanghai); + }).toThrow('No fork hash calculation possible'); + expect(() => { + c.forkHash('thisHardforkDoesNotExist'); + }).toThrow('No fork hash calculation possible'); + }); + + it('hardforkForForkHash()', () => { + const c = new Common({ chain: Chain.Mainnet }); + + const res = c.hardforkForForkHash('0x3edd5b10')!; + expect(res.name).toEqual(Hardfork.SpuriousDragon); + + expect(c.hardforkForForkHash('0x12345')).toBeNull(); + }); + + it('HF consensus updates', () => { + let c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Byzantium }); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfAuthority); + expect(c.consensusAlgorithm()).toEqual(ConsensusAlgorithm.Clique); + expect(c.consensusConfig()['period']).toBe(15); + + c = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Merge }); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfStake); + expect(c.consensusAlgorithm()).toEqual(ConsensusAlgorithm.Casper); + expect(c.consensusConfig()).toEqual({}); + }); + + it('Should correctly apply hardfork changes', () => { + // For sepolia MergeForkIdTransition happens AFTER merge + let c = new Common({ chain: Chain.Sepolia, hardfork: Hardfork.London }); + expect(c['HARDFORK_CHANGES'][11][0]).toEqual(Hardfork.Merge); + expect(c['HARDFORK_CHANGES'][12][0]).toEqual(Hardfork.MergeForkIdTransition); + + // Should give correct ConsensusType pre and post merge + expect(c.consensusType()).toEqual(ConsensusType.ProofOfWork); + c.setHardfork(Hardfork.Merge); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfStake); + c.setHardfork(Hardfork.MergeForkIdTransition); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfStake); + + // For kiln MergeForkIdTransition happens BEFORE Merge + + c = Common.fromGethGenesis(gethGenesisKiln, { + chain: 'kiln', + mergeForkIdPostMerge: false, + }); + + // MergeForkIdTransition change should be before Merge + expect(c['HARDFORK_CHANGES'][10][0]).toEqual(Hardfork.MergeForkIdTransition); + expect(c['HARDFORK_CHANGES'][11][0]).toEqual(Hardfork.Merge); + + // Should give correct ConsensusType pre and post merge + c.setHardfork(Hardfork.London); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfWork); + c.setHardfork(Hardfork.Merge); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfStake); + c.setHardfork(Hardfork.MergeForkIdTransition); + expect(c.consensusType()).toEqual(ConsensusType.ProofOfWork); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/mergePOS.test.ts b/packages/web3-eth-accounts/test/unit/common/mergePOS.test.ts new file mode 100644 index 00000000000..a2337c58c32 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/mergePOS.test.ts @@ -0,0 +1,256 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { toBigInt } from 'web3-utils'; +import { Chain, Common, Hardfork } from '../../../src/common'; + +import * as testnetMerge from '../../fixtures/common/merge/testnetMerge.json'; +import * as testnetPOS from '../../fixtures/common/merge/testnetPOS.json'; +import postMerge from '../../fixtures/common/post-merge.json'; + +describe('[Common]: Merge/POS specific logic', () => { + it('hardforkTTD()', () => { + const customChains = [testnetMerge]; + const c = new Common({ chain: 'testnetMerge', hardfork: Hardfork.Istanbul, customChains }); + expect(c.hardforkTTD(Hardfork.Merge)).toEqual(BigInt(5000)); + expect(c.hardforkTTD('thisHardforkDoesNotExist')).toBeNull(); + }); + + it('getHardforkByBlockNumber(), merge block null, with total difficulty', () => { + const customChains = [testnetMerge]; + const c = new Common({ + chain: 'testnetMerge', + hardfork: Hardfork.Istanbul, + customChains, + }); + + expect(c.getHardforkByBlockNumber(0)).toBe('chainstart'); + expect(c.getHardforkByBlockNumber(14)).toBe('london'); + expect(c.getHardforkByBlockNumber(15, 5000)).toBe('merge'); + expect(c.getHardforkByBlockNumber(15, 5001)).toBe('merge'); + expect(c.getHardforkByBlockNumber(15, 4999)).toBe('london'); + expect(c.getHardforkByBlockNumber(12, 4999)).toBe('berlin'); + }); + + it('getHardforkByBlockNumber(), merge block set, with total difficulty', () => { + const testnetMergeWithBlockNumber = JSON.parse(JSON.stringify(testnetMerge)); + // Set Merge block to 15 + testnetMergeWithBlockNumber['hardforks'][8]['block'] = 16; + const customChains = [testnetMergeWithBlockNumber]; + const c = new Common({ + chain: 'testnetMerge', + hardfork: Hardfork.Istanbul, + customChains, + }); + + expect(c.getHardforkByBlockNumber(0)).toBe('chainstart'); + expect(c.getHardforkByBlockNumber(16)).toBe('merge'); + expect(c.getHardforkByBlockNumber(16, 5000)).toBe('merge'); + expect(c.getHardforkByBlockNumber(16, 5001)).toBe('merge'); + expect(c.getHardforkByBlockNumber(12, 4999)).toBe('berlin'); + + expect(() => { + c.getHardforkByBlockNumber(16, 4999); + }).toThrow('Maximum HF determined by total difficulty is lower than the block number HF'); + + expect(() => { + c.getHardforkByBlockNumber(14, 5000); + }).toThrow('HF determined by block number is lower than the minimum total difficulty HF'); + }); + + it('getHardforkByBlockNumber(), merge block set + subsequent HF, with total difficulty', () => { + const testnetMergeWithBlockNumber = JSON.parse(JSON.stringify(testnetMerge)); + // Set Merge block to 15 + testnetMergeWithBlockNumber['hardforks'][8]['block'] = 16; + // Set Shanghai block to 18 + testnetMergeWithBlockNumber['hardforks'][9]['block'] = 18; + const customChains = [testnetMergeWithBlockNumber]; + const c = new Common({ + chain: 'testnetMerge', + hardfork: Hardfork.Istanbul, + customChains, + }); + + expect(c.getHardforkByBlockNumber(18, 5001)).toBe('shanghai'); + }); + + it('setHardforkByBlockNumber(), merge block null, with total difficulty', () => { + const customChains = [testnetMerge]; + const c = new Common({ + chain: 'testnetMerge', + hardfork: Hardfork.Istanbul, + customChains, + }); + + expect(c.setHardforkByBlockNumber(0)).toBe('chainstart'); + expect(c.setHardforkByBlockNumber(14)).toBe('london'); + expect(c.setHardforkByBlockNumber(15, 5000)).toBe('merge'); + expect(c.setHardforkByBlockNumber(15, 5001)).toBe('merge'); + expect(c.setHardforkByBlockNumber(15, 4999)).toBe('london'); + expect(c.setHardforkByBlockNumber(12, 4999)).toBe('berlin'); + }); + + it('setHardforkByBlockNumber(), merge block set, with total difficulty', () => { + const testnetMergeWithBlockNumber = JSON.parse(JSON.stringify(testnetMerge)); + // Set Merge block to 15 + testnetMergeWithBlockNumber['hardforks'][8]['block'] = 16; + const customChains = [testnetMergeWithBlockNumber]; + const c = new Common({ + chain: 'testnetMerge', + hardfork: Hardfork.Istanbul, + customChains, + }); + + expect(c.setHardforkByBlockNumber(0)).toBe('chainstart'); + expect(c.setHardforkByBlockNumber(16)).toBe('merge'); + expect(c.setHardforkByBlockNumber(16, 5000)).toBe('merge'); + expect(c.setHardforkByBlockNumber(16, 5001)).toBe('merge'); + expect(c.setHardforkByBlockNumber(12, 4999)).toBe('berlin'); + + expect(() => { + c.setHardforkByBlockNumber(16, 4999); + }).toThrow('Maximum HF determined by total difficulty is lower than the block number HF'); + + expect(() => { + c.setHardforkByBlockNumber(14, 5000); + }).toThrow('HF determined by block number is lower than the minimum total difficulty HF'); + }); + + it('setHardforkByBlockNumber(), merge block set + subsequent HF, with total difficulty', () => { + const testnetMergeWithBlockNumber = JSON.parse(JSON.stringify(testnetMerge)); + // Set Merge block to 15 + testnetMergeWithBlockNumber['hardforks'][8]['block'] = 16; + // Set Shanghai block to 18 + testnetMergeWithBlockNumber['hardforks'][9]['block'] = 18; + const customChains = [testnetMergeWithBlockNumber]; + const c = new Common({ + chain: 'testnetMerge', + hardfork: Hardfork.Istanbul, + customChains, + }); + + expect(c.setHardforkByBlockNumber(18, 5001)).toBe('shanghai'); + }); + + it('Pure POS testnet', () => { + const customChains = [testnetPOS]; + const c = new Common({ chain: 'testnetPOS', hardfork: Hardfork.Chainstart, customChains }); + + expect(c.hardforkTTD(Hardfork.Chainstart)).toEqual(BigInt(0)); + + expect(c.getHardforkByBlockNumber(5, 0)).toBe('shanghai'); + }); + + it('Should fail setting invalid hardfork', () => { + const customChains = [testnetPOS]; + expect(() => { + // eslint-disable-next-line no-new + new Common({ chain: 'testnetPOS', hardfork: Hardfork.Istanbul, customChains }); + }).toThrow(`Hardfork with name istanbul not supported`); + }); + + it('should get the correct merge hardfork at genesis', async () => { + const c = Common.fromGethGenesis(postMerge, { chain: 'post-merge' }); + expect(c.getHardforkByBlockNumber(0)).toEqual(Hardfork.London); + expect(c.getHardforkByBlockNumber(0, BigInt(0))).toEqual(Hardfork.Merge); + }); + + it('test post merge hardforks using Sepolia with block null', () => { + const c = new Common({ chain: Chain.Sepolia }); + + expect(c.getHardforkByBlockNumber(0)).toEqual(Hardfork.London); + // Make it null manually as config could be updated later + // eslint-disable-next-line no-null/no-null + const mergeHf = c.hardforks().filter(hf => hf.ttd !== undefined && hf.ttd !== null)[0]; + const prevMergeBlockVal = mergeHf.block; + // eslint-disable-next-line no-null/no-null + mergeHf.block = null; + + // should get Hardfork.London even though happened with 1450408 as terminal as config doesn't have that info + expect(c.getHardforkByBlockNumber(1450409)).toEqual(Hardfork.London); + // however with correct td in input it should select merge + expect(c.getHardforkByBlockNumber(1450409, BigInt('17000000000000000'))).toEqual( + Hardfork.Merge, + ); + // should select MergeForkIdTransition even without td specified as the block is set for this hardfork + expect(c.getHardforkByBlockNumber(1735371)).toEqual(Hardfork.MergeForkIdTransition); + // also with td specified + expect(c.getHardforkByBlockNumber(1735371, BigInt('17000000000000000'))).toEqual( + Hardfork.MergeForkIdTransition, + ); + + // Check nextHardforkBlockOrTimestamp should be MergeForkIdTransition's block on london and merge both + expect(c.nextHardforkBlockOrTimestamp(Hardfork.Berlin)).toEqual(toBigInt(1735371)); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.London)).toEqual(toBigInt(1735371)); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.Merge)).toEqual(toBigInt(1735371)); + + expect(() => { + c.getHardforkByBlockNumber(1735371, BigInt('15000000000000000')); + }).toThrow('Maximum HF determined by total difficulty is lower than the block number HF'); + + expect(c.setHardforkByBlockNumber(0)).toEqual(Hardfork.London); + expect(c.setHardforkByBlockNumber(1450409)).toEqual(Hardfork.London); + expect(c.setHardforkByBlockNumber(1450409, BigInt('17000000000000000'))).toEqual( + Hardfork.Merge, + ); + expect(c.setHardforkByBlockNumber(1735371)).toEqual(Hardfork.MergeForkIdTransition); + expect(c.setHardforkByBlockNumber(1735371, BigInt('17000000000000000'))).toEqual( + Hardfork.MergeForkIdTransition, + ); + + expect(() => { + c.setHardforkByBlockNumber(1735371, BigInt('15000000000000000')); + }).toThrow('Maximum HF determined by total difficulty is lower than the block number HF'); + // restore value + mergeHf.block = prevMergeBlockVal; + }); + + it('should get correct merge and post merge hf with merge block specified', () => { + const c = new Common({ chain: Chain.Sepolia }); + // eslint-disable-next-line no-null/no-null + const mergeHf = c.hardforks().filter(hf => hf.ttd !== undefined && hf.ttd !== null)[0]; + const prevMergeBlockVal = mergeHf.block; + // the terminal block on sepolia is 1450408 + mergeHf.block = 1450409; + + // should get merge even without td supplied as the merge hf now has the block specified + expect(c.setHardforkByBlockNumber(1450409)).toEqual(Hardfork.Merge); + expect(c.setHardforkByBlockNumber(1450409, BigInt('17000000000000000'))).toEqual( + Hardfork.Merge, + ); + expect(c.setHardforkByBlockNumber(1735371)).toEqual(Hardfork.MergeForkIdTransition); + expect(c.setHardforkByBlockNumber(1735371, BigInt('17000000000000000'))).toEqual( + Hardfork.MergeForkIdTransition, + ); + + // Check nextHardforkBlockOrTimestamp should be MergeForkIdTransition's block on london and merge both + expect(c.nextHardforkBlockOrTimestamp(Hardfork.London)).toEqual(toBigInt(1735371)); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.Merge)).toEqual(toBigInt(1735371)); + + // restore value + mergeHf.block = prevMergeBlockVal; + }); + + it('should throw if encounters a double ttd hardfork specification', () => { + const c = new Common({ chain: Chain.Sepolia }); + // Add the ttd to mergeForkIdTransition which occurs post merge in sepolia + c.hardforks().filter(hf => hf.name === 'mergeForkIdTransition')[0]!['ttd'] = + '17000000000000000'; + expect(() => { + c.setHardforkByBlockNumber(1735371); + }).toThrow('More than one merge hardforks found with ttd specified'); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/params.test.ts b/packages/web3-eth-accounts/test/unit/common/params.test.ts new file mode 100644 index 00000000000..46e8720e2db --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/params.test.ts @@ -0,0 +1,102 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, Hardfork } from '../../../src/common'; + +describe('[Common]: Parameter access for param(), paramByHardfork()', () => { + it('Basic usage', () => { + const c = new Common({ chain: Chain.Mainnet, eips: [2537] }); + expect(c.paramByHardfork('gasPrices', 'ecAdd', 'byzantium')).toEqual(BigInt(500)); + + c.setHardfork(Hardfork.Byzantium); + expect(c.param('gasPrices', 'ecAdd')).toEqual(BigInt(500)); + c.setHardfork(Hardfork.Istanbul); + expect(c.param('gasPrices', 'ecAdd')).toEqual(BigInt(150)); + c.setHardfork(Hardfork.MuirGlacier); + expect(c.param('gasPrices', 'ecAdd')).toEqual(BigInt(150)); + + expect(c.param('gasPrices', 'notexistingvalue')).toEqual(BigInt(0)); + expect(c.paramByHardfork('gasPrices', 'notexistingvalue', 'byzantium')).toEqual(BigInt(0)); + }); + + it('Error cases for param(), paramByHardfork()', () => { + const c = new Common({ chain: Chain.Mainnet }); + + expect(() => { + c.paramByHardfork('gasPrizes', 'ecAdd', 'byzantium'); + }).toThrow('Topic gasPrizes not defined'); + + c.setHardfork(Hardfork.Byzantium); + expect(c.param('gasPrices', 'ecAdd')).toEqual(BigInt(500)); + }); + + it('Parameter updates', () => { + const c = new Common({ chain: Chain.Mainnet }); + + expect(c.paramByHardfork('pow', 'minerReward', 'chainstart')).toEqual( + BigInt(5000000000000000000), + ); + + expect(c.paramByHardfork('pow', 'minerReward', 'byzantium')).toEqual( + BigInt(3000000000000000000), + ); + + expect(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'constantinople')).toEqual( + BigInt(200), + ); + + expect(c.paramByHardfork('gasPrices', 'netSstoreNoopGas', 'petersburg')).toEqual(BigInt(0)); + }); + + it('Access by block number, paramByBlock()', () => { + const c = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }); + expect(c.paramByBlock('pow', 'minerReward', 4370000)).toEqual(BigInt(3000000000000000000)); + expect(c.paramByBlock('pow', 'minerReward', 4369999)).toEqual(BigInt(5000000000000000000)); + + const td = BigInt('1196768507891266117779'); + expect(c.paramByBlock('pow', 'minerReward', 4370000, td)).toEqual( + BigInt(3000000000000000000), + ); + }); + + it('EIP param access, paramByEIP()', () => { + const c = new Common({ chain: Chain.Mainnet }); + + expect(c.paramByEIP('gasPrices', 'notexistingvalue', 2537)).toBeUndefined(); + + const UNSUPPORTED_EIP = 1000000; + expect(() => { + c.paramByEIP('gasPrices', 'Bls12381G1AddGas', UNSUPPORTED_EIP); + }).toThrow('not supported'); + + expect(() => { + c.paramByEIP('notExistingTopic', 'Bls12381G1AddGas', 2537); + }).toThrow('not defined'); + + expect(c.paramByEIP('gasPrices', 'Bls12381G1AddGas', 2537)).toEqual(BigInt(600)); + }); + + it('returns the right block delay for EIP3554', () => { + for (const fork of [Hardfork.MuirGlacier, Hardfork.Berlin]) { + const c = new Common({ chain: Chain.Mainnet, hardfork: fork }); + let delay = c.param('pow', 'difficultyBombDelay'); + expect(delay).toEqual(BigInt(9000000)); + c.setEIPs([3554]); + delay = c.param('pow', 'difficultyBombDelay'); + expect(delay).toEqual(BigInt(9500000)); + } + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/timestamp.test.ts b/packages/web3-eth-accounts/test/unit/common/timestamp.test.ts new file mode 100644 index 00000000000..6163c389050 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/timestamp.test.ts @@ -0,0 +1,145 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, Hardfork } from '../../../src/common'; + +import * as timestampJson from '../../fixtures/common/shanghai-time.json'; + +describe('[Common]: Timestamp Hardfork logic', () => { + it('shanghai-time', () => { + const c = Common.fromGethGenesis(timestampJson, { + chain: 'withdrawals', + }); + expect(c.getHardforkByBlockNumber(1, undefined, 0)).toEqual(Hardfork.MergeForkIdTransition); + expect(c.getHardforkByBlockNumber(1, undefined, 1668699476)).toEqual(Hardfork.Shanghai); + expect(c.getHardforkByBlockNumber(1, undefined, 1668699576)).toEqual(Hardfork.Shanghai); + }); + + it('schedule sharding on shanghai-time', () => { + const config = { + ...timestampJson.config, + shardingForkTime: timestampJson.config.shanghaiTime, + }; + const modifiedJson = { ...timestampJson, config }; + const c = Common.fromGethGenesis(modifiedJson, { + chain: 'modified', + }); + expect(c.getHardforkByBlockNumber(1, undefined, 0)).toEqual(Hardfork.MergeForkIdTransition); + expect(c.nextHardforkBlockOrTimestamp(Hardfork.Shanghai)).toBeNull(); + }); + + it('schedule sharding post shanghai-time', () => { + const config = { + ...timestampJson.config, + shardingForkTime: timestampJson.config.shanghaiTime + 1000, + }; + const modifiedJson = { ...timestampJson, config }; + const c = Common.fromGethGenesis(modifiedJson, { + chain: 'modified', + }); + expect(c.getHardforkByBlockNumber(1, undefined, 0)).toEqual(Hardfork.MergeForkIdTransition); + // Should give the shanghai as sharding is schedule a bit post shanghai + expect(c.getHardforkByBlockNumber(1, undefined, 1668699476)).toEqual(Hardfork.Shanghai); + expect(c.getHardforkByBlockNumber(1, undefined, 1668699576)).toEqual(Hardfork.Shanghai); + }); + + it('forkHash', () => { + const mainnet = new Common({ chain: Chain.Mainnet }); + const hfs = mainnet.hardforks(); + const mergeIndex = hfs.findIndex(hf => hf.name === Hardfork.Merge); + const hardforks = hfs.slice(0, mergeIndex + 1).concat([ + // Add these hardforks as specified here: + // https://github.com/ethereum/EIPs/pull/6122/files + { + name: 'mergeForkIdTransition', + block: 18000000, + forkHash: '0x4fb8a872', + }, + { + name: 'shanghai', + // eslint-disable-next-line no-null/no-null + block: null, + timestamp: '1668000000', + forkHash: '0xc1fdf181', + }, + ]); + + const c = Common.custom({ hardforks }, { baseChain: Chain.Mainnet }); + const mainnetGenesisHash = Buffer.from( + 'd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', + 'hex', + ); + for (const hf of c.hardforks()) { + if (typeof hf.forkHash !== 'string') { + continue; + } + expect(c._calcForkHash(hf.name, mainnetGenesisHash)).toEqual(hf.forkHash); + } + + c.setHardfork(Hardfork.MergeForkIdTransition); + expect(c.nextHardforkBlockOrTimestamp()).toEqual(BigInt(1668000000)); + + c.setHardfork(Hardfork.Shanghai); + expect(c.forkHash()).toBe('0xc1fdf181'); + expect(c.hardforkForForkHash('0xc1fdf181')?.name).toEqual(Hardfork.Shanghai); + }); + + it('setForkHashes', () => { + const mainnet = new Common({ chain: Chain.Mainnet }); + const hfs = mainnet.hardforks(); + const mergeIndex = hfs.findIndex(hf => hf.name === Hardfork.Merge); + const hardforks = hfs.slice(0, mergeIndex + 1).concat([ + // Add these hardforks as specified here: + // https://github.com/ethereum/EIPs/pull/6122/files + { + name: 'mergeForkIdTransition', + block: 18000000, + }, + { + name: 'shanghai', + // eslint-disable-next-line no-null/no-null + block: null, + timestamp: '1668000000', + }, + ]); + + const c = Common.custom({ hardforks }, { baseChain: Chain.Mainnet }); + const mainnetGenesisHash = Buffer.from( + 'd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3', + 'hex', + ); + + let noForkHashes = c.hardforks().reduce((acc, hf) => { + if (hf.forkHash === undefined) { + // eslint-disable-next-line no-param-reassign + acc += 1; + } + return acc; + }, 0); + expect(noForkHashes).toBe(2); + + c.setForkHashes(mainnetGenesisHash); + noForkHashes = c.hardforks().reduce((acc, hf) => { + if (hf.forkHash === undefined) { + // eslint-disable-next-line no-param-reassign + acc += 1; + } + return acc; + }, 0); + expect(noForkHashes).toBe(0); + expect(c.forkHash(Hardfork.Shanghai)).toBe('0xc1fdf181'); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/common/utils.test.ts b/packages/web3-eth-accounts/test/unit/common/utils.test.ts new file mode 100644 index 00000000000..a9bd9b39326 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/common/utils.test.ts @@ -0,0 +1,173 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Common } from '../../../src/common/common'; +import { Hardfork } from '../../../src/common'; +import { parseGethGenesis } from '../../../src/common/utils'; +import testnet from '../../fixtures/common/testnetValid.json'; +import invalidSpuriousDragon from '../../fixtures/common/invalid-spurious-dragon.json'; +import poa from '../../fixtures/common/poa.json'; +import postMerge from '../../fixtures/common/post-merge.json'; +import noExtraData from '../../fixtures/common/no-extra-data.json'; +import gethGenesisKiln from '../../fixtures/common/geth-genesis-kiln.json'; +import postMergeHardfork from '../../fixtures/common/post-merge-hardfork.json'; + +describe('[Utils/Parse]', () => { + const kilnForkHashes: any = { + chainstart: '0xbcadf543', + homestead: '0xbcadf543', + tangerineWhistle: '0xbcadf543', + spuriousDragon: '0xbcadf543', + byzantium: '0xbcadf543', + constantinople: '0xbcadf543', + petersburg: '0xbcadf543', + istanbul: '0xbcadf543', + berlin: '0xbcadf543', + london: '0xbcadf543', + mergeForkIdTransition: '0x013fd1b5', + merge: '0x013fd1b5', + }; + + it('should parse geth params file', async () => { + const params = parseGethGenesis(testnet, 'rinkeby'); + expect(params.genesis.nonce).toBe('0x0000000000000042'); + }); + + it('should throw with invalid Spurious Dragon blocks', async () => { + expect(() => { + parseGethGenesis(invalidSpuriousDragon, 'bad_params'); + }).toThrow(); + }); + + it('should import poa network params correctly', async () => { + let params = parseGethGenesis(poa, 'poa'); + expect(params.genesis.nonce).toBe('0x0000000000000000'); + expect(params.consensus).toEqual({ + type: 'poa', + algorithm: 'clique', + clique: { period: 15, epoch: 30000 }, + }); + poa.nonce = '00'; + params = parseGethGenesis(poa, 'poa'); + expect(params.genesis.nonce).toBe('0x0000000000000000'); + expect(params.hardfork).toEqual(Hardfork.London); + }); + + it('should generate expected hash with london block zero and base fee per gas defined', async () => { + const params = parseGethGenesis(postMerge, 'post-merge'); + expect(params.genesis.baseFeePerGas).toEqual(postMerge.baseFeePerGas); + }); + + it('should successfully parse genesis file with no extraData', async () => { + const params = parseGethGenesis(noExtraData, 'noExtraData'); + expect(params.genesis.extraData).toBe('0x'); + expect(params.genesis.timestamp).toBe('0x10'); + }); + + it('should successfully parse kiln genesis and set forkhash', async () => { + const common = Common.fromGethGenesis(gethGenesisKiln, { + chain: 'customChain', + genesisHash: Buffer.from( + '51c7fe41be669f69c45c33a56982cbde405313342d9e2b00d7c91a7b284dd4f8', + 'hex', + ), + mergeForkIdPostMerge: false, + }); + expect(common.hardforks().map(hf => hf.name)).toEqual([ + 'chainstart', + 'homestead', + 'tangerineWhistle', + 'spuriousDragon', + 'byzantium', + 'constantinople', + 'petersburg', + 'istanbul', + 'berlin', + 'london', + 'mergeForkIdTransition', + 'merge', + ]); + for (const hf of common.hardforks()) { + /* eslint-disable @typescript-eslint/no-use-before-define */ + expect(hf.forkHash).toEqual(kilnForkHashes[hf.name]); + } + + expect(common.hardfork()).toEqual(Hardfork.Merge); + + // Ok lets schedule shanghai at block 0, this should force merge to be scheduled at just after + // genesis if even mergeForkIdTransition is not confirmed to be post merge + // This will also check if the forks are being correctly sorted based on block + Object.assign(gethGenesisKiln.config, { shanghaiTime: Math.floor(Date.now() / 1000) }); + const common1 = Common.fromGethGenesis(gethGenesisKiln, { + chain: 'customChain', + }); + // merge hardfork is now scheduled just after shanghai even if mergeForkIdTransition is not confirmed + // to be post merge + expect(common1.hardforks().map(hf => hf.name)).toEqual([ + 'chainstart', + 'homestead', + 'tangerineWhistle', + 'spuriousDragon', + 'byzantium', + 'constantinople', + 'petersburg', + 'istanbul', + 'berlin', + 'london', + 'merge', + 'mergeForkIdTransition', + 'shanghai', + ]); + + expect(common1.hardfork()).toEqual(Hardfork.Shanghai); + }); + + it('should successfully parse genesis with hardfork scheduled post merge', async () => { + const common = Common.fromGethGenesis(postMergeHardfork, { + chain: 'customChain', + }); + expect(common.hardforks().map(hf => hf.name)).toEqual([ + 'chainstart', + 'homestead', + 'tangerineWhistle', + 'spuriousDragon', + 'byzantium', + 'constantinople', + 'petersburg', + 'istanbul', + 'muirGlacier', + 'berlin', + 'london', + 'merge', + 'shanghai', + ]); + + expect(common.getHardforkByBlockNumber(0)).toEqual(Hardfork.London); + expect(common.getHardforkByBlockNumber(1, BigInt(2))).toEqual(Hardfork.Merge); + // shanghai is at timestamp 8 + expect(common.getHardforkByBlockNumber(8)).toEqual(Hardfork.London); + expect(common.getHardforkByBlockNumber(8, BigInt(2))).toEqual(Hardfork.Merge); + expect(common.getHardforkByBlockNumber(8, undefined, 8)).toEqual(Hardfork.Shanghai); + // should be post merge at shanghai + expect(common.getHardforkByBlockNumber(8, BigInt(2), 8)).toEqual(Hardfork.Shanghai); + // if not post merge, then should error + expect(() => { + common.getHardforkByBlockNumber(8, BigInt(1), 8); + }).toThrow(); + + expect(common.hardfork()).toEqual(Hardfork.Shanghai); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/jest.config.js b/packages/web3-eth-accounts/test/unit/jest.config.js index de9992fdf10..a1352870672 100644 --- a/packages/web3-eth-accounts/test/unit/jest.config.js +++ b/packages/web3-eth-accounts/test/unit/jest.config.js @@ -5,7 +5,7 @@ module.exports = { testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], coverageDirectory: '../../.coverage/unit', - collectCoverageFrom: ['src/**'], + collectCoverageFrom: ['src/**/*.ts'], collectCoverage: true, coverageReporters: [ [ diff --git a/packages/web3-eth-accounts/test/unit/tx/base.test.ts b/packages/web3-eth-accounts/test/unit/tx/base.test.ts new file mode 100644 index 00000000000..54cfd9038d8 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/base.test.ts @@ -0,0 +1,369 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Point } from 'ethereum-cryptography/secp256k1'; +import { Chain, Common, Hardfork } from '../../../src/common'; +import { toBuffer, bufferToBigInt } from '../../../src/common/utils'; +import { MAX_UINT64, MAX_INTEGER, SECP256K1_ORDER } from '../../../src/tx/constants'; +import { + AccessListEIP2930Transaction, + Capability, + FeeMarketEIP1559Transaction, + Transaction, +} from '../../../src'; + +import type { BaseTransaction } from '../../../src/tx/baseTransaction'; +import eip2930Fixtures from '../../fixtures/json/eip2930txs.json'; +import eip1559Fixtures from '../../fixtures/json/eip1559txs.json'; + +import legacyFixtures from '../../fixtures/json/txs.json'; + +const privateToPublic = function (privateKey: Buffer): Buffer { + return Buffer.from(Point.fromPrivateKey(privateKey).toRawBytes(false).slice(1)); +}; +const common = new Common({ + chain: 5, + hardfork: Hardfork.London, +}); +// @ts-expect-error set private property +common._chainParams.chainId = 4; +describe('[BaseTransaction]', () => { + // EIP-2930 is not enabled in Common by default (2021-03-06) + // eslint-disable-next-line @typescript-eslint/no-shadow + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }); + + const legacyTxs: BaseTransaction[] = []; + for (const tx of legacyFixtures.slice(0, 4)) { + legacyTxs.push(Transaction.fromTxData(tx.data, { common })); + } + + const eip2930Txs: BaseTransaction[] = []; + for (const tx of eip2930Fixtures) { + eip2930Txs.push(AccessListEIP2930Transaction.fromTxData(tx.data, { common })); + } + + const eip1559Txs: BaseTransaction[] = []; + for (const tx of eip1559Fixtures) { + eip1559Txs.push(FeeMarketEIP1559Transaction.fromTxData(tx.data, { common })); + } + + const zero = Buffer.alloc(0); + const txTypes = [ + { + class: Transaction, + name: 'Transaction', + type: 0, + values: Array(6).fill(zero), + txs: legacyTxs, + fixtures: legacyFixtures, + activeCapabilities: [], + notActiveCapabilities: [ + Capability.EIP1559FeeMarket, + Capability.EIP2718TypedTransaction, + Capability.EIP2930AccessLists, + 9999, + ], + }, + { + class: AccessListEIP2930Transaction, + name: 'AccessListEIP2930Transaction', + type: 1, + values: [Buffer.from([1])].concat(Array(7).fill(zero)), + txs: eip2930Txs, + fixtures: eip2930Fixtures, + activeCapabilities: [Capability.EIP2718TypedTransaction, Capability.EIP2930AccessLists], + notActiveCapabilities: [Capability.EIP1559FeeMarket, 9999], + }, + { + class: FeeMarketEIP1559Transaction, + name: 'FeeMarketEIP1559Transaction', + type: 2, + values: [Buffer.from([1])].concat(Array(8).fill(zero)), + txs: eip1559Txs, + fixtures: eip1559Fixtures, + activeCapabilities: [ + Capability.EIP1559FeeMarket, + Capability.EIP2718TypedTransaction, + Capability.EIP2930AccessLists, + ], + notActiveCapabilities: [9999], + }, + ]; + + it('Initialization', () => { + for (const txType of txTypes) { + let tx = txType.class.fromTxData({}, { common }); + expect(tx.common.hardfork()).toBe('london'); + expect(Object.isFrozen(tx)).toBe(true); + + const initCommon = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.London, + }); + tx = txType.class.fromTxData({}, { common: initCommon }); + expect(tx.common.hardfork()).toBe('london'); + + initCommon.setHardfork(Hardfork.Byzantium); + expect(tx.common.hardfork()).toBe('london'); + + tx = txType.class.fromTxData({}, { common, freeze: false }); + expect(!Object.isFrozen(tx)).toBe(true); + + // Perform the same test as above, but now using a different construction method. This also implies that passing on the + // options object works as expected. + tx = txType.class.fromTxData({}, { common, freeze: false }); + const rlpData = tx.serialize(); + + tx = txType.class.fromSerializedTx(rlpData, { common }); + expect(tx.type).toEqual(txType.type); + + expect(Object.isFrozen(tx)).toBe(true); + + tx = txType.class.fromSerializedTx(rlpData, { common, freeze: false }); + expect(!Object.isFrozen(tx)).toBe(true); + + tx = txType.class.fromValuesArray(txType.values as any, { common }); + expect(Object.isFrozen(tx)).toBe(true); + + tx = txType.class.fromValuesArray(txType.values as any, { common, freeze: false }); + expect(!Object.isFrozen(tx)).toBe(true); + } + }); + + it('fromValuesArray()', () => { + let rlpData: any = legacyTxs[0].raw(); + rlpData[0] = toBuffer('0x0'); + expect(() => { + Transaction.fromValuesArray(rlpData); + }).toThrow('nonce cannot have leading zeroes'); + rlpData[0] = toBuffer('0x'); + rlpData[6] = toBuffer('0x0'); + expect(() => { + Transaction.fromValuesArray(rlpData); + }).toThrow('v cannot have leading zeroes'); + rlpData = eip2930Txs[0].raw(); + rlpData[3] = toBuffer('0x0'); + expect(() => { + AccessListEIP2930Transaction.fromValuesArray(rlpData); + }).toThrow('gasLimit cannot have leading zeroes'); + rlpData = eip1559Txs[0].raw(); + rlpData[2] = toBuffer('0x0'); + expect(() => { + FeeMarketEIP1559Transaction.fromValuesArray(rlpData); + }).toThrow('maxPriorityFeePerGas cannot have leading zeroes'); + }); + + it('serialize()', () => { + for (const txType of txTypes) { + for (const tx of txType.txs) { + expect(txType.class.fromSerializedTx(tx.serialize(), { common })).toBeTruthy(); + expect(txType.class.fromSerializedTx(tx.serialize(), { common })).toBeTruthy(); + } + } + }); + + it('supports()', () => { + for (const txType of txTypes) { + for (const tx of txType.txs) { + for (const activeCapability of txType.activeCapabilities) { + expect(tx.supports(activeCapability)).toBe(true); + } + for (const notActiveCapability of txType.notActiveCapabilities) { + expect(tx.supports(notActiveCapability)).toBe(false); + } + } + } + }); + + it('raw()', () => { + for (const txType of txTypes) { + for (const tx of txType.txs) { + expect(txType.class.fromValuesArray(tx.raw() as any, { common })).toBeTruthy(); + } + } + }); + + it('verifySignature()', () => { + for (const txType of txTypes) { + for (const tx of txType.txs) { + expect(tx.verifySignature()).toBe(true); + } + } + }); + + it('verifySignature() -> invalid', () => { + for (const txType of txTypes) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + for (const txFixture of txType.fixtures.slice(0, 4)) { + // set `s` to a single zero + txFixture.data.s = '0x0'; + // @ts-expect-error set data + const tx = txType.class.fromTxData(txFixture.data, { common }); + expect(tx.verifySignature()).toBe(false); + expect(tx.validate(true)).toContain('Invalid Signature'); + expect(tx.validate()).toBe(false); + } + } + }); + + it('sign()', () => { + for (const txType of txTypes) { + for (const [i, tx] of txType.txs.entries()) { + const { privateKey } = txType.fixtures[i]; + if (privateKey !== undefined) { + // eslint-disable-next-line jest/no-conditional-expect + expect(tx.sign(Buffer.from(privateKey, 'hex'))).toBeTruthy(); + } + + expect(() => tx.sign(Buffer.from('invalid'))).toThrow(); + } + } + }); + + it('isSigned() -> returns correct values', () => { + for (const txType of txTypes) { + const txs = [ + ...txType.txs, + // add unsigned variants + ...txType.txs.map(tx => + txType.class.fromTxData({ + ...tx, + v: undefined, + r: undefined, + s: undefined, + }), + ), + ]; + for (const tx of txs) { + expect(tx.isSigned()).toEqual( + tx.v !== undefined && tx.r !== undefined && tx.s !== undefined, + ); + } + } + }); + + it('getSenderAddress()', () => { + for (const txType of txTypes) { + for (const [i, tx] of txType.txs.entries()) { + const { privateKey, sendersAddress } = txType.fixtures[i]; + if (privateKey === undefined) { + continue; + } + const signedTx = tx.sign(Buffer.from(privateKey, 'hex')); + expect(signedTx.getSenderAddress().toString()).toBe(`0x${sendersAddress}`); + } + } + }); + + it('getSenderPublicKey()', () => { + for (const txType of txTypes) { + for (const [i, tx] of txType.txs.entries()) { + const { privateKey } = txType.fixtures[i]; + if (privateKey === undefined) { + continue; + } + const signedTx = tx.sign(Buffer.from(privateKey, 'hex')); + const txPubKey = signedTx.getSenderPublicKey(); + const pubKeyFromPriv = privateToPublic(Buffer.from(privateKey, 'hex')); + expect(txPubKey.equals(pubKeyFromPriv)).toBe(true); + } + } + }); + + it('getSenderPublicKey() -> should throw if s-value is greater than secp256k1n/2', () => { + // EIP-2: All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid. + // Reasoning: https://ethereum.stackexchange.com/a/55728 + for (const txType of txTypes) { + for (const [i, tx] of txType.txs.entries()) { + const { privateKey } = txType.fixtures[i]; + if (privateKey === undefined) { + continue; + } + let signedTx = tx.sign(Buffer.from(privateKey, 'hex')); + signedTx = JSON.parse(JSON.stringify(signedTx)); // deep clone + (signedTx as any).s = SECP256K1_ORDER + BigInt(1); + expect(() => { + signedTx.getSenderPublicKey(); + }).toThrow(); + } + } + }); + + it('verifySignature()->valid', () => { + for (const txType of txTypes) { + for (const [i, tx] of txType.txs.entries()) { + const { privateKey } = txType.fixtures[i]; + if (privateKey === undefined) { + continue; + } + const signedTx = tx.sign(Buffer.from(privateKey, 'hex')); + expect(signedTx.verifySignature()).toBeTruthy(); + } + } + }); + + it('initialization with defaults', () => { + const bufferZero = toBuffer('0x'); + const tx = Transaction.fromTxData({ + nonce: '', + gasLimit: '', + gasPrice: '', + to: '', + value: '', + data: '', + v: '', + r: '', + s: '', + }); + expect(tx.v).toBeUndefined(); + expect(tx.r).toBeUndefined(); + expect(tx.s).toBeUndefined(); + expect(tx.to).toBeUndefined(); + expect(tx.value).toBe(bufferToBigInt(bufferZero)); + expect(tx.data).toEqual(bufferZero); + expect(tx.gasPrice).toBe(bufferToBigInt(bufferZero)); + expect(tx.gasLimit).toBe(bufferToBigInt(bufferZero)); + expect(tx.nonce).toBe(bufferToBigInt(bufferZero)); + }); + + it('_validateCannotExceedMaxInteger()', () => { + const tx = FeeMarketEIP1559Transaction.fromTxData(eip1559Txs[0]); + expect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + (tx as any)._validateCannotExceedMaxInteger({ a: MAX_INTEGER }, 256, true); + }).toThrow('equal or exceed MAX_INTEGER'); + + expect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + (tx as any)._validateCannotExceedMaxInteger({ a: MAX_INTEGER + BigInt(1) }, 256, false); + }).toThrow('exceed MAX_INTEGER'); + + expect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + (tx as any)._validateCannotExceedMaxInteger({ a: BigInt(0) }, 100, false); + }).toThrow('unimplemented bits value'); + + expect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + (tx as any)._validateCannotExceedMaxInteger({ a: MAX_UINT64 + BigInt(1) }, 64, false); + }).toThrow('2^64'); + + expect(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + (tx as any)._validateCannotExceedMaxInteger({ a: MAX_UINT64 }, 64, true); + }).toThrow('2^64'); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/eip1559.test.ts b/packages/web3-eth-accounts/test/unit/tx/eip1559.test.ts new file mode 100644 index 00000000000..7040ad5a006 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/eip1559.test.ts @@ -0,0 +1,246 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { RLP } from '@ethereumjs/rlp'; +import { Chain, Common, Hardfork } from '../../../src/common'; + +import { FeeMarketEIP1559Transaction } from '../../../src'; + +import testdata from '../../fixtures/json/eip1559.json'; + +const common = new Common({ + chain: 5, + hardfork: Hardfork.London, +}); +// @ts-expect-error set private property +common._chainParams.chainId = 4; +const TWO_POW256 = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000'); + +const validAddress = Buffer.from('01'.repeat(20), 'hex'); +const validSlot = Buffer.from('01'.repeat(32), 'hex'); +const chainId = BigInt(4); + +describe('[FeeMarketEIP1559Transaction]', () => { + it('cannot input decimal or negative values %s', () => { + const values = [ + 'maxFeePerGas', + 'maxPriorityFeePerGas', + 'chainId', + 'nonce', + 'gasLimit', + 'value', + 'v', + 'r', + 's', + ]; + const cases = [ + 10.1, + '10.1', + '0xaa.1', + -10.1, + -1, + BigInt(-10), + '-100', + '-10.1', + '-0xaa', + Infinity, + -Infinity, + NaN, + {}, + true, + false, + // eslint-disable-next-line @typescript-eslint/no-empty-function + () => {}, + Number.MAX_SAFE_INTEGER + 1, + ]; + for (const value of values) { + const txData: any = {}; + for (const testCase of cases) { + if ( + value === 'chainId' && + ((typeof testCase === 'number' && Number.isNaN(testCase)) || testCase === false) + ) { + continue; + } + txData[value] = testCase; + expect(() => { + FeeMarketEIP1559Transaction.fromTxData(txData); + }).toThrow(); + } + } + }); + + it('getUpfrontCost()', () => { + const tx = FeeMarketEIP1559Transaction.fromTxData( + { + maxFeePerGas: 10, + maxPriorityFeePerGas: 8, + gasLimit: 100, + value: 6, + }, + { common }, + ); + expect(tx.getUpfrontCost()).toEqual(BigInt(806)); + let baseFee = BigInt(0); + expect(tx.getUpfrontCost(baseFee)).toEqual(BigInt(806)); + baseFee = BigInt(4); + expect(tx.getUpfrontCost(baseFee)).toEqual(BigInt(1006)); + }); + + it('sign()', () => { + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let index = 0; index < testdata.length; index += 1) { + const data = testdata[index]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const pkey = Buffer.from(data.privateKey.slice(2), 'hex'); + const txn = FeeMarketEIP1559Transaction.fromTxData(data, { common }); + const signed = txn.sign(pkey); + const rlpSerialized = Buffer.from(RLP.encode(Uint8Array.from(signed.serialize()))); + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + expect(rlpSerialized).toEqual(Buffer.from(data.signedTransactionRLP.slice(2), 'hex')); + } + }); + + it('hash()', () => { + const data = testdata[0]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const pkey = Buffer.from(data.privateKey.slice(2), 'hex'); + let txn = FeeMarketEIP1559Transaction.fromTxData(data, { common }); + let signed = txn.sign(pkey); + const expectedHash = Buffer.from( + '2e564c87eb4b40e7f469b2eec5aa5d18b0b46a24e8bf0919439cfb0e8fcae446', + 'hex', + ); + expect(signed.hash()).toEqual(expectedHash); + txn = FeeMarketEIP1559Transaction.fromTxData(data, { common, freeze: false }); + signed = txn.sign(pkey); + expect(signed.hash()).toEqual(expectedHash); + }); + + it('freeze property propagates from unsigned tx to signed tx', () => { + const data = testdata[0]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const pkey = Buffer.from(data.privateKey.slice(2), 'hex'); + const txn = FeeMarketEIP1559Transaction.fromTxData(data, { common, freeze: false }); + expect(Object.isFrozen(txn)).toBe(false); + const signedTxn = txn.sign(pkey); + expect(Object.isFrozen(signedTxn)).toBe(false); + }); + + it('common propagates from the common of tx, not the common in TxOptions', () => { + const data = testdata[0]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const pkey = Buffer.from(data.privateKey.slice(2), 'hex'); + const txn = FeeMarketEIP1559Transaction.fromTxData(data, { common, freeze: false }); + const newCommon = new Common({ + chain: Chain.Goerli, + hardfork: Hardfork.London, + eips: [2537], + }); + expect(Object.isFrozen(newCommon)).not.toEqual(common); + Object.defineProperty(txn, 'common', { + get() { + return newCommon; + }, + }); + const signedTxn = txn.sign(pkey); + expect(signedTxn.common.eips()).toContain(2537); + }); + + it('unsigned tx -> getMessageToSign()', () => { + const unsignedTx = FeeMarketEIP1559Transaction.fromTxData( + { + data: Buffer.from('010200', 'hex'), + to: validAddress, + accessList: [[validAddress, [validSlot]]], + chainId, + }, + { common }, + ); + const expectedHash = Buffer.from( + 'fa81814f7dd57bad435657a05eabdba2815f41e3f15ddd6139027e7db56b0dea', + 'hex', + ); + expect(unsignedTx.getMessageToSign(true)).toEqual(expectedHash); + + const expectedSerialization = Buffer.from( + '02f85904808080809401010101010101010101010101010101010101018083010200f838f7940101010101010101010101010101010101010101e1a00101010101010101010101010101010101010101010101010101010101010101', + 'hex', + ); + expect(unsignedTx.getMessageToSign(false)).toEqual(expectedSerialization); + }); + + it('toJSON()', () => { + const data = testdata[0]; + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const pkey = Buffer.from(data.privateKey.slice(2), 'hex'); + const txn = FeeMarketEIP1559Transaction.fromTxData(data, { common }); + const signed = txn.sign(pkey); + + const json = signed.toJSON(); + const expectedJSON = { + chainId: '0x4', + nonce: '0x333', + maxPriorityFeePerGas: '0x1284d', + maxFeePerGas: '0x1d97c', + gasLimit: '0x8ae0', + to: '0x000000000000000000000000000000000000aaaa', + value: '0x2933bc9', + data: '0x', + accessList: [], + v: '0x0', + r: '0xf924cb68412c8f1cfd74d9b581c71eeaf94fff6abdde3e5b02ca6b2931dcf47', + s: '0x7dd1c50027c3e31f8b565e25ce68a5072110f61fce5eee81b195dd51273c2f83', + }; + expect(json).toEqual(expectedJSON); + }); + + it('Fee validation', () => { + expect(() => { + FeeMarketEIP1559Transaction.fromTxData( + { + maxFeePerGas: TWO_POW256 - BigInt(1), + maxPriorityFeePerGas: 100, + gasLimit: 1, + value: 6, + }, + { common }, + ); + }).not.toThrow(); + expect(() => { + FeeMarketEIP1559Transaction.fromTxData( + { + maxFeePerGas: TWO_POW256 - BigInt(1), + maxPriorityFeePerGas: 100, + gasLimit: 100, + value: 6, + }, + { common }, + ); + }).toThrow(); + expect(() => { + FeeMarketEIP1559Transaction.fromTxData( + { + maxFeePerGas: 1, + maxPriorityFeePerGas: 2, + gasLimit: 100, + value: 6, + }, + { common }, + ); + }).toThrow(); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/eip3860.test.ts b/packages/web3-eth-accounts/test/unit/tx/eip3860.test.ts new file mode 100644 index 00000000000..7e1951b94e3 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/eip3860.test.ts @@ -0,0 +1,92 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, Hardfork } from '../../../src/common'; +import { Address } from '../../../src/tx/address'; +import { TransactionFactory } from '../../../src'; + +const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Merge, + eips: [3860], +}); + +const maxInitCodeSize = common.param('vm', 'maxInitCodeSize'); +const txTypes = [0, 1, 2]; +const addressZero = Address.zero(); + +describe('[EIP3860 tests]', () => { + it('Should instantiate create txs with MAX_INITCODE_SIZE', () => { + const data = Buffer.alloc(Number(maxInitCodeSize)); + for (const txType of txTypes) { + expect(TransactionFactory.fromTxData({ data, type: txType }, { common })).toBeTruthy(); + } + }); + + it('Should instantiate txs with MAX_INITCODE_SIZE data', () => { + const data = Buffer.alloc(Number(maxInitCodeSize)); + for (const txType of txTypes) { + expect( + TransactionFactory.fromTxData({ data, type: txType, to: addressZero }, { common }), + ).toBeTruthy(); + } + }); + + it('Should not instantiate create txs with MAX_INITCODE_SIZE+1 data', () => { + const data = Buffer.alloc(Number(maxInitCodeSize) + 1); + for (const txType of txTypes) { + expect(() => + TransactionFactory.fromTxData({ data, type: txType }, { common }), + ).toThrow(); + } + }); + + it('Should instantiate txs with MAX_INITCODE_SIZE+1 data', () => { + const data = Buffer.alloc(Number(maxInitCodeSize) + 1); + for (const txType of txTypes) { + expect( + TransactionFactory.fromTxData({ data, type: txType, to: addressZero }, { common }), + ).toBeTruthy(); + } + }); + + it('Should allow txs with MAX_INITCODE_SIZE+1 data if allowUnlimitedInitCodeSize is active', () => { + const data = Buffer.alloc(Number(maxInitCodeSize) + 1); + for (const txType of txTypes) { + expect( + TransactionFactory.fromTxData( + { data, type: txType }, + { common, allowUnlimitedInitCodeSize: true }, + ), + ).toBeTruthy(); + } + }); + + it('Should charge initcode analysis gas is allowUnlimitedInitCodeSize is active', () => { + const data = Buffer.alloc(Number(maxInitCodeSize)); + for (const txType of txTypes) { + const eip3860ActiveTx = TransactionFactory.fromTxData( + { data, type: txType }, + { common, allowUnlimitedInitCodeSize: true }, + ); + const eip3860DeactivedTx = TransactionFactory.fromTxData( + { data, type: txType }, + { common, allowUnlimitedInitCodeSize: false }, + ); + expect(eip3860ActiveTx.getDataFee() === eip3860DeactivedTx.getDataFee()).toBeTruthy(); + } + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/inputValue.test.ts b/packages/web3-eth-accounts/test/unit/tx/inputValue.test.ts new file mode 100644 index 00000000000..2f2fbacf9bb --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/inputValue.test.ts @@ -0,0 +1,288 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, Hardfork } from '../../../src/common'; +import { Address } from '../../../src/tx/address'; +import { toBuffer } from '../../../src/common/utils'; + +import { + AccessListEIP2930Transaction, + FeeMarketEIP1559Transaction, + Transaction, + TransactionFactory, +} from '../../../src'; + +import type { + AccessListEIP2930ValuesArray, + FeeMarketEIP1559ValuesArray, + TxValuesArray, +} from '../../../src'; +import type { BigIntLike, BufferLike, PrefixedHexString } from '../../../src/common/types'; + +type AddressLike = Address | Buffer | PrefixedHexString; +// @returns: Array with subtypes of the AddressLike type for a given address +function generateAddressLikeValues(address: string): AddressLike[] { + return [address, toBuffer(address), new Address(toBuffer(address))]; +} + +// @returns: Array with subtypes of the BigIntLike type for a given number +function generateBigIntLikeValues(value: number): BigIntLike[] { + return [value, BigInt(value), `0x${value.toString(16)}`, toBuffer(value)]; +} + +// @returns: Array with subtypes of the BufferLike type for a given string +function generateBufferLikeValues(value: string): BufferLike[] { + return [value, toBuffer(value)]; +} + +interface GenerateCombinationsArgs { + options: { [x: string]: any }; + optionIndex?: number; + results?: { [x: string]: any }[]; + current?: { [x: string]: any }; +} + +function generateCombinations({ + options, + optionIndex = 0, + results = [], + current = {}, +}: GenerateCombinationsArgs) { + const allKeys = Object.keys(options); + const optionKey = allKeys[optionIndex]; + const values = options[optionKey]; + // eslint-disable-next-line @typescript-eslint/prefer-for-of + for (let i = 0; i < values.length; i += 1) { + // eslint-disable-next-line no-param-reassign + current[optionKey] = values[i]; + + if (optionIndex + 1 < allKeys.length) { + generateCombinations({ options, optionIndex: optionIndex + 1, results, current }); + } else { + // Clone the object + const res = { ...current }; + results.push(res); + } + } + + return results; +} + +// Deterministic pseudorandom number generator +function mulberry32(seed: number) { + // eslint-disable-next-line no-param-reassign, no-multi-assign + let t = (seed += 0x6d2b79f5); + // eslint-disable-next-line no-bitwise + t = Math.imul(t ^ (t >>> 15), t | 1); + // eslint-disable-next-line no-bitwise + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + // eslint-disable-next-line no-bitwise + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; +} + +function getRandomSubarray(array: TArrayItem[], size: number) { + const shuffled = array.slice(0); + let seed = 1559; + let index: number; + let { length } = array; + let temp: TArrayItem; + while (length > 0) { + index = Math.floor((length + 1) * mulberry32(seed)); + temp = shuffled[index]; + shuffled[index] = shuffled[length]; + shuffled[length] = temp; + seed += 1; + length -= 1; + } + return shuffled.slice(0, size); +} + +const baseTxValues = { + data: generateBufferLikeValues('0x65'), + gasLimit: generateBigIntLikeValues(100000), + nonce: generateBigIntLikeValues(0), + to: generateAddressLikeValues('0x0000000000000000000000000000000000000000'), + r: generateBigIntLikeValues(100), + s: generateBigIntLikeValues(100), + value: generateBigIntLikeValues(10), +}; + +const legacyTxValues = { + gasPrice: generateBigIntLikeValues(100), +}; + +const accessListEip2930TxValues = { + chainId: generateBigIntLikeValues(4), +}; + +const eip1559TxValues = { + maxFeePerGas: generateBigIntLikeValues(100), + maxPriorityFeePerGas: generateBigIntLikeValues(50), +}; + +describe('[Transaction Input Values]', () => { + it('Legacy Transaction Values', () => { + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Homestead }); + const options = { ...baseTxValues, ...legacyTxValues, type: '0' }; + const legacyTxData = generateCombinations({ + options, + }); + const randomSample = getRandomSubarray(legacyTxData, 100); + for (const txData of randomSample) { + const tx = Transaction.fromTxData(txData, { common }); + expect(() => tx.hash()).toThrow(); + } + }); + + it('EIP-1559 Transaction Values', () => { + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }); + const options = { + ...baseTxValues, + ...accessListEip2930TxValues, + ...eip1559TxValues, + type: '2', + }; + const eip1559TxData = generateCombinations({ + options, + }); + const randomSample = getRandomSubarray(eip1559TxData, 100); + + for (const txData of randomSample) { + const tx = Transaction.fromTxData(txData, { common }); + expect(() => tx.hash()).toThrow(); + } + }); +}); + +test('[Invalid Array Input values]', () => { + const txTypes = [0x0, 0x1, 0x2]; + for (const signed of [false, true]) { + for (const txType of txTypes) { + let tx = TransactionFactory.fromTxData({ type: txType }); + if (signed) { + tx = tx.sign(Buffer.from('42'.repeat(32), 'hex')); + } + const rawValues = tx.raw(); + for (let x = 0; x < rawValues.length; x += 1) { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + rawValues[x] = [1, 2, 3]; + // eslint-disable-next-line default-case + switch (txType) { + case 0: + // eslint-disable-next-line jest/no-conditional-expect + expect(() => + Transaction.fromValuesArray(rawValues as TxValuesArray), + ).toThrow(); + break; + case 1: + // eslint-disable-next-line jest/no-conditional-expect + expect(() => + AccessListEIP2930Transaction.fromValuesArray( + rawValues as AccessListEIP2930ValuesArray, + ), + ).toThrow(); + break; + case 2: + // eslint-disable-next-line jest/no-conditional-expect + expect(() => + FeeMarketEIP1559Transaction.fromValuesArray( + rawValues as FeeMarketEIP1559ValuesArray, + ), + ).toThrow(); + break; + } + } + } + } +}); + +test('[Invalid Access Lists]', () => { + const txTypes = [0x1, 0x2]; + const invalidAccessLists = [ + [[]], // does not have an address and does not have slots + [[[], []]], // the address is an array + [['0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae']], // there is no storage slot array + [ + [ + '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae', + ['0x0000000000000000000000000000000000000000000000000000000000000003', []], + ], + ], // one of the slots is an array + [ + [ + '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae', + ['0x0000000000000000000000000000000000000000000000000000000000000003'], + '0xab', + ], + ], // extra field + [ + '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae', + ['0x0000000000000000000000000000000000000000000000000000000000000003'], + ], // account/slot needs to be encoded in a deeper array layer + ]; + for (const signed of [false, true]) { + for (const txType of txTypes) { + for (const invalidAccessListItem of invalidAccessLists) { + let tx: any; + try { + tx = TransactionFactory.fromTxData({ + type: txType, + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + accessList: invalidAccessListItem, + }); + if (signed) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + tx = tx.sign(Buffer.from('42'.repeat(32), 'hex')); + } + } catch (e: any) { + tx = TransactionFactory.fromTxData({ type: txType }); + if (signed) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + tx = tx.sign(Buffer.from('42'.repeat(32), 'hex')); + } + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + const rawValues = tx!.raw(); + + if (txType === 1 && rawValues[7].length === 0) { + rawValues[7] = invalidAccessListItem; + } else if (txType === 2 && rawValues[8].length === 0) { + rawValues[8] = invalidAccessListItem; + } + + // eslint-disable-next-line default-case + switch (txType) { + case 1: + // eslint-disable-next-line jest/no-conditional-expect + expect(() => + AccessListEIP2930Transaction.fromValuesArray( + rawValues as AccessListEIP2930ValuesArray, + ), + ).toThrow(); + break; + case 2: + // eslint-disable-next-line jest/no-conditional-expect + expect(() => + FeeMarketEIP1559Transaction.fromValuesArray( + rawValues as FeeMarketEIP1559ValuesArray, + ), + ).toThrow(); + break; + } + } + } + } +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/legacy.test.ts b/packages/web3-eth-accounts/test/unit/tx/legacy.test.ts new file mode 100644 index 00000000000..b0813f0455e --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/legacy.test.ts @@ -0,0 +1,479 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Buffer } from 'buffer'; +import { RLP } from '@ethereumjs/rlp'; +import { Chain, Common, Hardfork } from '../../../src/common'; +import { + arrToBufArr, + bufferToBigInt, + bufferToHex, + intToBuffer, + toBuffer, + unpadBuffer, +} from '../../../src/common/utils'; + +import { Transaction } from '../../../src'; +import type { TxData } from '../../../src'; +import txFixturesEip155 from '../../fixtures/json/ttTransactionTestEip155VitaliksTests.json'; +import txFixtures from '../../fixtures/json/txs.json'; + +describe('[Transaction]', () => { + const transactions: Transaction[] = []; + + it('cannot input decimal or negative values', () => { + const values = ['gasPrice', 'gasLimit', 'nonce', 'value', 'v', 'r', 's']; + const cases = [ + 10.1, + '10.1', + '0xaa.1', + -10.1, + -1, + BigInt(-10), + '-100', + '-10.1', + '-0xaa', + Infinity, + -Infinity, + NaN, + {}, + true, + false, + // eslint-disable-next-line @typescript-eslint/no-empty-function + () => {}, + Number.MAX_SAFE_INTEGER + 1, + ]; + for (const value of values) { + const txData: any = {}; + for (const testCase of cases) { + txData[value] = testCase; + expect(() => { + Transaction.fromTxData(txData); + }).toThrow(); + } + } + }); + + it('Initialization', () => { + const nonEIP2930Common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }); + expect(Transaction.fromTxData({}, { common: nonEIP2930Common })).toBeTruthy(); + + const txData = txFixtures[3].raw.map(toBuffer); + txData[6] = intToBuffer(45); // v with 0-parity and chain ID 5 + let tx = Transaction.fromValuesArray(txData); + expect(tx.common.chainId() === BigInt(5)).toBe(true); + + txData[6] = intToBuffer(46); // v with 1-parity and chain ID 5 + tx = Transaction.fromValuesArray(txData); + expect(tx.common.chainId() === BigInt(5)).toBe(true); + + txData[6] = intToBuffer(2033); // v with 0-parity and chain ID 999 + tx = Transaction.fromValuesArray(txData); + expect(tx.common.chainId()).toEqual(BigInt(999)); + + txData[6] = intToBuffer(2034); // v with 1-parity and chain ID 999 + tx = Transaction.fromValuesArray(txData); + expect(tx.common.chainId()).toEqual(BigInt(999)); + }); + + it('Initialization -> decode with fromValuesArray()', () => { + for (const tx of txFixtures.slice(0, 4)) { + const txData = tx.raw.map(toBuffer); + const pt = Transaction.fromValuesArray(txData); + + expect(bufferToHex(unpadBuffer(toBuffer(pt.nonce)))).toEqual(tx.raw[0]); + expect(bufferToHex(toBuffer(pt.gasPrice))).toEqual(tx.raw[1]); + expect(bufferToHex(toBuffer(pt.gasLimit))).toEqual(tx.raw[2]); + expect(pt.to?.toString()).toEqual(tx.raw[3]); + expect(bufferToHex(unpadBuffer(toBuffer(pt.value)))).toEqual(tx.raw[4]); + expect(`0x${pt.data.toString('hex')}`).toEqual(tx.raw[5]); + expect(bufferToHex(toBuffer(pt.v))).toEqual(tx.raw[6]); + expect(bufferToHex(toBuffer(pt.r))).toEqual(tx.raw[7]); + expect(bufferToHex(toBuffer(pt.s))).toEqual(tx.raw[8]); + + transactions.push(pt); + } + }); + + it('Initialization -> should accept lesser r values', () => { + const tx = Transaction.fromTxData({ r: bufferToBigInt(toBuffer('0x0005')) }); + expect(tx.r!.toString(16)).toBe('5'); + }); + + it('Initialization -> throws when creating a a transaction with incompatible chainid and v value', () => { + let common = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Petersburg }); + let tx = Transaction.fromTxData({}, { common }); + expect(tx.common.chainId()).toEqual(BigInt(5)); + const privKey = Buffer.from(txFixtures[0].privateKey, 'hex'); + tx = tx.sign(privKey); + const serialized = tx.serialize(); + common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Petersburg }); + expect(() => Transaction.fromSerializedTx(serialized, { common })).toThrow(); + }); + + it('Initialization -> throws if v is set to an EIP155-encoded value incompatible with the chain id', () => { + expect(() => { + const common = new Common({ chain: 42, hardfork: Hardfork.Petersburg }); + Transaction.fromTxData({ v: BigInt(1) }, { common }); + }).toThrow(); + }); + + it('validate() -> should validate with string option', () => { + for (const tx of transactions) { + expect(typeof tx.validate(true)[0]).toBe('string'); + } + }); + + it('getBaseFee() -> should return base fee', () => { + const tx = Transaction.fromTxData({}); + expect(tx.getBaseFee()).toEqual(BigInt(53000)); + }); + + it('getDataFee() -> should return data fee', () => { + let tx = Transaction.fromTxData({}); + expect(tx.getDataFee()).toEqual(BigInt(0)); + + tx = Transaction.fromValuesArray(txFixtures[3].raw.map(toBuffer)); + expect(tx.getDataFee()).toEqual(BigInt(1716)); + + tx = Transaction.fromValuesArray(txFixtures[3].raw.map(toBuffer), { freeze: false }); + expect(tx.getDataFee()).toEqual(BigInt(1716)); + }); + + it('getDataFee() -> should return correct data fee for istanbul', () => { + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }); + let tx = Transaction.fromTxData({}, { common }); + expect(tx.getDataFee()).toEqual(BigInt(0)); + + tx = Transaction.fromValuesArray(txFixtures[3].raw.map(toBuffer), { + common, + }); + expect(tx.getDataFee()).toEqual(BigInt(1716)); + }); + + it('getDataFee() -> should invalidate cached value on hardfork change', () => { + const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Byzantium }); + const tx = Transaction.fromValuesArray(txFixtures[0].raw.map(toBuffer), { + common, + }); + expect(tx.getDataFee()).toEqual(BigInt(656)); + tx.common.setHardfork(Hardfork.Istanbul); + expect(tx.getDataFee()).toEqual(BigInt(240)); + }); + + it('getUpfrontCost() -> should return upfront cost', () => { + const tx = Transaction.fromTxData({ + gasPrice: 1000, + gasLimit: 10000000, + value: 42, + }); + expect(tx.getUpfrontCost()).toEqual(BigInt(10000000042)); + }); + + it('serialize()', () => { + for (const [i, tx] of transactions.entries()) { + const s1 = tx.serialize(); + const s2 = Buffer.from(RLP.encode(txFixtures[i].raw)); + expect(s1.equals(s2)).toBe(true); + } + }); + + it('serialize() -> should round trip decode a tx', () => { + const tx = Transaction.fromTxData({ value: 5000 }); + const s1 = tx.serialize(); + + const s1Rlp = toBuffer(`0x${s1.toString('hex')}`); + const tx2 = Transaction.fromSerializedTx(s1Rlp); + const s2 = tx2.serialize(); + + expect(s1.equals(s2)).toBe(true); + }); + + it('hash() / getMessageToSign(true) / getMessageToSign(false)', () => { + const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.TangerineWhistle, + }); + + let tx = Transaction.fromValuesArray(txFixtures[3].raw.slice(0, 6).map(toBuffer), { + common, + }); + expect(() => { + tx.hash(); + }).toThrow(); + tx = Transaction.fromValuesArray(txFixtures[3].raw.map(toBuffer), { + common, + }); + expect(tx.hash()).toEqual( + Buffer.from('375a8983c9fc56d7cfd118254a80a8d7403d590a6c9e105532b67aca1efb97aa', 'hex'), + ); + expect(tx.getMessageToSign()).toEqual( + Buffer.from('61e1ec33764304dddb55348e7883d4437426f44ab3ef65e6da1e025734c03ff0', 'hex'), + ); + expect(tx.getMessageToSign(false)).toHaveLength(6); + expect(tx.hash()).toEqual( + Buffer.from('375a8983c9fc56d7cfd118254a80a8d7403d590a6c9e105532b67aca1efb97aa', 'hex'), + ); + }); + + it('hash() -> with defined chainId', () => { + const tx = Transaction.fromValuesArray(txFixtures[4].raw.map(toBuffer)); + expect(tx.hash().toString('hex')).toBe( + '0f09dc98ea85b7872f4409131a790b91e7540953992886fc268b7ba5c96820e4', + ); + expect(tx.hash().toString('hex')).toBe( + '0f09dc98ea85b7872f4409131a790b91e7540953992886fc268b7ba5c96820e4', + ); + expect(tx.getMessageToSign().toString('hex')).toBe( + 'f97c73fdca079da7652dbc61a46cd5aeef804008e057be3e712c43eac389aaf0', + ); + }); + + it("getMessageToSign(), getSenderPublicKey() (implicit call) -> verify EIP155 signature based on Vitalik's tests", () => { + for (const tx of txFixturesEip155) { + const pt = Transaction.fromSerializedTx(toBuffer(tx.rlp)); + expect(pt.getMessageToSign().toString('hex')).toEqual(tx.hash); + expect(`0x${pt.serialize().toString('hex')}`).toEqual(tx.rlp); + expect(pt.getSenderAddress().toString()).toBe(`0x${tx.sender}`); + } + }); + + it('getMessageToSign(), sign(), getSenderPublicKey() (implicit call) -> verify EIP155 signature before and after signing', () => { + // Inputs and expected results for this test are taken directly from the example in https://eips.ethereum.org/EIPS/eip-155 + const txRaw = [ + '0x09', + '0x4a817c800', + '0x5208', + '0x3535353535353535353535353535353535353535', + '0x0de0b6b3a7640000', + '0x', + ]; + const privateKey = Buffer.from( + '4646464646464646464646464646464646464646464646464646464646464646', + 'hex', + ); + const pt = Transaction.fromValuesArray(txRaw.map(toBuffer)); + + // Note that Vitalik's example has a very similar value denoted "signing data". + // It's not the output of `serialize()`, but the pre-image of the hash returned by `tx.hash(false)`. + // We don't have a getter for such a value in Transaction. + expect(pt.serialize().toString('hex')).toBe( + 'ec098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a764000080808080', + ); + const signedTx = pt.sign(privateKey); + expect(signedTx.getMessageToSign().toString('hex')).toBe( + 'daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53', + ); + expect(signedTx.serialize().toString('hex')).toBe( + 'f86c098504a817c800825208943535353535353535353535353535353535353535880de0b6b3a76400008025a028ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa636276a067cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d83', + ); + }); + + it('sign(), getSenderPublicKey() (implicit call) -> EIP155 hashing when singing', () => { + const common = new Common({ chain: 1, hardfork: Hardfork.Petersburg }); + for (const txData of txFixtures.slice(0, 3)) { + const tx = Transaction.fromValuesArray(txData.raw.slice(0, 6).map(toBuffer), { + common, + }); + + const privKey = Buffer.from(txData.privateKey, 'hex'); + const txSigned = tx.sign(privKey); + + expect(txSigned.getSenderAddress().toString()).toBe(`0x${txData.sendersAddress}`); + } + }); + + it('sign(), serialize(): serialize correctly after being signed with EIP155 Signature for tx created on ropsten', () => { + const txRaw = [ + '0x1', + '0x02540be400', + '0x5208', + '0xd7250824390ec5c8b71d856b5de895e271170d9d', + '0x0de0b6b3a7640000', + '0x', + ]; + const privateKey = Buffer.from( + 'DE3128752F183E8930D7F00A2AAA302DCB5E700B2CBA2D8CA5795660F07DEFD5', + 'hex', + ); + const common = new Common({ chain: 1 }); + const tx = Transaction.fromValuesArray(txRaw.map(toBuffer), { common }); + const signedTx = tx.sign(privateKey); + expect(signedTx.serialize().toString('hex')).toBe( + 'f86c018502540be40082520894d7250824390ec5c8b71d856b5de895e271170d9d880de0b6b3a76400008026a05e5c85a426b11e1ba5d9b567e904818a33975962942f538d247cd7391f5fb27aa00c8ec23ca4a3cdc2515916e4adc89676ce124fd7d0ddbb3ddd37c441dd584c21', + ); + }); + + it('sign(), verifySignature(): should ignore any previous signature when decided if EIP155 should be used in a new one', () => { + const txData: TxData = { + data: '0x7cf5dab00000000000000000000000000000000000000000000000000000000000000005', + gasLimit: '0x15f90', + gasPrice: '0x1', + nonce: '0x01', + to: '0xd9024df085d09398ec76fbed18cac0e1149f50dc', + value: '0x0', + }; + + const privateKey = Buffer.from( + '4646464646464646464646464646464646464646464646464646464646464646', + 'hex', + ); + + const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.TangerineWhistle, + }); + + const fixtureTxSignedWithoutEIP155 = Transaction.fromTxData(txData, { + common, + }).sign(privateKey); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + let signedWithEIP155 = Transaction.fromTxData(txData).sign(privateKey); + + expect(signedWithEIP155.verifySignature()).toBe(true); + expect(signedWithEIP155.v?.toString(16)).not.toBe('1c'); + expect(signedWithEIP155.v?.toString(16)).not.toBe('1b'); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + signedWithEIP155 = Transaction.fromTxData(fixtureTxSignedWithoutEIP155.toJSON()).sign( + privateKey, + ); + + expect(signedWithEIP155.verifySignature()).toBe(true); + expect(signedWithEIP155.v?.toString(16)).not.toBe('1c'); + expect(signedWithEIP155.v?.toString(16)).not.toBe('1b'); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + let signedWithoutEIP155 = Transaction.fromTxData(txData, { + common, + }).sign(privateKey); + + expect(signedWithoutEIP155.verifySignature()).toBe(true); + expect( + signedWithoutEIP155.v?.toString(16) === '1c' || + signedWithoutEIP155.v?.toString(16) === '1b', + ).toBe(true); + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + signedWithoutEIP155 = Transaction.fromTxData(txData, { + common, + }).sign(privateKey); + + expect(signedWithoutEIP155.verifySignature()).toBe(true); + expect( + signedWithoutEIP155.v?.toString(16) === '1c' || + signedWithoutEIP155.v?.toString(16) === '1b', + ).toBe(true); + }); + + it('constructor: throw on legacy transactions which have v !== 27 and v !== 28 and v < 37', () => { + function getTxData(v: number) { + return { + v, + }; + } + for (let n = 0; n < 27; n += 1) { + expect(() => Transaction.fromTxData(getTxData(n))).toThrow(); + } + expect(() => Transaction.fromTxData(getTxData(29))).toThrow(); + expect(() => Transaction.fromTxData(getTxData(36))).toThrow(); + + expect(() => Transaction.fromTxData(getTxData(27))).not.toThrow(); + expect(() => Transaction.fromTxData(getTxData(28))).not.toThrow(); + expect(() => Transaction.fromTxData(getTxData(37))).not.toThrow(); + }); + + it('sign(), verifySignature(): sign tx with chainId specified in params', () => { + const common = new Common({ chain: Chain.Goerli, hardfork: Hardfork.Petersburg }); + let tx = Transaction.fromTxData({}, { common }); + expect(tx.common.chainId()).toEqual(BigInt(5)); + + const privKey = Buffer.from(txFixtures[0].privateKey, 'hex'); + tx = tx.sign(privKey); + + const serialized = tx.serialize(); + + const reTx = Transaction.fromSerializedTx(serialized, { common }); + expect(reTx.verifySignature()).toBe(true); + expect(reTx.common.chainId()).toEqual(BigInt(5)); + }); + + it('freeze property propagates from unsigned tx to signed tx', () => { + const tx = Transaction.fromTxData({}, { freeze: false }); + expect(Object.isFrozen(tx)).toBe(false); + const privKey = Buffer.from(txFixtures[0].privateKey, 'hex'); + const signedTxn = tx.sign(privKey); + expect(Object.isFrozen(signedTxn)).toBe(false); + }); + + it('common propagates from the common of tx, not the common in TxOptions', () => { + const common = new Common({ chain: Chain.Goerli, hardfork: Hardfork.London }); + const pkey = Buffer.from(txFixtures[0].privateKey, 'hex'); + const txn = Transaction.fromTxData({}, { common, freeze: false }); + const newCommon = new Common({ + chain: Chain.Goerli, + hardfork: Hardfork.London, + eips: [2537], + }); + expect(newCommon).not.toEqual(common); + Object.defineProperty(txn, 'common', { + get() { + return newCommon; + }, + }); + const signedTxn = txn.sign(pkey); + expect(signedTxn.common.eips()).toContain(2537); + }); + + it('isSigned() -> returns correct values', () => { + let tx = Transaction.fromTxData({}); + expect(tx.isSigned()).toBe(false); + + const txData: TxData = { + data: '0x7cf5dab00000000000000000000000000000000000000000000000000000000000000005', + gasLimit: '0x15f90', + gasPrice: '0x1', + nonce: '0x01', + to: '0xd9024df085d09398ec76fbed18cac0e1149f50dc', + value: '0x0', + }; + const privateKey = Buffer.from( + '4646464646464646464646464646464646464646464646464646464646464646', + 'hex', + ); + tx = Transaction.fromTxData(txData); + expect(tx.isSigned()).toBe(false); + tx = tx.sign(privateKey); + expect(tx.isSigned()).toBe(true); + + tx = Transaction.fromTxData(txData); + expect(tx.isSigned()).toBe(false); + const rawUnsigned = tx.serialize(); + tx = tx.sign(privateKey); + const rawSigned = tx.serialize(); + expect(tx.isSigned()).toBe(true); + + tx = Transaction.fromSerializedTx(rawUnsigned); + expect(tx.isSigned()).toBe(false); + tx = tx.sign(privateKey); + expect(tx.isSigned()).toBe(true); + tx = Transaction.fromSerializedTx(rawSigned); + expect(tx.isSigned()).toBe(true); + + const signedValues = arrToBufArr(RLP.decode(Uint8Array.from(rawSigned))) as Buffer[]; + tx = Transaction.fromValuesArray(signedValues); + expect(tx.isSigned()).toBe(true); + tx = Transaction.fromValuesArray(signedValues.slice(0, 6)); + expect(tx.isSigned()).toBe(false); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/transactionFactory.test.ts b/packages/web3-eth-accounts/test/unit/tx/transactionFactory.test.ts new file mode 100644 index 00000000000..5881465917d --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/transactionFactory.test.ts @@ -0,0 +1,147 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Chain, Common, Hardfork } from '../../../src/common'; + +import { + AccessListEIP2930Transaction, + FeeMarketEIP1559Transaction, + Transaction, + TransactionFactory, +} from '../../../src'; + +const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.London, +}); + +const pKey = Buffer.from('4646464646464646464646464646464646464646464646464646464646464646', 'hex'); + +const unsignedTx = Transaction.fromTxData({}); +const signedTx = unsignedTx.sign(pKey); + +const unsignedEIP2930Tx = AccessListEIP2930Transaction.fromTxData( + { chainId: BigInt(1) }, + { common }, +); +const signedEIP2930Tx = unsignedEIP2930Tx.sign(pKey); + +const unsignedEIP1559Tx = FeeMarketEIP1559Transaction.fromTxData( + { chainId: BigInt(1) }, + { common }, +); +const signedEIP1559Tx = unsignedEIP1559Tx.sign(pKey); + +const txTypes = [ + { + class: Transaction, + name: 'Transaction', + unsigned: unsignedTx, + signed: signedTx, + eip2718: false, + type: 0, + }, + { + class: AccessListEIP2930Transaction, + name: 'AccessListEIP2930Transaction', + unsigned: unsignedEIP2930Tx, + signed: signedEIP2930Tx, + eip2718: true, + type: 1, + }, + { + class: FeeMarketEIP1559Transaction, + name: 'FeeMarketEIP1559Transaction', + unsigned: unsignedEIP1559Tx, + signed: signedEIP1559Tx, + eip2718: true, + type: 2, + }, +]; + +describe('[TransactionFactory]: Basic functions', () => { + it('fromSerializedData() -> success cases', () => { + for (const txType of txTypes) { + const serialized = txType.unsigned.serialize(); + const factoryTx = TransactionFactory.fromSerializedData(serialized, { common }); + expect(factoryTx.constructor.name).toEqual(txType.class.name); + } + }); + + it('fromSerializedData() -> error cases', () => { + for (const txType of txTypes) { + if (!txType.eip2718) { + continue; + } + const unsupportedCommon = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Istanbul, + }); + expect(() => { + TransactionFactory.fromSerializedData(txType.unsigned.serialize(), { + common: unsupportedCommon, + }); + }).toThrow(); + + expect(() => { + const serialized = txType.unsigned.serialize(); + serialized[0] = 99; // edit the transaction type + TransactionFactory.fromSerializedData(serialized, { common }); + }).toThrow(); + } + }); + + it('fromBlockBodyData() -> success cases', () => { + for (const txType of txTypes) { + let rawTx; + if (txType.eip2718) { + rawTx = txType.signed.serialize(); + } else { + rawTx = txType.signed.raw() as Buffer[]; + } + const tx = TransactionFactory.fromBlockBodyData(rawTx, { common }); + expect(tx.constructor.name).toEqual(txType.name); + expect(txType.eip2718 ? tx.serialize() : tx.raw()).toEqual(rawTx); + } + }); + + it('fromTxData() -> success cases', () => { + for (const txType of txTypes) { + const tx = TransactionFactory.fromTxData({ type: txType.type }, { common }); + expect(tx.constructor.name).toEqual(txType.class.name); + if (txType.eip2718) { + continue; + } + const _tx = TransactionFactory.fromTxData({}); + expect(_tx.constructor.name).toEqual(txType.class.name); + } + }); + + it('fromTxData() -> error cases', () => { + const unsupportedCommon = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }); + expect(() => { + TransactionFactory.fromTxData({ type: 1 }, { common: unsupportedCommon }); + }).toThrow(); + + expect(() => { + TransactionFactory.fromTxData({ type: 999 }); + }).toThrow(); + + expect(() => { + TransactionFactory.fromTxData({ value: BigInt('-100') }); + }).toThrow(); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/typedTxsAndEIP2930.test.ts b/packages/web3-eth-accounts/test/unit/tx/typedTxsAndEIP2930.test.ts new file mode 100644 index 00000000000..ddfc479da2a --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/typedTxsAndEIP2930.test.ts @@ -0,0 +1,574 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Point } from 'ethereum-cryptography/secp256k1'; +import { Chain, Common, Hardfork } from '../../../src/common'; +import { + bufferToBigInt, + bufferToHex, + AccessListEIP2930Transaction, + FeeMarketEIP1559Transaction, +} from '../../../src'; +import { Address } from '../../../src/tx/address'; +import { MAX_INTEGER, MAX_UINT64, SECP256K1_ORDER_DIV_2 } from '../../../src/tx/constants'; + +import type { AccessList, AccessListBufferItem } from '../../../src'; + +const privateToPublic = function (privateKey: Buffer): Buffer { + return Buffer.from(Point.fromPrivateKey(privateKey).toRawBytes(false).slice(1)); +}; +const pKey = Buffer.from('4646464646464646464646464646464646464646464646464646464646464646', 'hex'); +const address = Address.publicToAddress(privateToPublic(pKey)); + +const common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.London, +}); + +const txTypes = [ + { + class: AccessListEIP2930Transaction, + name: 'AccessListEIP2930Transaction', + type: 1, + }, + { + class: FeeMarketEIP1559Transaction, + name: 'FeeMarketEIP1559Transaction', + type: 2, + }, +]; + +const validAddress = Buffer.from('01'.repeat(20), 'hex'); +const validSlot = Buffer.from('01'.repeat(32), 'hex'); +const chainId = BigInt(1); + +describe('[AccessListEIP2930Transaction / FeeMarketEIP1559Transaction] -> EIP-2930 Compatibility', () => { + it('Initialization / Getter -> fromTxData()', () => { + for (const txType of txTypes) { + let tx = txType.class.fromTxData({}, { common }); + expect(tx).toBeTruthy(); + + tx = txType.class.fromTxData({ + chainId: 5, + }); + expect(tx.common.chainId() === BigInt(5)).toBeTruthy(); + + tx = txType.class.fromTxData({ + chainId: 99999, + }); + expect(tx.common.chainId() === BigInt(99999)).toBeTruthy(); + + const nonEIP2930Common = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.Istanbul, + }); + expect(() => { + txType.class.fromTxData({}, { common: nonEIP2930Common }); + }).toThrow(); + + expect(() => { + txType.class.fromTxData( + { + chainId: chainId + BigInt(1), + }, + { common }, + ); + }).toThrow(); + + expect(() => { + txType.class.fromTxData( + { + v: 2, + }, + { common }, + ); + }).toThrow(); + } + }); + + it('cannot input decimal values', () => { + const values = ['chainId', 'nonce', 'gasPrice', 'gasLimit', 'value', 'v', 'r', 's']; + const cases = [ + 10.1, + '10.1', + '0xaa.1', + -10.1, + -1, + BigInt(-10), + '-100', + '-10.1', + '-0xaa', + Infinity, + -Infinity, + NaN, + {}, + true, + false, + // eslint-disable-next-line @typescript-eslint/no-empty-function + () => {}, + Number.MAX_SAFE_INTEGER + 1, + ]; + for (const value of values) { + const txData: any = {}; + for (const testCase of cases) { + if ( + value === 'chainId' && + ((typeof testCase === 'number' && Number.isNaN(testCase)) || testCase === false) + ) { + continue; + } + txData[value] = testCase; + expect(() => { + AccessListEIP2930Transaction.fromTxData(txData); + }).toThrow(); + } + } + }); + + it('Initialization / Getter -> fromSerializedTx()', () => { + for (const txType of txTypes) { + expect(() => { + txType.class.fromSerializedTx(Buffer.from([99]), {}); + }).toThrow('wrong tx type'); + + expect(() => { + // Correct tx type + RLP-encoded 5 + const serialized = Buffer.concat([Buffer.from([txType.type]), Buffer.from([5])]); + txType.class.fromSerializedTx(serialized, {}); + }).toThrow('must be array'); + + expect(() => { + const serialized = Buffer.concat([ + Buffer.from([txType.type]), + Buffer.from('c0', 'hex'), + ]); + txType.class.fromSerializedTx(serialized, {}); + }).toThrow('values (for unsigned tx)'); + } + }); + + it('Access Lists -> success cases', () => { + for (const txType of txTypes) { + const access: AccessList = [ + { + address: bufferToHex(validAddress), + storageKeys: [bufferToHex(validSlot)], + }, + ]; + const txn = txType.class.fromTxData( + { + accessList: access, + chainId: 1, + }, + { common }, + ); + + // Check if everything is converted + + const BufferArray = txn.accessList; + const JSON = txn.AccessListJSON; + + expect(BufferArray[0][0].equals(validAddress)).toBeTruthy(); + expect(BufferArray[0][1][0].equals(validSlot)).toBeTruthy(); + + expect(JSON).toEqual(access); + + // also verify that we can always get the json access list, even if we don't provide one. + + const txnRaw = txType.class.fromTxData( + { + accessList: BufferArray, + chainId: 1, + }, + { common }, + ); + + const JSONRaw = txnRaw.AccessListJSON; + + expect(JSONRaw).toEqual(access); + } + }); + + it('Access Lists -> error cases', () => { + for (const txType of txTypes) { + let accessList: any[] = [ + [ + Buffer.from('01'.repeat(21), 'hex'), // Address of 21 bytes instead of 20 + [], + ], + ]; + + expect(() => { + txType.class.fromTxData({ chainId, accessList }, { common }); + }).toThrow(); + + accessList = [ + [ + validAddress, + [ + Buffer.from('01'.repeat(31), 'hex'), // Slot of 31 bytes instead of 32 + ], + ], + ]; + + expect(() => { + txType.class.fromTxData({ chainId, accessList }, { common }); + }).toThrow(); + + accessList = [[]]; // Address does not exist + + expect(() => { + txType.class.fromTxData({ chainId, accessList }, { common }); + }).toThrow(); + + accessList = [[validAddress]]; // Slots does not exist + + expect(() => { + txType.class.fromTxData({ chainId, accessList }, { common }); + }).toThrow(); + + accessList = [[validAddress, validSlot]]; // Slots is not an array + + expect(() => { + txType.class.fromTxData({ chainId, accessList }, { common }); + }).toThrow(); + + accessList = [[validAddress, [], []]]; // 3 items where 2 are expected + + expect(() => { + txType.class.fromTxData({ chainId, accessList }, { common }); + }).toThrow(); + } + }); + + it('sign()', () => { + for (const txType of txTypes) { + let tx = txType.class.fromTxData( + { + data: Buffer.from('010200', 'hex'), + to: validAddress, + accessList: [[validAddress, [validSlot]]], + chainId, + }, + { common }, + ); + let signed = tx.sign(pKey); + const signedAddress = signed.getSenderAddress(); + expect(signedAddress.buf.equals(address)).toBeTruthy(); + // expect(signedAddress).toEqual(Address.publicToAddress(Buffer.from(address))); + signed.verifySignature(); // If this throws, test will not end. + + tx = txType.class.fromTxData({}, { common }); + signed = tx.sign(pKey); + + expect(tx.accessList).toEqual([]); + expect(signed.accessList).toEqual([]); + + tx = txType.class.fromTxData({}, { common }); + + expect(() => { + tx.hash(); + }).toThrow(); + + expect(() => { + tx.getSenderPublicKey(); + }).toThrow(); + + expect(() => { + const high = SECP256K1_ORDER_DIV_2 + BigInt(1); + const _tx = txType.class.fromTxData({ s: high, r: 1, v: 1 }, { common }); + const _signed = _tx.sign(pKey); + _signed.getSenderPublicKey(); + }).toThrow(); + } + }); + + it('getDataFee()', () => { + for (const txType of txTypes) { + let tx = txType.class.fromTxData({}, { common }); + expect(tx.getDataFee()).toEqual(BigInt(0)); + + tx = txType.class.fromTxData({}, { common, freeze: false }); + expect(tx.getDataFee()).toEqual(BigInt(0)); + + const mutableCommon = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }); + tx = txType.class.fromTxData({}, { common: mutableCommon }); + tx.common.setHardfork(Hardfork.Istanbul); + expect(tx.getDataFee()).toEqual(BigInt(0)); + } + }); +}); + +describe('[AccessListEIP2930Transaction] -> Class Specific Tests', () => { + it('Initialization', () => { + const tx = AccessListEIP2930Transaction.fromTxData({}, { common }); + expect(AccessListEIP2930Transaction.fromTxData(tx, { common })).toBeTruthy(); + + const _validAddress = Buffer.from('01'.repeat(20), 'hex'); + const _validSlot = Buffer.from('01'.repeat(32), 'hex'); + const _chainId = BigInt(1); + expect(() => { + AccessListEIP2930Transaction.fromTxData( + { + data: Buffer.from('010200', 'hex'), + to: _validAddress, + accessList: [[_validAddress, [_validSlot]]], + chainId: _chainId, + gasLimit: MAX_UINT64, + gasPrice: MAX_INTEGER, + }, + { common }, + ); + }).toThrow('gasLimit * gasPrice cannot exceed MAX_INTEGER'); + + const buffer = Buffer.from([]); + const _address = Buffer.from([]); + const storageKeys = [Buffer.from([]), Buffer.from([])]; + const aclBuf: AccessListBufferItem = [_address, storageKeys]; + expect(() => { + AccessListEIP2930Transaction.fromValuesArray( + [buffer, buffer, buffer, buffer, buffer, buffer, buffer, [aclBuf], buffer], + {}, + ); + }).toThrow(); + }); + + it('should return right upfront cost', () => { + let tx = AccessListEIP2930Transaction.fromTxData( + { + data: Buffer.from('010200', 'hex'), + to: validAddress, + accessList: [[validAddress, [validSlot]]], + chainId, + }, + { common }, + ); + // Cost should be: + // Base fee + 2*TxDataNonZero + TxDataZero + AccessListAddressCost + AccessListSlotCost + const txDataZero = Number(common.param('gasPrices', 'txDataZero')); + const txDataNonZero = Number(common.param('gasPrices', 'txDataNonZero')); + const accessListStorageKeyCost = Number( + common.param('gasPrices', 'accessListStorageKeyCost'), + ); + const accessListAddressCost = Number(common.param('gasPrices', 'accessListAddressCost')); + const baseFee = Number(common.param('gasPrices', 'tx')); + const creationFee = Number(common.param('gasPrices', 'txCreation')); + + expect( + tx.getBaseFee() === + BigInt( + txDataNonZero * 2 + + txDataZero + + baseFee + + accessListAddressCost + + accessListStorageKeyCost, + ), + ).toBeTruthy(); + + // In this Tx, `to` is `undefined`, so we should charge homestead creation gas. + tx = AccessListEIP2930Transaction.fromTxData( + { + data: Buffer.from('010200', 'hex'), + accessList: [[validAddress, [validSlot]]], + chainId, + }, + { common }, + ); + + expect( + tx.getBaseFee() === + BigInt( + txDataNonZero * 2 + + txDataZero + + creationFee + + baseFee + + accessListAddressCost + + accessListStorageKeyCost, + ), + ).toBeTruthy(); + + // Explicitly check that even if we have duplicates in our list, we still charge for those + tx = AccessListEIP2930Transaction.fromTxData( + { + to: validAddress, + accessList: [ + [validAddress, [validSlot]], + [validAddress, [validSlot, validSlot]], + ], + chainId, + }, + { common }, + ); + + expect( + tx.getBaseFee() === + BigInt(baseFee + accessListAddressCost * 2 + accessListStorageKeyCost * 3), + ).toBeTruthy(); + }); + + it('getUpfrontCost() -> should return upfront cost', () => { + const tx = AccessListEIP2930Transaction.fromTxData( + { + gasPrice: 1000, + gasLimit: 10000000, + value: 42, + }, + { common }, + ); + expect(tx.getUpfrontCost()).toEqual(BigInt(10000000042)); + }); + + it('unsigned tx -> getMessageToSign()', () => { + const unsignedTx = AccessListEIP2930Transaction.fromTxData( + { + data: Buffer.from('010200', 'hex'), + to: validAddress, + accessList: [[validAddress, [validSlot]]], + chainId, + }, + { common }, + ); + const expectedHash = Buffer.from( + '78528e2724aa359c58c13e43a7c467eb721ce8d410c2a12ee62943a3aaefb60b', + 'hex', + ); + expect(unsignedTx.getMessageToSign(true)).toEqual(expectedHash); + + const expectedSerialization = Buffer.from( + '01f858018080809401010101010101010101010101010101010101018083010200f838f7940101010101010101010101010101010101010101e1a00101010101010101010101010101010101010101010101010101010101010101', + 'hex', + ); + expect(unsignedTx.getMessageToSign(false)).toEqual(expectedSerialization); + }); + + // Data from + // https://github.com/INFURA/go-ethlibs/blob/75b2a52a39d353ed8206cffaf68d09bd1b154aae/eth/transaction_signing_test.go#L87 + + it('should sign transaction correctly and return expected JSON', () => { + const _address = Buffer.from('0000000000000000000000000000000000001337', 'hex'); + const slot1 = Buffer.from( + '0000000000000000000000000000000000000000000000000000000000000000', + 'hex', + ); + const txData = { + data: Buffer.from('', 'hex'), + gasLimit: 0x62d4, + gasPrice: 0x3b9aca00, + nonce: 0x00, + to: new Address(Buffer.from('df0a88b2b68c673713a8ec826003676f272e3573', 'hex')), + value: 0x01, + chainId: bufferToBigInt(Buffer.from('796f6c6f763378', 'hex')), + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + accessList: [[_address, [slot1]]], + }; + + const customChainParams = { + name: 'custom', + chainId: txData.chainId, + eips: [2718, 2929, 2930], + }; + const usedCommon = Common.custom(customChainParams, { + baseChain: Chain.Mainnet, + hardfork: Hardfork.Berlin, + }); + usedCommon.setEIPs([2718, 2929, 2930]); + + const expectedUnsignedRaw = Buffer.from( + '01f86587796f6c6f76337880843b9aca008262d494df0a88b2b68c673713a8ec826003676f272e35730180f838f7940000000000000000000000000000000000001337e1a00000000000000000000000000000000000000000000000000000000000000000808080', + 'hex', + ); + const pkey = Buffer.from( + 'fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19', + 'hex', + ); + const expectedSigned = Buffer.from( + '01f8a587796f6c6f76337880843b9aca008262d494df0a88b2b68c673713a8ec826003676f272e35730180f838f7940000000000000000000000000000000000001337e1a0000000000000000000000000000000000000000000000000000000000000000080a0294ac94077b35057971e6b4b06dfdf55a6fbed819133a6c1d31e187f1bca938da00be950468ba1c25a5cb50e9f6d8aa13c8cd21f24ba909402775b262ac76d374d', + 'hex', + ); + const expectedHash = Buffer.from( + 'bbd570a3c6acc9bb7da0d5c0322fe4ea2a300db80226f7df4fef39b2d6649eec', + 'hex', + ); + const v = BigInt(0); + const r = bufferToBigInt( + Buffer.from('294ac94077b35057971e6b4b06dfdf55a6fbed819133a6c1d31e187f1bca938d', 'hex'), + ); + const s = bufferToBigInt( + Buffer.from('0be950468ba1c25a5cb50e9f6d8aa13c8cd21f24ba909402775b262ac76d374d', 'hex'), + ); + + const unsignedTx = AccessListEIP2930Transaction.fromTxData(txData, { common: usedCommon }); + + const serializedMessageRaw = unsignedTx.serialize(); + + expect(expectedUnsignedRaw.equals(serializedMessageRaw)).toBeTruthy(); + + const signed = unsignedTx.sign(pkey); + + expect(v === signed.v!).toBeTruthy(); + expect(r === signed.r!).toBeTruthy(); + expect(s === signed.s!).toBeTruthy(); + expect(expectedSigned.equals(signed.serialize())).toBeTruthy(); + expect(expectedHash.equals(signed.hash())).toBeTruthy(); + + const expectedJSON = { + chainId: '0x796f6c6f763378', + nonce: '0x0', + gasPrice: '0x3b9aca00', + gasLimit: '0x62d4', + to: '0xdf0a88b2b68c673713a8ec826003676f272e3573', + value: '0x1', + data: '0x', + accessList: [ + { + address: '0x0000000000000000000000000000000000001337', + storageKeys: [ + '0x0000000000000000000000000000000000000000000000000000000000000000', + ], + }, + ], + v: '0x0', + r: '0x294ac94077b35057971e6b4b06dfdf55a6fbed819133a6c1d31e187f1bca938d', + s: '0xbe950468ba1c25a5cb50e9f6d8aa13c8cd21f24ba909402775b262ac76d374d', + }; + + expect(signed.toJSON()).toEqual(expectedJSON); + }); + + it('freeze property propagates from unsigned tx to signed tx', () => { + const tx = AccessListEIP2930Transaction.fromTxData({}, { freeze: false }); + expect(Object.isFrozen(tx)).toBe(false); + const signedTxn = tx.sign(pKey); + expect(Object.isFrozen(signedTxn)).toBe(false); + }); + + it('common propagates from the common of tx, not the common in TxOptions', () => { + const txn = AccessListEIP2930Transaction.fromTxData({}, { common, freeze: false }); + const newCommon = new Common({ + chain: Chain.Mainnet, + hardfork: Hardfork.London, + eips: [2537], + }); + expect(newCommon).not.toEqual(common); + Object.defineProperty(txn, 'common', { + get() { + return newCommon; + }, + }); + const signedTxn = txn.sign(pKey); + expect(signedTxn.common.eips().includes(2537)).toBeTruthy(); + }); +}); diff --git a/packages/web3-eth-accounts/test/unit/tx/types.ts b/packages/web3-eth-accounts/test/unit/tx/types.ts new file mode 100644 index 00000000000..59579c036e5 --- /dev/null +++ b/packages/web3-eth-accounts/test/unit/tx/types.ts @@ -0,0 +1,78 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +export type ForkName = + | 'London+3860' + | 'London' + | 'Berlin' + | 'Istanbul' + | 'Byzantium' + | 'ConstantinopleFix' + | 'Constantinople' + | 'EIP150' + | 'EIP158' + | 'Frontier' + | 'Homestead'; + +export type ForkNamesMap = { [forkName in ForkName]: string }; + +export interface TxData { + data: string; + gasLimit: string; + gasPrice: string; + nonce: string; + to: string; + value: string; + + v: string; + r: string; + s: string; +} + +// The type of each entry from ./ttTransactionTestEip155VitaliksTests.json +export interface VitaliksTestsDataEntry { + blocknumber: string; + hash: string; + rlp: string; + sender: string; + transaction: TxData; +} + +// The type of ./txs.json +export type TxsJsonEntry = { + privateKey: string; + sendersAddress: string; + type: string; + cost: number; + raw: string[]; + data: TxData; +}; + +export type ForksData = { + [forkName in ForkName]: { hash?: string; sender?: string; exception?: string }; +}; + +export type OfficialTransactionTestData = { + _info: { + comment: string; + filledwith: string; + lllcversion: string; + source: string; + sourceHash: string; + }; + result: ForksData; + txbytes: string; +}; diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 0ebabd10de6..09fd61d5211 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -118,3 +118,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `signTransaction` will now return `gas` instead of `gasLimit` for returned transaction object regardless of what property name the provider uses (#5915) - `formatTransaction` will now replace `data` transaction property with `input` (#5915) - `isTransactionCall` will now check if `value.input` `isHexStrict` if provided (#5915) + +### Added + +- Added source files (#5956) + +### Removed + +- Removed dependencies @ethereumjs/tx, @ethereumjs/common (#5963) diff --git a/packages/web3-eth/package.json b/packages/web3-eth/package.json index bd7918be097..8c1c4d78799 100644 --- a/packages/web3-eth/package.json +++ b/packages/web3-eth/package.json @@ -61,8 +61,6 @@ "web3-providers-http": "^4.0.1-rc.0" }, "dependencies": { - "@ethereumjs/common": "^2.6.5", - "@ethereumjs/tx": "^3.5.2", "setimmediate": "^1.0.5", "web3-core": "^4.0.1-rc.0", "web3-errors": "^1.0.0-rc.0", diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index a84e795328d..b4c4e5cf6ba 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -54,6 +54,7 @@ import { hexToBytes, bytesToBuffer, } from 'web3-utils'; +import { TransactionFactory } from 'web3-eth-accounts'; import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator'; import { ContractExecutionError, @@ -64,8 +65,6 @@ import { TransactionRevertWithCustomError, } from 'web3-errors'; import { ethRpcMethods } from 'web3-rpc-methods'; -import defaultImport, * as fullImport from '@ethereumjs/tx'; - import { decodeSignedTransaction } from './utils/decode_signed_transaction'; import { accountSchema, @@ -98,8 +97,6 @@ import { getTransactionError } from './utils/get_transaction_error'; // eslint-disable-next-line import/no-cycle import { getRevertReason } from './utils/get_revert_reason'; -const { TransactionFactory } = defaultImport || fullImport; - /** * * @param web3Context ({@link Web3Context}) Web3 configuration object that contains things such as the provider, request manager, wallet, etc. diff --git a/packages/web3-eth/src/utils/decode_signed_transaction.ts b/packages/web3-eth/src/utils/decode_signed_transaction.ts index a36879fc255..91074eac957 100644 --- a/packages/web3-eth/src/utils/decode_signed_transaction.ts +++ b/packages/web3-eth/src/utils/decode_signed_transaction.ts @@ -14,14 +14,12 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import defaultImport, * as fullImport from '@ethereumjs/tx'; import { HexStringBytes, SignedTransactionInfoAPI, TransactionSignedAPI } from 'web3-types'; import { bytesToHex, DataFormat, format, hexToBytes, keccak256 } from 'web3-utils'; +import { TransactionFactory } from 'web3-eth-accounts'; import { detectRawTransactionType } from './detect_transaction_type'; import { formatTransaction } from './format_transaction'; -const { TransactionFactory } = defaultImport || fullImport; - /** * Decodes an [RLP](https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/#top) encoded transaction. * diff --git a/packages/web3-eth/src/utils/prepare_transaction_for_signing.ts b/packages/web3-eth/src/utils/prepare_transaction_for_signing.ts index 2aa99552246..297838441f9 100644 --- a/packages/web3-eth/src/utils/prepare_transaction_for_signing.ts +++ b/packages/web3-eth/src/utils/prepare_transaction_for_signing.ts @@ -15,9 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import Common from '@ethereumjs/common'; -import defaultImport, * as fullImport from '@ethereumjs/tx'; -import { TxOptions } from '@ethereumjs/tx'; import { EthExecutionAPI, HexString, @@ -29,13 +26,12 @@ import { } from 'web3-types'; import { Web3Context } from 'web3-core'; import { FormatType, ETH_DATA_FORMAT, toNumber } from 'web3-utils'; +import { TransactionFactory, TxOptions, Common } from 'web3-eth-accounts'; import { isNullish } from 'web3-validator'; import { validateTransactionForSigning } from '../validation'; import { formatTransaction } from './format_transaction'; import { transactionBuilder } from './transaction_builder'; -const { TransactionFactory } = defaultImport || fullImport; - const getEthereumjsTxDataFromTransaction = ( transaction: FormatType, ) => ({ @@ -91,19 +87,34 @@ const getEthereumjsTransactionOptions = ( }, ); } - } else if (transaction.common) - common = Common.custom( - { - name: transaction.common.customChain.name ?? 'custom-network', - chainId: toNumber(transaction.common.customChain.chainId) as number, - networkId: toNumber(transaction.common.customChain.networkId) as number, - defaultHardfork: transaction.common.hardfork ?? web3Context.defaultHardfork, - }, - { - baseChain: transaction.common.baseChain ?? web3Context.defaultChain, - }, - ); + } else { + const name = + transaction?.common?.customChain?.name ?? transaction.chain ?? 'custom-network'; + const chainId = toNumber( + transaction?.common?.customChain?.chainId ?? transaction?.chainId, + ) as number; + const networkId = toNumber( + transaction?.common?.customChain?.networkId ?? transaction?.networkId, + ) as number; + const defaultHardfork = + transaction?.common?.hardfork ?? transaction?.hardfork ?? web3Context.defaultHardfork; + const baseChain = + transaction.common?.baseChain ?? transaction.chain ?? web3Context.defaultChain; + if (chainId && networkId && name) { + common = Common.custom( + { + name, + chainId, + networkId, + defaultHardfork, + }, + { + baseChain, + }, + ); + } + } return { common } as TxOptions; }; diff --git a/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts b/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts index bd3b0e360c7..c999535b4a9 100644 --- a/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts +++ b/packages/web3-eth/test/unit/prepare_transaction_for_signing.test.ts @@ -23,7 +23,7 @@ import { AccessListEIP2930Transaction, FeeMarketEIP1559Transaction, Transaction, -} from '@ethereumjs/tx'; +} from 'web3-eth-accounts'; import { ethRpcMethods } from 'web3-rpc-methods'; import { prepareTransactionForSigning } from '../../src/utils/prepare_transaction_for_signing'; @@ -35,7 +35,7 @@ describe('prepareTransactionForSigning', () => { config: { defaultNetworkId: '0x1' }, }); - describe('should return an @ethereumjs/tx instance with expected properties', () => { + describe('should return an web3-utils/tx instance with expected properties', () => { it.each(validTransactions)( 'mockBlock: %s\nexpectedTransaction: %s\nexpectedPrivateKey: %s\nexpectedAddress: %s\nexpectedRlpEncodedTransaction: %s\nexpectedTransactionHash: %s\nexpectedMessageToSign: %s\nexpectedV: %s\nexpectedR: %s\nexpectedS: %s', async ( @@ -60,7 +60,7 @@ describe('prepareTransactionForSigning', () => { expectedPrivateKey, ); - // should produce an @ethereumjs/tx instance + // should produce an web3-utils/tx instance expect( ethereumjsTx instanceof Transaction || ethereumjsTx instanceof AccessListEIP2930Transaction || @@ -90,13 +90,13 @@ describe('prepareTransactionForSigning', () => { // should have expected v, r, and s const v = !isNullish(signedTransaction.v) - ? `0x${signedTransaction.v.toString('hex')}` + ? `0x${signedTransaction.v.toString(16)}` : ''; const r = !isNullish(signedTransaction.r) - ? `0x${signedTransaction.r.toString('hex')}` + ? `0x${signedTransaction.r.toString(16)}` : ''; const s = !isNullish(signedTransaction.s) - ? `0x${signedTransaction.s.toString('hex')}` + ? `0x${signedTransaction.s.toString(16)}` : ''; expect(v).toBe(expectedV); expect(r).toBe(expectedR); diff --git a/packages/web3-utils/CHANGELOG.md b/packages/web3-utils/CHANGELOG.md index 73aac100038..13df2c6ec3d 100644 --- a/packages/web3-utils/CHANGELOG.md +++ b/packages/web3-utils/CHANGELOG.md @@ -95,3 +95,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added source files (#5956) - Added hybrid build (ESM and CJS) of library (#5904) + +### Removed + +- Removed dependencies @ethereumjs/tx, @ethereumjs/common (#5963) diff --git a/packages/web3-utils/src/converters.ts b/packages/web3-utils/src/converters.ts index d097022155b..1729006d381 100644 --- a/packages/web3-utils/src/converters.ts +++ b/packages/web3-utils/src/converters.ts @@ -17,21 +17,20 @@ along with web3.js. If not, see . import { Address, Bytes, HexString, Numbers, ValueTypes } from 'web3-types'; import { - validator, isAddress, - isHexStrict, isHex, - utils as validatorUtils, + isHexStrict, isNullish, + utils as validatorUtils, + validator, } from 'web3-validator'; import { keccak256 } from 'ethereum-cryptography/keccak'; - import { HexProcessingError, InvalidAddressError, InvalidBytesError, - InvalidUnitError, InvalidNumberError, + InvalidUnitError, } from 'web3-errors'; const base = BigInt(10); diff --git a/packages/web3-utils/src/validation.ts b/packages/web3-utils/src/validation.ts index 629f82e7539..37d5fb5257b 100644 --- a/packages/web3-utils/src/validation.ts +++ b/packages/web3-utils/src/validation.ts @@ -19,16 +19,16 @@ import { InvalidBlockError } from 'web3-errors'; import { checkAddressCheckSum as checkAddressCheckSumValidator, isAddress as isAddressValidator, + isBlockTag, isBloom as isBloomValidator, isContractAddressInBloom as isContractAddressInBloomValidator, isHex as isHexValidator, isHexStrict as isHexStrictValidator, isInBloom as isInBloomValidator, + isNullish as isNullishValidator, isTopic as isTopicValidator, isTopicInBloom as isTopicInBloomValidator, isUserEthereumAddressInBloom as isUserEthereumAddressInBloomValidator, - isNullish as isNullishValidator, - isBlockTag, } from 'web3-validator'; import { BlockNumberOrTag, BlockTags } from 'web3-types'; diff --git a/packages/web3-utils/src/web3_deferred_promise.ts b/packages/web3-utils/src/web3_deferred_promise.ts index 88f4b979ae5..f1a46c8ef03 100644 --- a/packages/web3-utils/src/web3_deferred_promise.ts +++ b/packages/web3-utils/src/web3_deferred_promise.ts @@ -17,6 +17,7 @@ along with web3.js. If not, see . import { OperationTimeoutError } from 'web3-errors'; import { Web3DeferredPromiseInterface } from 'web3-types'; + /** * The class is a simple implementation of a deferred promise with optional timeout functionality, * which can be useful when dealing with asynchronous tasks. diff --git a/packages/web3-validator/CHANGELOG.md b/packages/web3-validator/CHANGELOG.md index 826a96a71dc..d5cc1b5e45c 100644 --- a/packages/web3-validator/CHANGELOG.md +++ b/packages/web3-validator/CHANGELOG.md @@ -85,3 +85,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added source files (#5956) - Added hybrid build (ESM and CJS) of library (#5904) +- Added functions `isHexString`, `isHexPrefixed`, `validateNoLeadingZeroes` (#5963) diff --git a/packages/web3-validator/src/validation/string.ts b/packages/web3-validator/src/validation/string.ts index eb07993c301..e0c60bdd47f 100644 --- a/packages/web3-validator/src/validation/string.ts +++ b/packages/web3-validator/src/validation/string.ts @@ -25,6 +25,22 @@ export const isString = (value: ValidInputTypes) => typeof value === 'string'; export const isHexStrict = (hex: ValidInputTypes) => typeof hex === 'string' && /^((-)?0x[0-9a-f]+|(0x))$/i.test(hex); +/** + * Is the string a hex string. + * + * @param value + * @param length + * @returns output the string is a hex string + */ +export function isHexString(value: string, length?: number): boolean { + if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) return false; + + if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) + return false; + + return true; +} + export const isHex = (hex: ValidInputTypes): boolean => typeof hex === 'number' || typeof hex === 'bigint' || @@ -35,3 +51,38 @@ export const isHexString8Bytes = (value: string, prefixed = true) => export const isHexString32Bytes = (value: string, prefixed = true) => prefixed ? isHexStrict(value) && value.length === 66 : isHex(value) && value.length === 64; + +/** + * Returns a `Boolean` on whether or not the a `String` starts with '0x' + * @param str the string input value + * @return a boolean if it is or is not hex prefixed + * @throws if the str input is not a string + */ +export function isHexPrefixed(str: string): boolean { + if (typeof str !== 'string') { + throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`); + } + + return str.startsWith('0x'); +} + +/** + * Checks provided Buffers for leading zeroes and throws if found. + * + * Examples: + * + * Valid values: 0x1, 0x, 0x01, 0x1234 + * Invalid values: 0x0, 0x00, 0x001, 0x0001 + * + * Note: This method is useful for validating that RLP encoded integers comply with the rule that all + * integer values encoded to RLP must be in the most compact form and contain no leading zero bytes + * @param values An object containing string keys and Buffer values + * @throws if any provided value is found to have leading zero bytes + */ +export const validateNoLeadingZeroes = function (values: { [key: string]: Buffer | undefined }) { + for (const [k, v] of Object.entries(values)) { + if (v !== undefined && v.length > 0 && v[0] === 0) { + throw new Error(`${k} cannot have leading zeroes, received: ${v.toString('hex')}`); + } + } +}; diff --git a/packages/web3-validator/test/fixtures/validation.ts b/packages/web3-validator/test/fixtures/validation.ts index f93d47c5fec..61a93ef6935 100644 --- a/packages/web3-validator/test/fixtures/validation.ts +++ b/packages/web3-validator/test/fixtures/validation.ts @@ -178,6 +178,65 @@ export const validHexData: any[] = [ BigInt(-255), ]; +export const isHexStringData: any[] = [ + { in: ['0x0000000000000000000000000000000000000000'], out: true }, + { in: ['0x0000000000000000000000000000000000000000', false], out: true }, + { in: ['0x0000000000000000000000000000000000000000', 2], out: false }, + { in: ['0x0000000000000000000000000000000000000000', undefined], out: true }, + { in: ['0x0001', 2], out: true }, + { in: ['0x0001', 3], out: false }, + { in: ['0x0001', 1], out: false }, + { in: ['123abcdefg'], out: false }, + { in: ['1x12345'], out: false }, + { in: ['123'], out: false }, + { in: [123], out: false }, + // eslint-disable-next-line no-null/no-null + { in: [null], out: false }, + { in: [false], out: false }, + { in: [{}], out: false }, +]; +export const isHexString8BytesData: any[] = [ + { in: ['0x0000000000000001', true], out: true }, + { in: ['0000000000000001', true], out: false }, + { in: ['0x0000000000000001', false], out: false }, + { in: ['0000000000000001', false], out: true }, + { in: [123, true], out: false }, + { in: [123, false], out: false }, + { in: [true, true], out: false }, + { in: [false, false], out: false }, + { in: [{}, true], out: false }, + { in: [{}, false], out: false }, +]; +export const isObjectData: any[] = [ + { in: 'asd', out: false }, + { in: [], out: false }, + { in: true, out: false }, + { in: false, out: false }, + { in: {}, out: true }, + // eslint-disable-next-line no-null/no-null + { in: null, out: false }, + { in: undefined, out: false }, + { in: Buffer.from('asd'), out: false }, +]; +export const isHexString32BytesData: any[] = [ + { in: ['0x0000000000000000000000000000000000000000000000000000000000000001', true], out: true }, + { in: ['0000000000000000000000000000000000000000000000000000000000000001', true], out: false }, + { + in: ['0x0000000000000000000000000000000000000000000000000000000000000001', false], + out: false, + }, + { in: ['0000000000000000000000000000000000000000000000000000000000000001', false], out: true }, + { in: [123, true], out: false }, + { in: [123, false], out: false }, + { in: [true, true], out: false }, + { in: [false, false], out: false }, + { in: [{}, true], out: false }, + { in: [{}, false], out: false }, +]; +export const isHexPrefixedData: any[] = [ + { in: '0x0000000000000000000000000000000000000000000000000000000000000001', out: true }, + { in: '0000000000000000000000000000000000000000000000000000000000000001', out: false }, +]; export const validStringNumbersWithHex: [string, string][] = [ ['72', '0x48'], ['4668', '0x123c'], @@ -394,7 +453,55 @@ export const validBooleanData: any[] = [true, false, 1, 0, '1', '0', '0x0', '0x1 export const invalidBooleanData = invalidHexStrictData.filter( data => data !== 1 && data !== 0 && data !== '0' && data !== '1' && typeof data !== 'boolean', ); - +export const isTopicData: any[] = [ + { in: '0x0000000000000000000000000000000000000000000000000000000000000000', out: true }, + { in: '0x000000000000000000000000000000000000000000000000000000000000001a', out: true }, + { in: '0x000000000000000000000000000000000000000000000000000000000000001A', out: true }, + { in: '0x00000000000000000000000000000000000000000000000000000000000001aA', out: false }, + { in: '0x00000000000000000000000000000000000000000000000000000000000000000', out: false }, + { in: '0x000000000000000000000000000000000000000000000000000000000000000', out: false }, + { in: 123, out: false }, + // eslint-disable-next-line no-null/no-null + { in: null, out: false }, + { in: false, out: false }, + { in: {}, out: false }, +]; +export const isTopicInBloomData: any[] = [ + { in: [123, ''], out: false }, + // eslint-disable-next-line no-null/no-null + { in: [null, ''], out: false }, + { in: [false, ''], out: false }, + { in: [{}, ''], out: false }, + { + in: [ + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + 123, + ], + out: false, + }, + { + in: [ + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + // eslint-disable-next-line no-null/no-null + null, + ], + out: false, + }, + { + in: [ + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + false, + ], + out: false, + }, + { + in: [ + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + {}, + ], + out: false, + }, +]; export const validFilterObjectData: Filter[] = [ { fromBlock: '0xc0ff3', diff --git a/packages/web3-validator/test/unit/validation/object.test.ts b/packages/web3-validator/test/unit/validation/object.test.ts new file mode 100644 index 00000000000..debd89ec2f5 --- /dev/null +++ b/packages/web3-validator/test/unit/validation/object.test.ts @@ -0,0 +1,29 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { isObject } from '../../../src/validation/object'; +import { isObjectData } from '../../fixtures/validation'; + +describe('validation', () => { + describe('object', () => { + describe('isObject', () => { + it.each(isObjectData)('%s', data => { + expect(isObject(data.in)).toBe(data.out); + }); + }); + }); +}); diff --git a/packages/web3-validator/test/unit/validation/string.test.ts b/packages/web3-validator/test/unit/validation/string.test.ts index 69d39aa16d8..c4dd5a126ed 100644 --- a/packages/web3-validator/test/unit/validation/string.test.ts +++ b/packages/web3-validator/test/unit/validation/string.test.ts @@ -14,13 +14,27 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ - -import { isString, isHex, isHexStrict } from '../../../src/validation/string'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { toBuffer } from 'web3-eth-accounts'; +import { + isString, + isHex, + isHexStrict, + isHexString, + isHexString8Bytes, + isHexString32Bytes, + isHexPrefixed, + validateNoLeadingZeroes, +} from '../../../src/validation/string'; import { invalidHexData, invalidHexStrictData, validHexStrictData, validHexData, + isHexStringData, + isHexString8BytesData, + isHexString32BytesData, + isHexPrefixedData, } from '../../fixtures/validation'; describe('validation', () => { @@ -65,5 +79,83 @@ describe('validation', () => { }); }); }); + describe('isHexString', () => { + it.each(isHexStringData)('%s', data => { + expect(isHexString(data.in[0], data.in[1])).toBe(data.out); + }); + }); + describe('isHexString8Bytes', () => { + it.each(isHexString8BytesData)('%s', data => { + expect(isHexString8Bytes(data.in[0], data.in[1])).toBe(data.out); + }); + }); + describe('isHexString32Bytes', () => { + it.each(isHexString32BytesData)('%s', data => { + expect(isHexString32Bytes(data.in[0], data.in[1])).toBe(data.out); + }); + }); + describe('isHexPrefixed', () => { + it.each(isHexPrefixedData)('%s', data => { + expect(isHexPrefixed(data.in)).toBe(data.out); + }); + it('should fails', () => { + expect(() => { + // @ts-expect-error no type validation + isHexPrefixed(1); + }).toThrow(`[isHexPrefixed] input must be type 'string', received type number`); + expect(() => { + // @ts-expect-error no type validation + isHexPrefixed(false); + }).toThrow(`[isHexPrefixed] input must be type 'string', received type boolean`); + expect(() => { + // @ts-expect-error no type validation + isHexPrefixed(true); + }).toThrow(`[isHexPrefixed] input must be type 'string', received type boolean`); + expect(() => { + // @ts-expect-error no type validation + isHexPrefixed({}); + }).toThrow(`[isHexPrefixed] input must be type 'string', received type object`); + expect(() => { + // @ts-expect-error no type validation + isHexPrefixed([]); + }).toThrow(`[isHexPrefixed] input must be type 'string', received type object`); + }); + }); + + describe('validateNoLeadingZeroes', () => { + it.each(isHexPrefixedData)('%s', data => { + expect(isHexPrefixed(data.in)).toBe(data.out); + }); + it('valid', () => { + const noLeadingZeroes = { + a: toBuffer('0x123'), + }; + const noleadingZeroBytes = { + a: toBuffer('0x01'), + }; + const emptyBuffer = { + a: toBuffer('0x'), + }; + const undefinedValue = { + a: undefined, + }; + + expect(() => validateNoLeadingZeroes(noLeadingZeroes)).not.toThrow(); + expect(() => validateNoLeadingZeroes(emptyBuffer)).not.toThrow(); + expect(() => validateNoLeadingZeroes(undefinedValue)).not.toThrow(); + expect(() => validateNoLeadingZeroes(noleadingZeroBytes)).not.toThrow(); + }); + it('fails', () => { + const leadingZeroBytes = { + a: toBuffer('0x001'), + }; + const onlyZeroes = { + a: toBuffer('0x0'), + }; + + expect(() => validateNoLeadingZeroes(leadingZeroBytes)).toThrow(); + expect(() => validateNoLeadingZeroes(onlyZeroes)).toThrow(); + }); + }); }); }); diff --git a/packages/web3-validator/test/unit/validation/topic.test.ts b/packages/web3-validator/test/unit/validation/topic.test.ts index b3f84dd3c72..fe062f8e9f5 100644 --- a/packages/web3-validator/test/unit/validation/topic.test.ts +++ b/packages/web3-validator/test/unit/validation/topic.test.ts @@ -16,7 +16,13 @@ along with web3.js. If not, see . */ import { isFilterObject } from '../../../src/validation/filter'; -import { invalidFilterObjectData, validFilterObjectData } from '../../fixtures/validation'; +import { + invalidFilterObjectData, + isTopicData, + isTopicInBloomData, + validFilterObjectData, +} from '../../fixtures/validation'; +import { isTopic, isTopicInBloom } from '../../../src/validation/topic'; describe('validation', () => { describe('filter', () => { @@ -34,4 +40,18 @@ describe('validation', () => { }); }); }); + describe('isTopic', () => { + describe('valid cases', () => { + it.each(isTopicData)('%s', data => { + expect(isTopic(data.in)).toBe(data.out); + }); + }); + }); + describe('isTopicInBloom', () => { + describe('valid cases', () => { + it.each(isTopicInBloomData)('%s', data => { + expect(isTopicInBloom(data.in[0], data.in[1])).toBe(data.out); + }); + }); + }); }); diff --git a/scripts/system_tests_utils.ts b/scripts/system_tests_utils.ts index a4d7227a02b..3e4bce79744 100644 --- a/scripts/system_tests_utils.ts +++ b/scripts/system_tests_utils.ts @@ -19,7 +19,6 @@ along with web3.js. If not, see . import { ETH_DATA_FORMAT, format, SocketProvider } from 'web3-utils'; // eslint-disable-next-line import/no-extraneous-dependencies import { - create, create as _createAccount, decrypt, privateKeyToAccount, @@ -193,7 +192,7 @@ export const createAccountProvider = (context: Web3Context) => }; const createWithContext = () => { - const account = create(); + const account = _createAccount(); return { ...account, @@ -259,7 +258,7 @@ const walletsOnWorker = 20; if (tempAccountList.length === 0) { tempAccountList = accountsString; } -let currentIndex = Math.floor(Math.random() * tempAccountList.length); +let currentIndex = Math.floor(Math.random() * (tempAccountList ? tempAccountList.length : 0)); export const createTempAccount = async ( config: { unlock?: boolean; @@ -313,23 +312,6 @@ export const getSystemTestAccountsWithKeys = async (): Promise< export const getSystemTestAccounts = async (): Promise => (await getSystemTestAccountsWithKeys()).map(a => a.address); -// export const signTxAndSend = async (tx: any, privateKey: string): Promise => { -// const web3 = new Web3(getSystemTestProvider()); -// const acc = web3.eth.accounts.privateKeyToAccount(privateKey); -// tx.gas = '0x5208'; -// tx.gasLimit = '4200000'; -// tx.from = acc.address; -// // tx.v = '0x1'; -// // tx.r = '0x0'; -// // tx.s = '0x0'; -// // x.gasPrice = '0x4a817c800'; -// // tx.maxFeePerGas = '0x1229298c00'; -// // tx.maxPriorityFeePerGas = '0x49504f80'; -// tx.type = '0x0'; -// const signedTx = await acc.signTransaction(tx); -// return web3.eth.sendSignedTransaction(signedTx.rawTransaction); -// }; - export const signTxAndSendEIP1559 = async ( provider: unknown, tx: Record, diff --git a/yarn.lock b/yarn.lock index 4f72b03a0ce..7a5c826b7f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -367,7 +367,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@ethereumjs/common@^2.4.0", "@ethereumjs/common@^2.6.4", "@ethereumjs/common@^2.6.5": +"@ethereumjs/common@^2.4.0", "@ethereumjs/common@^2.6.4": version "2.6.5" resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== @@ -375,7 +375,12 @@ crc-32 "^1.2.0" ethereumjs-util "^7.1.5" -"@ethereumjs/tx@^3.3.0", "@ethereumjs/tx@^3.5.2": +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/tx@^3.3.0": version "3.5.2" resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.2.tgz#197b9b6299582ad84f9527ca961466fce2296c1c" integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== @@ -4286,7 +4291,7 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -crc-32@^1.2.0: +crc-32@^1.2.0, crc-32@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==