@ethereumjs/tx
Advanced tools
Comparing version 4.2.0 to 5.0.0-rc.1
{ | ||
"name": "@ethereumjs/tx", | ||
"version": "4.2.0", | ||
"description": "A simple module for creating, manipulating and signing Ethereum transactions", | ||
"version": "5.0.0-rc.1", | ||
"description": "Implementation of the various Ethereum Transaction Types", | ||
"keywords": [ | ||
@@ -30,4 +30,11 @@ "ethereum", | ||
], | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"type": "commonjs", | ||
"main": "dist/cjs/index.js", | ||
"module": "dist/esm/index.js", | ||
"exports": { | ||
".": { | ||
"import": "./dist/esm/index.js", | ||
"require": "./dist/cjs/index.js" | ||
} | ||
}, | ||
"files": [ | ||
@@ -40,4 +47,4 @@ "dist", | ||
"clean": "../../config/cli/clean-package.sh", | ||
"coverage": "../../config/cli/coverage.sh", | ||
"docs:build": "typedoc --options typedoc.js", | ||
"coverage": "npx vitest run --coverage.enabled --coverage.reporter=lcov", | ||
"docs:build": "typedoc --options typedoc.cjs", | ||
"examples": "ts-node ../../scripts/examples-runner.ts -- tx", | ||
@@ -48,15 +55,21 @@ "lint": "../../config/cli/lint.sh", | ||
"prepublishOnly": "../../config/cli/prepublish.sh", | ||
"tape": "tape -r ts-node/register", | ||
"test": "npm run test:node && npm run test:browser && npm run test:txTests", | ||
"test:browser": "karma start karma.conf.js", | ||
"test:node": "tape -r ts-node/register -- 'test/**/*.spec.ts'", | ||
"test:txTests": "tape -r ts-node/register ./test/transactionRunner.ts", | ||
"test": "npm run test:node && npm run test:browser", | ||
"test:browser": "npx vitest run --config=./vitest.config.browser.ts --browser.name=chrome --browser.headless", | ||
"test:node": "npx vitest run", | ||
"tsc": "../../config/cli/ts-compile.sh" | ||
}, | ||
"dependencies": { | ||
"@ethereumjs/common": "^3.2.0", | ||
"@ethereumjs/rlp": "^4.0.1", | ||
"@ethereumjs/util": "^8.1.0", | ||
"ethereum-cryptography": "^2.0.0" | ||
"@ethereumjs/common": "4.0.0-rc.1", | ||
"@ethereumjs/rlp": "5.0.0-rc.1", | ||
"@ethereumjs/util": "9.0.0-rc.1", | ||
"ethereum-cryptography": "^2.1.2" | ||
}, | ||
"peerDependencies": { | ||
"c-kzg": "^2.1.0" | ||
}, | ||
"peerDependenciesMeta": { | ||
"c-kzg": { | ||
"optional": true | ||
} | ||
}, | ||
"devDependencies": { | ||
@@ -66,8 +79,7 @@ "@types/minimist": "^1.2.0", | ||
"minimist": "^1.2.0", | ||
"node-dir": "^0.1.16", | ||
"testdouble": "^3.17.2" | ||
"node-dir": "^0.1.16" | ||
}, | ||
"engines": { | ||
"node": ">=14" | ||
"node": ">=18" | ||
} | ||
} |
125
README.md
@@ -9,2 +9,4 @@ # @ethereumjs/tx | ||
Note: this README has been updated containing the changes from our next breaking release round [UNRELEASED] targeted for Summer 2023. See the README files from the [maintenance-v6](https://github.com/ethereumjs/ethereumjs-monorepo/tree/maintenance-v6/) branch for documentation matching our latest releases. | ||
| Implements schema and functions related to Ethereum's transaction. | | ||
@@ -36,3 +38,3 @@ | ------------------------------------------------------------------ | | ||
1. Install an additional dependency that supports the `kzg` interface defined in [the kzg interface](./src/kzg/kzg.ts). You can install the default option [c-kzg](https://github.com/ethereum/c-kzg-4844) by simply running `npm install c-kzg`. | ||
2. Download the trusted setup required for the KZG module. It can be found [here](../client/lib/trustedSetups/trusted_setup.txt) within the client package. | ||
2. Download the trusted setup required for the KZG module. It can be found [here](../client/src/trustedSetups/trusted_setup.txt) within the client package. | ||
@@ -44,2 +46,4 @@ #### Global Initialization | ||
```typescript | ||
import { initKZG } from '@ethereumjs/util' | ||
// Make the kzg library available globally | ||
@@ -59,4 +63,4 @@ import * as kzg from 'c-kzg' | ||
- `public static fromTxData(txData: TxData, opts: TxOptions = {})`: instantiate from a data dictionary | ||
- `public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {})`: instantiate from a serialized tx | ||
- `public static fromValuesArray(values: Buffer[], opts: TxOptions = {})`: instantiate from a values array | ||
- `public static fromSerializedTx(serialized: Uint8Array, opts: TxOptions = {})`: instantiate from a serialized tx | ||
- `public static fromValuesArray(values: Uint8Array[], opts: TxOptions = {})`: instantiate from a values array | ||
@@ -69,8 +73,6 @@ See one of the code examples on the tx types below on how to use. | ||
The `Transaction` constructor receives a parameter of an [`@ethereumjs/common`](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/common) object that lets you specify the chain and hardfork to be used. If there is no `Common` provided the chain ID provided as a parameter on typed tx or the chain ID derived from the `v` value on signed EIP-155 conforming legacy txs will be taken (introduced in `v3.2.1`). In other cases the chain defaults to `mainnet`. | ||
The `LegacyTransaction` constructor receives a parameter of an [`@ethereumjs/common`](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/common) object that lets you specify the chain and hardfork to be used. If there is no `Common` provided the chain ID provided as a parameter on typed tx or the chain ID derived from the `v` value on signed EIP-155 conforming legacy txs will be taken (introduced in `v3.2.1`). In other cases the chain defaults to `mainnet`. | ||
Base default HF (determined by `Common`): `merge` | ||
Base default HF (determined by `Common`): `Hardfork.Shanghai` | ||
Starting with `v3.2.1` the tx library now deviates from the default HF for typed tx using the following rule: "The default HF is the default HF from `Common` if the tx type is active on that HF. Otherwise it is set to the first greater HF where the tx is active." | ||
Hardforks adding features and/or tx types: | ||
@@ -85,13 +87,4 @@ | ||
| `london` | `v3.2.0` | `EIP-1559` Transactions | | ||
| `cancun` | `v5.0.0` | `EIP-4844` Transactions | | ||
### Standalone EIPs | ||
The following "standalone" EIPs are supported by the library can be manually activated using a respectively initialized `Common` instance, e.g.: | ||
```typescript | ||
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London, eips: [3860] }) | ||
``` | ||
- [EIP-3860](https://eips.ethereum.org/EIPS/eip-3855): Limit and meter initcode (`experimental`) | ||
### Transaction Types | ||
@@ -104,3 +97,4 @@ | ||
- `AccessListEIP2930Transaction` ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930), optional access lists) | ||
- `Transaction`, the Ethereum standard tx up to `berlin`, now referred to as legacy txs with the introduction of tx types | ||
- `BlobEIP4844Transaction` ([EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), blob transactions) | ||
- `LegacyTransaction`, the Ethereum standard tx up to `berlin`, now referred to as legacy txs with the introduction of tx types | ||
@@ -110,7 +104,9 @@ #### Blob Transactions (EIP-4844) | ||
- Class: `BlobEIP4844Transaction` | ||
- Activation: `sharding` | ||
- Type: `5` | ||
- Activation: `cancun` | ||
- Type: `3` | ||
This library supports an experimental version of the blob transaction type introduced with [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) as being specified in the [01d3209](https://github.com/ethereum/EIPs/commit/01d320998d1d53d95f347b5f43feaf606f230703) EIP version from February 8, 2023 and deployed along `eip4844-devnet-4` (January 2023), see PR [#2349](https://github.com/ethereumjs/ethereumjs-monorepo/pull/2349). | ||
This library supports the blob transaction type introduced with [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844) as being specified in the [b9a5a11](https://github.com/ethereum/EIPs/commit/b9a5a117ab7e1dc18f937841d00598b527c306e7) EIP version from July 2023 deployed along [4844-devnet-7](https://github.com/ethpandaops/4844-testnet) (July 2023), see PR [#2349](https://github.com/ethereumjs/ethereumjs-monorepo/pull/2349) and following. | ||
**Note:** 4844 support is not yet completely stable and there will still be (4844-)breaking changes along all types of library releases. | ||
**Note:** This functionality needs a manual KZG library installation and global initialization, see [KZG Setup](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/tx/README.md#kzg-setup) for instructions. | ||
@@ -124,3 +120,4 @@ | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { BlobEIP4844Transaction, initKZG } from '@ethereumjs/tx' | ||
import { BlobEIP4844Transaction } from '@ethereumjs/tx' | ||
import { initKZG } from '@ethereumjs/util' | ||
import * as kzg from 'c-kzg' | ||
@@ -149,2 +146,3 @@ | ||
blobs: ['0xghi...'], // Test with empty array on a first run | ||
proofs: ['0xabcd...'], // | ||
} | ||
@@ -155,4 +153,6 @@ | ||
Note that `versionedHashes` and `kzgCommitments` have a real length of 32 bytes and `blobs` have a real length of `4096` bytes and values are trimmed here for brevity. | ||
Note that `versionedHashes` and `kzgCommitments` have a real length of 32 bytes, `blobs` have a real length of `4096` bytes and values are trimmed here for brevity. | ||
Alternatively, you can pass a `blobsData` property with an array of strings corresponding to a set of blobs and the `fromTxData` constructor will derive the corresponding `blobs`, `versionedHashes`, `kzgCommitments`, and `kzgProofs` for you. | ||
See the [Blob Transaction Tests](./test/eip4844.spec.ts) for examples of usage in instantiating, serializing, and deserializing these transactions. | ||
@@ -238,3 +238,3 @@ | ||
- Class: `Transaction` | ||
- Class: `LegacyTransaction` | ||
- Activation: `chainstart` (with modifications along the road, see HF section below) | ||
@@ -248,3 +248,3 @@ - Type: `0` (internal) | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { Transaction } from '@ethereumjs/tx' | ||
import { LegacyTransaction } from '@ethereumjs/tx' | ||
@@ -261,3 +261,3 @@ const txParams = { | ||
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Istanbul }) | ||
const tx = Transaction.fromTxData(txParams, { common }) | ||
const tx = LegacyTransaction.fromTxData(txParams, { common }) | ||
@@ -297,5 +297,5 @@ const privateKey = Buffer.from( | ||
- `public static fromTxData(txData: TxData | AccessListEIP2930TxData, txOptions: TxOptions = {}): TypedTransaction` | ||
- `public static fromSerializedData(data: Buffer, txOptions: TxOptions = {}): TypedTransaction` | ||
- `public static fromBlockBodyData(data: Buffer | Buffer[], txOptions: TxOptions = {})` | ||
- `public static async fromEthersProvider(provider: string | ethers.providers.JsonRpcProvider, txHash: string, txOptions?: TxOptions)` | ||
- `public static fromSerializedData(data: Uint8Array, txOptions: TxOptions = {}): TypedTransaction` | ||
- `public static fromBlockBodyData(data: Uint8Array | Uint8Array[], txOptions: TxOptions = {})` | ||
- `public static async fromJsonRpcProvider(provider: string | EthersProvider, txHash: string, txOptions?: TxOptions)` | ||
@@ -309,4 +309,5 @@ ### Sending a Transaction | ||
```typescript | ||
import { Transaction } from '@ethereumjs/tx' | ||
import { Common } from '@ethereumjs/common' | ||
import { LegacyTransaction } from '@ethereumjs/tx' | ||
import { hexToBytes } from '@ethereumjs/util' | ||
@@ -328,4 +329,4 @@ const from = 'PUBLIC_KEY' | ||
const tx = Transaction.fromTxData(txData, { common }) | ||
const signedTx = tx.sign(Buffer.from(PRIV_KEY, 'hex')) | ||
const tx = LegacyTransaction.fromTxData(txData, { common }) | ||
const signedTx = tx.sign(hexToBytes(PRIV_KEY)) | ||
``` | ||
@@ -353,2 +354,8 @@ | ||
## Browser | ||
With the breaking release round in Summer 2023 we have added hybrid ESM/CJS builds for all our libraries (see section below) and have eliminated many of the caveats which had previously prevented a frictionless browser usage. | ||
It is now easily possible to run a browser build of one of the EthereumJS libraries within a modern browser using the provided ESM build. For a setup example see [./examples/browser.html](./examples/browser.html). | ||
## Special Topics | ||
@@ -358,3 +365,3 @@ | ||
To sign a tx with a hardware or external wallet use `tx.getMessageToSign(false)` to return an [EIP-155](https://eips.ethereum.org/EIPS/eip-155) compliant unsigned tx. | ||
To sign a tx with a hardware or external wallet use `tx.getMessageToSign()` to return an [EIP-155](https://eips.ethereum.org/EIPS/eip-155) compliant unsigned tx. | ||
@@ -366,5 +373,5 @@ A legacy transaction will return a Buffer list of the values, and a Typed Transaction ([EIP-2718](https://eips.ethereum.org/EIPS/eip-2718)) will return the serialized output. | ||
```typescript | ||
import { Transaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' | ||
import { Chain, Common } from '@ethereumjs/common' | ||
import { bufArrToArr } from '@ethereumjs/util' | ||
import { LegacyTransaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' | ||
import { bytesToHex } from '@ethereumjs/util' | ||
import { RLP } from '@ethereumjs/rlp' | ||
@@ -374,7 +381,7 @@ import Eth from '@ledgerhq/hw-app-eth' | ||
const eth = new Eth(transport) | ||
const common = new Common({ chain: Chain.Rinkeby }) | ||
const common = new Common({ chain: Chain.Sepolia }) | ||
let txData: any = { value: 1 } | ||
let tx: Transaction | FeeMarketEIP1559Transaction | ||
let unsignedTx: Buffer[] | Buffer | ||
let unsignedTx: Uint8Array[] | Uint8Array | ||
let signedTx: typeof tx | ||
@@ -385,10 +392,10 @@ const bip32Path = "44'/60'/0'/0/0" | ||
// Signing a legacy tx | ||
tx = Transaction.fromTxData(txData, { common }) | ||
unsignedTx = tx.getMessageToSign(false) | ||
unsignedTx = Buffer.from(RLP.encode(bufArrToArr(unsignedTx))) // ledger signTransaction API expects it to be serialized | ||
tx = LegacyTransaction.fromTxData(txData, { common }) | ||
unsignedTx = tx.getMessageToSign() | ||
unsignedTx = RLP.encode(unsignedTx) // ledger signTransaction API expects it to be serialized | ||
let { v, r, s } = await eth.signTransaction(bip32Path, unsignedTx) | ||
txData = { ...txData, v, r, s } | ||
signedTx = Transaction.fromTxData(txData, { common }) | ||
let from = signedTx.getSenderAddress().toString() | ||
console.log(`signedTx: 0x${signedTx.serialize().toString('hex')}\nfrom: ${from}`) | ||
signedTx = LegacyTransaction.fromTxData(txData, { common }) | ||
let from = bytesToHex(signedTx.getSenderAddress()) | ||
console.log(`signedTx: ${bytesToHex(signedTx.serialize())}\nfrom: ${from}`) | ||
@@ -398,8 +405,8 @@ // Signing a 1559 tx | ||
tx = FeeMarketEIP1559Transaction.fromTxData(txData, { common }) | ||
unsignedTx = tx.getMessageToSign(false) | ||
unsignedTx = tx.getMessageToSign() | ||
;({ v, r, s } = await eth.signTransaction(bip32Path, unsignedTx)) // this syntax is: object destructuring - assignment without declaration | ||
txData = { ...txData, v, r, s } | ||
signedTx = FeeMarketEIP1559Transaction.fromTxData(txData, { common }) | ||
from = signedTx.getSenderAddress().toString() | ||
console.log(`signedTx: ${signedTx.serialize().toString('hex')}\nfrom: ${from}`) | ||
from = bytesToHex(signedTx.getSenderAddress()) | ||
console.log(`signedTx: ${bytesToHex(signedTx.serialize())}\nfrom: ${from}`) | ||
} | ||
@@ -423,3 +430,3 @@ | ||
const opts = { common: this._common, freeze: false } | ||
const tx = Transaction.fromTxData(txParams, opts) | ||
const tx = LegacyTransaction.fromTxData(txParams, opts) | ||
@@ -439,2 +446,26 @@ // override getSenderAddress | ||
### Hybrid CJS/ESM Builds | ||
With the breaking releases from Summer 2023 we have started to ship our libraries with both CommonJS (`cjs` folder) and ESM builds (`esm` folder), see `package.json` for the detailed setup. | ||
If you use an ES6-style `import` in your code files from the ESM build will be used: | ||
```typescript | ||
import { EthereumJSClass } from '@ethereumjs/[PACKAGE_NAME]' | ||
``` | ||
If you use Node.js specific `require` the CJS build will be used: | ||
```typescript | ||
const { EthereumJSClass } = require('@ethereumjs/[PACKAGE_NAME]') | ||
``` | ||
Using ESM will give you additional advantages over CJS beyond browser usage like static code analysis / Tree Shaking which CJS can not provide. | ||
### Buffer -> Uint8Array | ||
With the breaking releases from Summer 2023 we have removed all Node.js specific `Buffer` usages from our libraries and replace these with [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) representations, which are available both in Node.js and the browser (`Buffer` is a subclass of `Uint8Array`). | ||
We have converted existing Buffer conversion methods to Uint8Array conversion methods in the [@ethereumjs/util](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/util) `bytes` module, see the respective README section for guidance. | ||
### BigInt Support | ||
@@ -441,0 +472,0 @@ |
@@ -1,2 +0,2 @@ | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { Chain, Common } from '@ethereumjs/common' | ||
import { | ||
@@ -7,27 +7,27 @@ Address, | ||
SECP256K1_ORDER_DIV_2, | ||
bufferToBigInt, | ||
bufferToHex, | ||
bigIntToHex, | ||
bytesToBigInt, | ||
bytesToHex, | ||
ecsign, | ||
publicToAddress, | ||
toBuffer, | ||
unpadBuffer, | ||
toBytes, | ||
unpadBytes, | ||
} from '@ethereumjs/util' | ||
import { Capability } from './types' | ||
import { checkMaxInitCodeSize } from './util' | ||
import { Capability, TransactionType } from './types.js' | ||
import { checkMaxInitCodeSize } from './util.js' | ||
import type { | ||
AccessListEIP2930TxData, | ||
AccessListEIP2930ValuesArray, | ||
FeeMarketEIP1559TxData, | ||
FeeMarketEIP1559ValuesArray, | ||
JsonTx, | ||
Transaction, | ||
TransactionInterface, | ||
TxData, | ||
TxOptions, | ||
TxValuesArray, | ||
} from './types' | ||
} from './types.js' | ||
import type { Hardfork } from '@ethereumjs/common' | ||
import type { BigIntLike } from '@ethereumjs/util' | ||
interface TransactionCache { | ||
hash: Buffer | undefined | ||
hash: Uint8Array | undefined | ||
dataFee?: { | ||
@@ -46,4 +46,6 @@ value: bigint | ||
*/ | ||
export abstract class BaseTransaction<TransactionObject> { | ||
private readonly _type: number | ||
export abstract class BaseTransaction<T extends TransactionType> | ||
implements TransactionInterface<T> | ||
{ | ||
protected readonly _type: TransactionType | ||
@@ -54,3 +56,3 @@ public readonly nonce: bigint | ||
public readonly value: bigint | ||
public readonly data: Buffer | ||
public readonly data: Uint8Array | ||
@@ -87,30 +89,22 @@ public readonly v?: bigint | ||
/** | ||
* 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 | ||
constructor(txData: TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData, opts: TxOptions) { | ||
constructor(txData: TxData[T], opts: TxOptions) { | ||
const { nonce, gasLimit, to, value, data, v, r, s, type } = txData | ||
this._type = Number(bufferToBigInt(toBuffer(type))) | ||
this._type = Number(bytesToBigInt(toBytes(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) | ||
const toB = toBytes(to === '' ? '0x' : to) | ||
const vB = toBytes(v === '' ? '0x' : v) | ||
const rB = toBytes(r === '' ? '0x' : r) | ||
const sB = toBytes(s === '' ? '0x' : s) | ||
this.nonce = bufferToBigInt(toBuffer(nonce === '' ? '0x' : nonce)) | ||
this.gasLimit = bufferToBigInt(toBuffer(gasLimit === '' ? '0x' : gasLimit)) | ||
this.nonce = bytesToBigInt(toBytes(nonce === '' ? '0x' : nonce)) | ||
this.gasLimit = bytesToBigInt(toBytes(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.value = bytesToBigInt(toBytes(value === '' ? '0x' : value)) | ||
this.data = toBytes(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.v = vB.length > 0 ? bytesToBigInt(vB) : undefined | ||
this.r = rB.length > 0 ? bytesToBigInt(rB) : undefined | ||
this.s = sB.length > 0 ? bytesToBigInt(sB) : undefined | ||
@@ -155,3 +149,3 @@ this._validateCannotExceedMaxInteger({ value: this.value, r: this.r, s: this.s }) | ||
* | ||
* See `Capabilites` in the `types` module for a reference | ||
* See `Capabilities` in the `types` module for a reference | ||
* on all supported capabilities. | ||
@@ -164,11 +158,12 @@ */ | ||
/** | ||
* Checks if the transaction has the minimum amount of gas required | ||
* (DataFee + TxFee + Creation Fee). | ||
* Validates the transaction signature and minimum gas requirements. | ||
* @returns {string[]} an array of error strings | ||
*/ | ||
validate(): boolean | ||
validate(stringError: false): boolean | ||
validate(stringError: true): string[] | ||
validate(stringError: boolean = false): boolean | string[] { | ||
getValidationErrors(): string[] { | ||
const errors = [] | ||
if (this.isSigned() && !this.verifySignature()) { | ||
errors.push('Invalid Signature') | ||
} | ||
if (this.getBaseFee() > this.gasLimit) { | ||
@@ -178,7 +173,13 @@ errors.push(`gasLimit is too low. given ${this.gasLimit}, need at least ${this.getBaseFee()}`) | ||
if (this.isSigned() && !this.verifySignature()) { | ||
errors.push('Invalid Signature') | ||
} | ||
return errors | ||
} | ||
return stringError ? errors : errors.length === 0 | ||
/** | ||
* Validates the transaction signature and minimum gas requirements. | ||
* @returns {boolean} true if the transaction is valid, false otherwise | ||
*/ | ||
isValid(): boolean { | ||
const errors = this.getValidationErrors() | ||
return errors.length === 0 | ||
} | ||
@@ -252,7 +253,7 @@ | ||
toCreationAddress(): boolean { | ||
return this.to === undefined || this.to.buf.length === 0 | ||
return this.to === undefined || this.to.bytes.length === 0 | ||
} | ||
/** | ||
* Returns a Buffer Array of the raw Buffers of this transaction, in order. | ||
* Returns a Uint8Array Array of the raw Bytes of this transaction, in order. | ||
* | ||
@@ -262,7 +263,7 @@ * Use {@link BaseTransaction.serialize} to add a transaction to a block | ||
* | ||
* For an unsigned tx this method uses the empty Buffer values for the | ||
* For an unsigned tx this method uses the empty Bytes values for the | ||
* signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant | ||
* representation for external signing use {@link BaseTransaction.getMessageToSign}. | ||
*/ | ||
abstract raw(): TxValuesArray | AccessListEIP2930ValuesArray | FeeMarketEIP1559ValuesArray | ||
abstract raw(): TxValuesArray[T] | ||
@@ -272,15 +273,14 @@ /** | ||
*/ | ||
abstract serialize(): Buffer | ||
abstract serialize(): Uint8Array | ||
// 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 | ||
abstract getMessageToSign(hashMessage: false): Buffer | Buffer[] | ||
abstract getMessageToSign(hashMessage?: true): Buffer | ||
// Returns the raw unsigned tx, which is used to sign the transaction. | ||
abstract getMessageToSign(): Uint8Array | Uint8Array[] | ||
abstract hash(): Buffer | ||
// Returns the hashed unsigned tx, which is used to sign the transaction. | ||
abstract getHashedMessageToSign(): Uint8Array | ||
abstract getMessageToVerifySignature(): Buffer | ||
abstract hash(): Uint8Array | ||
abstract getMessageToVerifySignature(): Uint8Array | ||
public isSigned(): boolean { | ||
@@ -302,3 +302,3 @@ const { v, r, s } = this | ||
const publicKey = this.getSenderPublicKey() | ||
return unpadBuffer(publicKey).length !== 0 | ||
return unpadBytes(publicKey).length !== 0 | ||
} catch (e: any) { | ||
@@ -319,3 +319,3 @@ return false | ||
*/ | ||
abstract getSenderPublicKey(): Buffer | ||
abstract getSenderPublicKey(): Uint8Array | ||
@@ -331,3 +331,3 @@ /** | ||
*/ | ||
sign(privateKey: Buffer): TransactionObject { | ||
sign(privateKey: Uint8Array): Transaction[T] { | ||
if (privateKey.length !== 32) { | ||
@@ -344,3 +344,3 @@ const msg = this._errorMsg('Private key must be 32 bytes in length.') | ||
if ( | ||
this.type === 0 && | ||
this.type === TransactionType.Legacy && | ||
this.common.gteHardfork('spuriousDragon') && | ||
@@ -353,3 +353,3 @@ !this.supports(Capability.EIP155ReplayProtection) | ||
const msgHash = this.getMessageToSign(true) | ||
const msgHash = this.getHashedMessageToSign() | ||
const { v, r, s } = ecsign(msgHash, privateKey) | ||
@@ -372,6 +372,18 @@ const tx = this._processSignature(v, r, s) | ||
*/ | ||
abstract toJSON(): JsonTx | ||
toJSON(): JsonTx { | ||
return { | ||
type: bigIntToHex(BigInt(this.type)), | ||
nonce: bigIntToHex(this.nonce), | ||
gasLimit: bigIntToHex(this.gasLimit), | ||
to: this.to !== undefined ? this.to.toString() : undefined, | ||
value: bigIntToHex(this.value), | ||
data: bytesToHex(this.data), | ||
v: this.v !== undefined ? bigIntToHex(this.v) : undefined, | ||
r: this.r !== undefined ? bigIntToHex(this.r) : undefined, | ||
s: this.s !== undefined ? bigIntToHex(this.s) : undefined, | ||
} | ||
} | ||
// 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 | ||
// Accept the v,r,s values from the `sign` method, and convert this into a T | ||
protected abstract _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): Transaction[T] | ||
@@ -389,3 +401,3 @@ /** | ||
if (chainId !== undefined) { | ||
const chainIdBigInt = bufferToBigInt(toBuffer(chainId)) | ||
const chainIdBigInt = bytesToBigInt(toBytes(chainId)) | ||
if (common) { | ||
@@ -403,3 +415,3 @@ if (common.chainId() !== chainIdBigInt) { | ||
// -> Instantiate Common with chain ID | ||
return new Common({ chain: chainIdBigInt, hardfork: this.DEFAULT_HARDFORK }) | ||
return new Common({ chain: chainIdBigInt }) | ||
} else { | ||
@@ -414,3 +426,3 @@ // No Common, chain ID not supported by Common | ||
}, | ||
{ baseChain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK } | ||
{ baseChain: this.DEFAULT_CHAIN } | ||
) | ||
@@ -422,5 +434,3 @@ } | ||
// -> return Common provided or create new default Common | ||
return ( | ||
common?.copy() ?? new Common({ chain: this.DEFAULT_CHAIN, hardfork: this.DEFAULT_HARDFORK }) | ||
) | ||
return common?.copy() ?? new Common({ chain: this.DEFAULT_CHAIN }) | ||
} | ||
@@ -527,3 +537,3 @@ } | ||
try { | ||
hash = this.isSigned() ? bufferToHex(this.hash()) : 'not available (unsigned)' | ||
hash = this.isSigned() ? bytesToHex(this.hash()) : 'not available (unsigned)' | ||
} catch (e: any) { | ||
@@ -530,0 +540,0 @@ hash = 'error' |
import { RLP } from '@ethereumjs/rlp' | ||
import { | ||
MAX_INTEGER, | ||
arrToBufArr, | ||
bigIntToHex, | ||
bigIntToUnpaddedBuffer, | ||
bufArrToArr, | ||
bufferToBigInt, | ||
bigIntToUnpaddedBytes, | ||
bytesToBigInt, | ||
bytesToHex, | ||
concatBytes, | ||
ecrecover, | ||
toBuffer, | ||
equalsBytes, | ||
hexToBytes, | ||
toBytes, | ||
validateNoLeadingZeroes, | ||
} from '@ethereumjs/util' | ||
import { keccak256 } from 'ethereum-cryptography/keccak' | ||
import { keccak256 } from 'ethereum-cryptography/keccak.js' | ||
import { BaseTransaction } from './baseTransaction' | ||
import { AccessLists } from './util' | ||
import { BaseTransaction } from './baseTransaction.js' | ||
import { TransactionType } from './types.js' | ||
import { AccessLists } from './util.js' | ||
import type { | ||
AccessList, | ||
AccessListBuffer, | ||
FeeMarketEIP1559TxData, | ||
FeeMarketEIP1559ValuesArray, | ||
AccessListBytes, | ||
TxData as AllTypesTxData, | ||
TxValuesArray as AllTypesTxValuesArray, | ||
JsonTx, | ||
TxOptions, | ||
} from './types' | ||
} from './types.js' | ||
import type { Common } from '@ethereumjs/common' | ||
const TRANSACTION_TYPE = 2 | ||
const TRANSACTION_TYPE_BUFFER = Buffer.from(TRANSACTION_TYPE.toString(16).padStart(2, '0'), 'hex') | ||
type TxData = AllTypesTxData[TransactionType.FeeMarketEIP1559] | ||
type TxValuesArray = AllTypesTxValuesArray[TransactionType.FeeMarketEIP1559] | ||
const TRANSACTION_TYPE_BYTES = hexToBytes( | ||
'0x' + TransactionType.FeeMarketEIP1559.toString(16).padStart(2, '0') | ||
) | ||
/** | ||
@@ -37,5 +44,5 @@ * Typed transaction with a new gas fee market mechanism | ||
*/ | ||
export class FeeMarketEIP1559Transaction extends BaseTransaction<FeeMarketEIP1559Transaction> { | ||
export class FeeMarketEIP1559Transaction extends BaseTransaction<TransactionType.FeeMarketEIP1559> { | ||
public readonly chainId: bigint | ||
public readonly accessList: AccessListBuffer | ||
public readonly accessList: AccessListBytes | ||
public readonly AccessListJSON: AccessList | ||
@@ -48,10 +55,2 @@ public readonly maxPriorityFeePerGas: bigint | ||
/** | ||
* 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. | ||
@@ -66,3 +65,3 @@ * | ||
*/ | ||
public static fromTxData(txData: FeeMarketEIP1559TxData, opts: TxOptions = {}) { | ||
public static fromTxData(txData: TxData, opts: TxOptions = {}) { | ||
return new FeeMarketEIP1559Transaction(txData, opts) | ||
@@ -77,12 +76,12 @@ } | ||
*/ | ||
public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {}) { | ||
if (!serialized.slice(0, 1).equals(TRANSACTION_TYPE_BUFFER)) { | ||
public static fromSerializedTx(serialized: Uint8Array, opts: TxOptions = {}) { | ||
if (equalsBytes(serialized.subarray(0, 1), TRANSACTION_TYPE_BYTES) === false) { | ||
throw new Error( | ||
`Invalid serialized tx input: not an EIP-1559 transaction (wrong tx type, expected: ${TRANSACTION_TYPE}, received: ${serialized | ||
.slice(0, 1) | ||
.toString('hex')}` | ||
`Invalid serialized tx input: not an EIP-1559 transaction (wrong tx type, expected: ${ | ||
TransactionType.FeeMarketEIP1559 | ||
}, received: ${bytesToHex(serialized.subarray(0, 1))}` | ||
) | ||
} | ||
const values = arrToBufArr(RLP.decode(serialized.slice(1))) | ||
const values = RLP.decode(serialized.subarray(1)) | ||
@@ -93,3 +92,3 @@ if (!Array.isArray(values)) { | ||
return FeeMarketEIP1559Transaction.fromValuesArray(values as any, opts) | ||
return FeeMarketEIP1559Transaction.fromValuesArray(values as TxValuesArray, opts) | ||
} | ||
@@ -103,3 +102,3 @@ | ||
*/ | ||
public static fromValuesArray(values: FeeMarketEIP1559ValuesArray, opts: TxOptions = {}) { | ||
public static fromValuesArray(values: TxValuesArray, opts: TxOptions = {}) { | ||
if (values.length !== 9 && values.length !== 12) { | ||
@@ -131,3 +130,3 @@ throw new Error( | ||
{ | ||
chainId: bufferToBigInt(chainId), | ||
chainId: bytesToBigInt(chainId), | ||
nonce, | ||
@@ -141,3 +140,3 @@ maxPriorityFeePerGas, | ||
accessList: accessList ?? [], | ||
v: v !== undefined ? bufferToBigInt(v) : undefined, // EIP2930 supports v's with value 0 (empty Buffer) | ||
v: v !== undefined ? bytesToBigInt(v) : undefined, // EIP2930 supports v's with value 0 (empty Uint8Array) | ||
r, | ||
@@ -157,4 +156,4 @@ s, | ||
*/ | ||
public constructor(txData: FeeMarketEIP1559TxData, opts: TxOptions = {}) { | ||
super({ ...txData, type: TRANSACTION_TYPE }, opts) | ||
public constructor(txData: TxData, opts: TxOptions = {}) { | ||
super({ ...txData, type: TransactionType.FeeMarketEIP1559 }, opts) | ||
const { chainId, accessList, maxFeePerGas, maxPriorityFeePerGas } = txData | ||
@@ -177,5 +176,5 @@ | ||
this.maxFeePerGas = bufferToBigInt(toBuffer(maxFeePerGas === '' ? '0x' : maxFeePerGas)) | ||
this.maxPriorityFeePerGas = bufferToBigInt( | ||
toBuffer(maxPriorityFeePerGas === '' ? '0x' : maxPriorityFeePerGas) | ||
this.maxFeePerGas = bytesToBigInt(toBytes(maxFeePerGas === '' ? '0x' : maxFeePerGas)) | ||
this.maxPriorityFeePerGas = bytesToBigInt( | ||
toBytes(maxPriorityFeePerGas === '' ? '0x' : maxPriorityFeePerGas) | ||
) | ||
@@ -245,3 +244,3 @@ | ||
/** | ||
* Returns a Buffer Array of the raw Buffers of the EIP-1559 transaction, in order. | ||
* Returns a Uint8Array Array of the raw Bytes of the EIP-1559 transaction, in order. | ||
* | ||
@@ -254,20 +253,20 @@ * Format: `[chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gasLimit, to, value, data, | ||
* | ||
* For an unsigned tx this method uses the empty Buffer values for the | ||
* For an unsigned tx this method uses the empty Bytes values for the | ||
* signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant | ||
* representation for external signing use {@link FeeMarketEIP1559Transaction.getMessageToSign}. | ||
*/ | ||
raw(): FeeMarketEIP1559ValuesArray { | ||
raw(): TxValuesArray { | ||
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), | ||
bigIntToUnpaddedBytes(this.chainId), | ||
bigIntToUnpaddedBytes(this.nonce), | ||
bigIntToUnpaddedBytes(this.maxPriorityFeePerGas), | ||
bigIntToUnpaddedBytes(this.maxFeePerGas), | ||
bigIntToUnpaddedBytes(this.gasLimit), | ||
this.to !== undefined ? this.to.bytes : new Uint8Array(0), | ||
bigIntToUnpaddedBytes(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([]), | ||
this.v !== undefined ? bigIntToUnpaddedBytes(this.v) : new Uint8Array(0), | ||
this.r !== undefined ? bigIntToUnpaddedBytes(this.r) : new Uint8Array(0), | ||
this.s !== undefined ? bigIntToUnpaddedBytes(this.s) : new Uint8Array(0), | ||
] | ||
@@ -286,12 +285,9 @@ } | ||
*/ | ||
serialize(): Buffer { | ||
serialize(): Uint8Array { | ||
const base = this.raw() | ||
return Buffer.concat([ | ||
TRANSACTION_TYPE_BUFFER, | ||
Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), | ||
]) | ||
return concatBytes(TRANSACTION_TYPE_BYTES, RLP.encode(base)) | ||
} | ||
/** | ||
* Returns the serialized unsigned tx (hashed or raw), which can be used | ||
* Returns the raw serialized unsigned tx, which can be used | ||
* to sign the transaction (e.g. for sending to a hardware wallet). | ||
@@ -303,21 +299,23 @@ * | ||
* ```javascript | ||
* const serializedMessage = tx.getMessageToSign(false) // use this for the HW wallet input | ||
* const serializedMessage = tx.getMessageToSign() // use this for the HW wallet input | ||
* ``` | ||
* | ||
* @param hashMessage - Return hashed message if set to true (default: true) | ||
*/ | ||
getMessageToSign(hashMessage = true): Buffer { | ||
getMessageToSign(): Uint8Array { | ||
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)) | ||
} else { | ||
return message | ||
} | ||
const message = concatBytes(TRANSACTION_TYPE_BYTES, RLP.encode(base)) | ||
return message | ||
} | ||
/** | ||
* Returns the hashed serialized unsigned tx, 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. | ||
*/ | ||
getHashedMessageToSign(): Uint8Array { | ||
return keccak256(this.getMessageToSign()) | ||
} | ||
/** | ||
* Computes a sha3-256 hash of the serialized tx. | ||
@@ -328,3 +326,3 @@ * | ||
*/ | ||
public hash(): Buffer { | ||
public hash(): Uint8Array { | ||
if (!this.isSigned()) { | ||
@@ -337,3 +335,3 @@ const msg = this._errorMsg('Cannot call hash method if transaction is not signed') | ||
if (!this.cache.hash) { | ||
this.cache.hash = Buffer.from(keccak256(this.serialize())) | ||
this.cache.hash = keccak256(this.serialize()) | ||
} | ||
@@ -343,3 +341,3 @@ return this.cache.hash | ||
return Buffer.from(keccak256(this.serialize())) | ||
return keccak256(this.serialize()) | ||
} | ||
@@ -350,4 +348,4 @@ | ||
*/ | ||
public getMessageToVerifySignature(): Buffer { | ||
return this.getMessageToSign() | ||
public getMessageToVerifySignature(): Uint8Array { | ||
return this.getHashedMessageToSign() | ||
} | ||
@@ -358,3 +356,3 @@ | ||
*/ | ||
public getSenderPublicKey(): Buffer { | ||
public getSenderPublicKey(): Uint8Array { | ||
if (!this.isSigned()) { | ||
@@ -374,4 +372,4 @@ const msg = this._errorMsg('Cannot call this method if transaction is not signed') | ||
v! + BigInt(27), // Recover the 27 which was stripped from ecsign | ||
bigIntToUnpaddedBuffer(r!), | ||
bigIntToUnpaddedBuffer(s!) | ||
bigIntToUnpaddedBytes(r!), | ||
bigIntToUnpaddedBytes(s!) | ||
) | ||
@@ -384,3 +382,3 @@ } catch (e: any) { | ||
_processSignature(v: bigint, r: Buffer, s: Buffer) { | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) { | ||
const opts = { ...this.txOptions, common: this.common } | ||
@@ -400,4 +398,4 @@ | ||
v: v - BigInt(27), // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
r: bufferToBigInt(r), | ||
s: bufferToBigInt(s), | ||
r: bytesToBigInt(r), | ||
s: bytesToBigInt(s), | ||
}, | ||
@@ -413,16 +411,10 @@ opts | ||
const accessListJSON = AccessLists.getAccessListJSON(this.accessList) | ||
const baseJson = super.toJSON() | ||
return { | ||
...baseJson, | ||
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, | ||
} | ||
@@ -429,0 +421,0 @@ } |
import { RLP } from '@ethereumjs/rlp' | ||
import { | ||
MAX_INTEGER, | ||
arrToBufArr, | ||
bigIntToHex, | ||
bigIntToUnpaddedBuffer, | ||
bufArrToArr, | ||
bufferToBigInt, | ||
bigIntToUnpaddedBytes, | ||
bytesToBigInt, | ||
bytesToHex, | ||
concatBytes, | ||
ecrecover, | ||
toBuffer, | ||
equalsBytes, | ||
hexToBytes, | ||
toBytes, | ||
validateNoLeadingZeroes, | ||
} from '@ethereumjs/util' | ||
import { keccak256 } from 'ethereum-cryptography/keccak' | ||
import { keccak256 } from 'ethereum-cryptography/keccak.js' | ||
import { BaseTransaction } from './baseTransaction' | ||
import { AccessLists } from './util' | ||
import { BaseTransaction } from './baseTransaction.js' | ||
import { TransactionType } from './types.js' | ||
import { AccessLists } from './util.js' | ||
import type { | ||
AccessList, | ||
AccessListBuffer, | ||
AccessListEIP2930TxData, | ||
AccessListEIP2930ValuesArray, | ||
AccessListBytes, | ||
TxData as AllTypesTxData, | ||
TxValuesArray as AllTypesTxValuesArray, | ||
JsonTx, | ||
TxOptions, | ||
} from './types' | ||
} from './types.js' | ||
import type { Common } from '@ethereumjs/common' | ||
const TRANSACTION_TYPE = 1 | ||
const TRANSACTION_TYPE_BUFFER = Buffer.from(TRANSACTION_TYPE.toString(16).padStart(2, '0'), 'hex') | ||
type TxData = AllTypesTxData[TransactionType.AccessListEIP2930] | ||
type TxValuesArray = AllTypesTxValuesArray[TransactionType.AccessListEIP2930] | ||
const TRANSACTION_TYPE_BYTES = hexToBytes( | ||
'0x' + TransactionType.AccessListEIP2930.toString(16).padStart(2, '0') | ||
) | ||
/** | ||
@@ -37,5 +44,5 @@ * Typed transaction with optional access lists | ||
*/ | ||
export class AccessListEIP2930Transaction extends BaseTransaction<AccessListEIP2930Transaction> { | ||
export class AccessListEIP2930Transaction extends BaseTransaction<TransactionType.AccessListEIP2930> { | ||
public readonly chainId: bigint | ||
public readonly accessList: AccessListBuffer | ||
public readonly accessList: AccessListBytes | ||
public readonly AccessListJSON: AccessList | ||
@@ -47,10 +54,2 @@ public readonly gasPrice: bigint | ||
/** | ||
* 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. | ||
@@ -65,3 +64,3 @@ * | ||
*/ | ||
public static fromTxData(txData: AccessListEIP2930TxData, opts: TxOptions = {}) { | ||
public static fromTxData(txData: TxData, opts: TxOptions = {}) { | ||
return new AccessListEIP2930Transaction(txData, opts) | ||
@@ -76,12 +75,12 @@ } | ||
*/ | ||
public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {}) { | ||
if (!serialized.slice(0, 1).equals(TRANSACTION_TYPE_BUFFER)) { | ||
public static fromSerializedTx(serialized: Uint8Array, opts: TxOptions = {}) { | ||
if (equalsBytes(serialized.subarray(0, 1), TRANSACTION_TYPE_BYTES) === false) { | ||
throw new Error( | ||
`Invalid serialized tx input: not an EIP-2930 transaction (wrong tx type, expected: ${TRANSACTION_TYPE}, received: ${serialized | ||
.slice(0, 1) | ||
.toString('hex')}` | ||
`Invalid serialized tx input: not an EIP-2930 transaction (wrong tx type, expected: ${ | ||
TransactionType.AccessListEIP2930 | ||
}, received: ${bytesToHex(serialized.subarray(0, 1))}` | ||
) | ||
} | ||
const values = arrToBufArr(RLP.decode(Uint8Array.from(serialized.slice(1)))) | ||
const values = RLP.decode(Uint8Array.from(serialized.subarray(1))) | ||
@@ -92,3 +91,3 @@ if (!Array.isArray(values)) { | ||
return AccessListEIP2930Transaction.fromValuesArray(values as any, opts) | ||
return AccessListEIP2930Transaction.fromValuesArray(values as TxValuesArray, opts) | ||
} | ||
@@ -102,3 +101,3 @@ | ||
*/ | ||
public static fromValuesArray(values: AccessListEIP2930ValuesArray, opts: TxOptions = {}) { | ||
public static fromValuesArray(values: TxValuesArray, opts: TxOptions = {}) { | ||
if (values.length !== 8 && values.length !== 11) { | ||
@@ -119,3 +118,3 @@ throw new Error( | ||
{ | ||
chainId: bufferToBigInt(chainId), | ||
chainId: bytesToBigInt(chainId), | ||
nonce, | ||
@@ -128,3 +127,3 @@ gasPrice, | ||
accessList: accessList ?? emptyAccessList, | ||
v: v !== undefined ? bufferToBigInt(v) : undefined, // EIP2930 supports v's with value 0 (empty Buffer) | ||
v: v !== undefined ? bytesToBigInt(v) : undefined, // EIP2930 supports v's with value 0 (empty Uint8Array) | ||
r, | ||
@@ -144,4 +143,4 @@ s, | ||
*/ | ||
public constructor(txData: AccessListEIP2930TxData, opts: TxOptions = {}) { | ||
super({ ...txData, type: TRANSACTION_TYPE }, opts) | ||
public constructor(txData: TxData, opts: TxOptions = {}) { | ||
super({ ...txData, type: TransactionType.AccessListEIP2930 }, opts) | ||
const { chainId, accessList, gasPrice } = txData | ||
@@ -165,3 +164,3 @@ | ||
this.gasPrice = bufferToBigInt(toBuffer(gasPrice === '' ? '0x' : gasPrice)) | ||
this.gasPrice = bytesToBigInt(toBytes(gasPrice === '' ? '0x' : gasPrice)) | ||
@@ -217,3 +216,3 @@ this._validateCannotExceedMaxInteger({ | ||
/** | ||
* Returns a Buffer Array of the raw Buffers of the EIP-2930 transaction, in order. | ||
* Returns a Uint8Array Array of the raw Bytess of the EIP-2930 transaction, in order. | ||
* | ||
@@ -226,19 +225,19 @@ * Format: `[chainId, nonce, gasPrice, gasLimit, to, value, data, accessList, | ||
* | ||
* For an unsigned tx this method uses the empty Buffer values for the | ||
* For an unsigned tx this method uses the empty Bytes values for the | ||
* signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant | ||
* representation for external signing use {@link AccessListEIP2930Transaction.getMessageToSign}. | ||
*/ | ||
raw(): AccessListEIP2930ValuesArray { | ||
raw(): TxValuesArray { | ||
return [ | ||
bigIntToUnpaddedBuffer(this.chainId), | ||
bigIntToUnpaddedBuffer(this.nonce), | ||
bigIntToUnpaddedBuffer(this.gasPrice), | ||
bigIntToUnpaddedBuffer(this.gasLimit), | ||
this.to !== undefined ? this.to.buf : Buffer.from([]), | ||
bigIntToUnpaddedBuffer(this.value), | ||
bigIntToUnpaddedBytes(this.chainId), | ||
bigIntToUnpaddedBytes(this.nonce), | ||
bigIntToUnpaddedBytes(this.gasPrice), | ||
bigIntToUnpaddedBytes(this.gasLimit), | ||
this.to !== undefined ? this.to.bytes : new Uint8Array(0), | ||
bigIntToUnpaddedBytes(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([]), | ||
this.v !== undefined ? bigIntToUnpaddedBytes(this.v) : new Uint8Array(0), | ||
this.r !== undefined ? bigIntToUnpaddedBytes(this.r) : new Uint8Array(0), | ||
this.s !== undefined ? bigIntToUnpaddedBytes(this.s) : new Uint8Array(0), | ||
] | ||
@@ -257,12 +256,9 @@ } | ||
*/ | ||
serialize(): Buffer { | ||
serialize(): Uint8Array { | ||
const base = this.raw() | ||
return Buffer.concat([ | ||
TRANSACTION_TYPE_BUFFER, | ||
Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), | ||
]) | ||
return concatBytes(TRANSACTION_TYPE_BYTES, RLP.encode(base)) | ||
} | ||
/** | ||
* Returns the serialized unsigned tx (hashed or raw), which can be used | ||
* Returns the raw serialized unsigned tx, which can be used | ||
* to sign the transaction (e.g. for sending to a hardware wallet). | ||
@@ -274,21 +270,23 @@ * | ||
* ```javascript | ||
* const serializedMessage = tx.getMessageToSign(false) // use this for the HW wallet input | ||
* const serializedMessage = tx.getMessageToSign() // use this for the HW wallet input | ||
* ``` | ||
* | ||
* @param hashMessage - Return hashed message if set to true (default: true) | ||
*/ | ||
getMessageToSign(hashMessage = true): Buffer { | ||
getMessageToSign(): Uint8Array { | ||
const base = this.raw().slice(0, 8) | ||
const message = Buffer.concat([ | ||
TRANSACTION_TYPE_BUFFER, | ||
Buffer.from(RLP.encode(bufArrToArr(base as Buffer[]))), | ||
]) | ||
if (hashMessage) { | ||
return Buffer.from(keccak256(message)) | ||
} else { | ||
return message | ||
} | ||
const message = concatBytes(TRANSACTION_TYPE_BYTES, RLP.encode(base)) | ||
return message | ||
} | ||
/** | ||
* Returns the hashed serialized unsigned tx, 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. | ||
*/ | ||
getHashedMessageToSign(): Uint8Array { | ||
return keccak256(this.getMessageToSign()) | ||
} | ||
/** | ||
* Computes a sha3-256 hash of the serialized tx. | ||
@@ -299,3 +297,3 @@ * | ||
*/ | ||
public hash(): Buffer { | ||
public hash(): Uint8Array { | ||
if (!this.isSigned()) { | ||
@@ -308,3 +306,3 @@ const msg = this._errorMsg('Cannot call hash method if transaction is not signed') | ||
if (!this.cache.hash) { | ||
this.cache.hash = Buffer.from(keccak256(this.serialize())) | ||
this.cache.hash = keccak256(this.serialize()) | ||
} | ||
@@ -314,3 +312,3 @@ return this.cache.hash | ||
return Buffer.from(keccak256(this.serialize())) | ||
return keccak256(this.serialize()) | ||
} | ||
@@ -321,4 +319,4 @@ | ||
*/ | ||
public getMessageToVerifySignature(): Buffer { | ||
return this.getMessageToSign() | ||
public getMessageToVerifySignature(): Uint8Array { | ||
return this.getHashedMessageToSign() | ||
} | ||
@@ -329,3 +327,3 @@ | ||
*/ | ||
public getSenderPublicKey(): Buffer { | ||
public getSenderPublicKey(): Uint8Array { | ||
if (!this.isSigned()) { | ||
@@ -345,4 +343,4 @@ const msg = this._errorMsg('Cannot call this method if transaction is not signed') | ||
v! + BigInt(27), // Recover the 27 which was stripped from ecsign | ||
bigIntToUnpaddedBuffer(r!), | ||
bigIntToUnpaddedBuffer(s!) | ||
bigIntToUnpaddedBytes(r!), | ||
bigIntToUnpaddedBytes(s!) | ||
) | ||
@@ -355,3 +353,3 @@ } catch (e: any) { | ||
_processSignature(v: bigint, r: Buffer, s: Buffer) { | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) { | ||
const opts = { ...this.txOptions, common: this.common } | ||
@@ -370,4 +368,4 @@ | ||
v: v - BigInt(27), // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
r: bufferToBigInt(r), | ||
s: bufferToBigInt(s), | ||
r: bytesToBigInt(r), | ||
s: bytesToBigInt(s), | ||
}, | ||
@@ -383,15 +381,9 @@ opts | ||
const accessListJSON = AccessLists.getAccessListJSON(this.accessList) | ||
const baseJson = super.toJSON() | ||
return { | ||
...baseJson, | ||
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, | ||
} | ||
@@ -398,0 +390,0 @@ } |
@@ -1,6 +0,6 @@ | ||
import { TypeOutput, setLengthLeft, toBuffer, toType } from '@ethereumjs/util' | ||
import { TypeOutput, setLengthLeft, toBytes, toType } from '@ethereumjs/util' | ||
import type { TxData } from './types' | ||
import type { TypedTxData } from './types.js' | ||
export const normalizeTxParams = (_txParams: any): TxData => { | ||
export const normalizeTxParams = (_txParams: any): TypedTxData => { | ||
const txParams = Object.assign({}, _txParams) | ||
@@ -18,3 +18,3 @@ | ||
txParams.to !== null && txParams.to !== undefined | ||
? setLengthLeft(toBuffer(txParams.to), 20) | ||
? setLengthLeft(toBytes(txParams.to), 20) | ||
: null | ||
@@ -32,3 +32,3 @@ | ||
if (txParams.v !== '0x') { | ||
if (txParams.v !== '0x' || txParams.r !== '0x' || txParams.s !== '0x') { | ||
txParams.v = toType(txParams.v, TypeOutput.BigInt) | ||
@@ -35,0 +35,0 @@ } |
@@ -1,5 +0,6 @@ | ||
export { FeeMarketEIP1559Transaction } from './eip1559Transaction' | ||
export { AccessListEIP2930Transaction } from './eip2930Transaction' | ||
export { Transaction } from './legacyTransaction' | ||
export { TransactionFactory } from './transactionFactory' | ||
export * from './types' | ||
export { FeeMarketEIP1559Transaction } from './eip1559Transaction.js' | ||
export { AccessListEIP2930Transaction } from './eip2930Transaction.js' | ||
export { BlobEIP4844Transaction } from './eip4844Transaction.js' | ||
export { LegacyTransaction } from './legacyTransaction.js' | ||
export { TransactionFactory } from './transactionFactory.js' | ||
export * from './types.js' |
import { RLP } from '@ethereumjs/rlp' | ||
import { | ||
MAX_INTEGER, | ||
arrToBufArr, | ||
bigIntToHex, | ||
bigIntToUnpaddedBuffer, | ||
bufArrToArr, | ||
bufferToBigInt, | ||
bigIntToUnpaddedBytes, | ||
bytesToBigInt, | ||
ecrecover, | ||
toBuffer, | ||
unpadBuffer, | ||
toBytes, | ||
unpadBytes, | ||
validateNoLeadingZeroes, | ||
} from '@ethereumjs/util' | ||
import { keccak256 } from 'ethereum-cryptography/keccak' | ||
import { keccak256 } from 'ethereum-cryptography/keccak.js' | ||
import { BaseTransaction } from './baseTransaction' | ||
import { Capability } from './types' | ||
import { BaseTransaction } from './baseTransaction.js' | ||
import { Capability, TransactionType } from './types.js' | ||
import type { JsonTx, TxData, TxOptions, TxValuesArray } from './types' | ||
import type { | ||
TxData as AllTypesTxData, | ||
TxValuesArray as AllTypesTxValuesArray, | ||
JsonTx, | ||
TxOptions, | ||
} from './types.js' | ||
import type { Common } from '@ethereumjs/common' | ||
const TRANSACTION_TYPE = 0 | ||
type TxData = AllTypesTxData[TransactionType.Legacy] | ||
type TxValuesArray = AllTypesTxValuesArray[TransactionType.Legacy] | ||
@@ -33,3 +37,3 @@ function meetsEIP155(_v: bigint, chainId: bigint) { | ||
*/ | ||
export class Transaction extends BaseTransaction<Transaction> { | ||
export class LegacyTransaction extends BaseTransaction<TransactionType.Legacy> { | ||
public readonly gasPrice: bigint | ||
@@ -48,3 +52,3 @@ | ||
public static fromTxData(txData: TxData, opts: TxOptions = {}) { | ||
return new Transaction(txData, opts) | ||
return new LegacyTransaction(txData, opts) | ||
} | ||
@@ -57,4 +61,4 @@ | ||
*/ | ||
public static fromSerializedTx(serialized: Buffer, opts: TxOptions = {}) { | ||
const values = arrToBufArr(RLP.decode(Uint8Array.from(serialized))) as Buffer[] | ||
public static fromSerializedTx(serialized: Uint8Array, opts: TxOptions = {}) { | ||
const values = RLP.decode(serialized) | ||
@@ -65,3 +69,3 @@ if (!Array.isArray(values)) { | ||
return this.fromValuesArray(values, opts) | ||
return this.fromValuesArray(values as TxValuesArray, opts) | ||
} | ||
@@ -75,3 +79,3 @@ | ||
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 | ||
// If length is not 6, it has length 9. If v/r/s are empty Uint8Arrays, it is still an unsigned transaction | ||
// This happens if you get the RLP data from `raw()` | ||
@@ -88,3 +92,3 @@ if (values.length !== 6 && values.length !== 9) { | ||
return new Transaction( | ||
return new LegacyTransaction( | ||
{ | ||
@@ -113,7 +117,7 @@ nonce, | ||
public constructor(txData: TxData, opts: TxOptions = {}) { | ||
super({ ...txData, type: TRANSACTION_TYPE }, opts) | ||
super({ ...txData, type: TransactionType.Legacy }, opts) | ||
this.common = this._validateTxV(this.v, opts.common) | ||
this.gasPrice = bufferToBigInt(toBuffer(txData.gasPrice === '' ? '0x' : txData.gasPrice)) | ||
this.gasPrice = bytesToBigInt(toBytes(txData.gasPrice === '' ? '0x' : txData.gasPrice)) | ||
@@ -150,3 +154,3 @@ if (this.gasPrice * this.gasLimit > MAX_INTEGER) { | ||
/** | ||
* Returns a Buffer Array of the raw Buffers of the legacy transaction, in order. | ||
* Returns a Uint8Array Array of the raw Bytes of the legacy transaction, in order. | ||
* | ||
@@ -159,3 +163,3 @@ * Format: `[nonce, gasPrice, gasLimit, to, value, data, v, r, s]` | ||
* | ||
* For an unsigned tx this method returns the empty Buffer values | ||
* For an unsigned tx this method returns the empty Bytes values | ||
* for the signature parameters `v`, `r` and `s`. For an EIP-155 compliant | ||
@@ -166,11 +170,11 @@ * representation have a look at {@link Transaction.getMessageToSign}. | ||
return [ | ||
bigIntToUnpaddedBuffer(this.nonce), | ||
bigIntToUnpaddedBuffer(this.gasPrice), | ||
bigIntToUnpaddedBuffer(this.gasLimit), | ||
this.to !== undefined ? this.to.buf : Buffer.from([]), | ||
bigIntToUnpaddedBuffer(this.value), | ||
bigIntToUnpaddedBytes(this.nonce), | ||
bigIntToUnpaddedBytes(this.gasPrice), | ||
bigIntToUnpaddedBytes(this.gasLimit), | ||
this.to !== undefined ? this.to.bytes : new Uint8Array(0), | ||
bigIntToUnpaddedBytes(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([]), | ||
this.v !== undefined ? bigIntToUnpaddedBytes(this.v) : new Uint8Array(0), | ||
this.r !== undefined ? bigIntToUnpaddedBytes(this.r) : new Uint8Array(0), | ||
this.s !== undefined ? bigIntToUnpaddedBytes(this.s) : new Uint8Array(0), | ||
] | ||
@@ -184,31 +188,12 @@ } | ||
* | ||
* For an unsigned tx this method uses the empty Buffer values for the | ||
* For an unsigned tx this method uses the empty Uint8Array values for the | ||
* signature parameters `v`, `r` and `s` for encoding. For an EIP-155 compliant | ||
* representation for external signing use {@link Transaction.getMessageToSign}. | ||
*/ | ||
serialize(): Buffer { | ||
return Buffer.from(RLP.encode(bufArrToArr(this.raw()))) | ||
serialize(): Uint8Array { | ||
return RLP.encode(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(bigIntToUnpaddedBuffer(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 | ||
* Returns the raw unsigned tx, which can be used | ||
* to sign the transaction (e.g. for sending to a hardware wallet). | ||
@@ -220,22 +205,36 @@ * | ||
* ```javascript | ||
* import { bufArrToArr } from '@ethereumjs/util' | ||
* import { RLP } from '@ethereumjs/rlp' | ||
* const message = tx.getMessageToSign(false) | ||
* const serializedMessage = Buffer.from(RLP.encode(bufArrToArr(message))) // use this for the HW wallet input | ||
* const message = tx.getMessageToSign() | ||
* const serializedMessage = RLP.encode(message)) // use this for the HW wallet input | ||
* ``` | ||
* | ||
* @param hashMessage - Return hashed message if set to true (default: true) | ||
*/ | ||
getMessageToSign(hashMessage: false): Buffer[] | ||
getMessageToSign(hashMessage?: true): Buffer | ||
getMessageToSign(hashMessage = true) { | ||
const message = this._getMessageToSign() | ||
if (hashMessage) { | ||
return Buffer.from(keccak256(RLP.encode(bufArrToArr(message)))) | ||
} else { | ||
return message | ||
getMessageToSign(): Uint8Array[] { | ||
const message = [ | ||
bigIntToUnpaddedBytes(this.nonce), | ||
bigIntToUnpaddedBytes(this.gasPrice), | ||
bigIntToUnpaddedBytes(this.gasLimit), | ||
this.to !== undefined ? this.to.bytes : new Uint8Array(0), | ||
bigIntToUnpaddedBytes(this.value), | ||
this.data, | ||
] | ||
if (this.supports(Capability.EIP155ReplayProtection)) { | ||
message.push(bigIntToUnpaddedBytes(this.common.chainId())) | ||
message.push(unpadBytes(toBytes(0))) | ||
message.push(unpadBytes(toBytes(0))) | ||
} | ||
return message | ||
} | ||
/** | ||
* Returns the hashed serialized unsigned tx, which can be used | ||
* to sign the transaction (e.g. for sending to a hardware wallet). | ||
*/ | ||
getHashedMessageToSign() { | ||
const message = this.getMessageToSign() | ||
return keccak256(RLP.encode(message)) | ||
} | ||
/** | ||
* The amount of gas paid for the data in this tx | ||
@@ -271,3 +270,3 @@ */ | ||
*/ | ||
hash(): Buffer { | ||
hash(): Uint8Array { | ||
if (!this.isSigned()) { | ||
@@ -280,3 +279,3 @@ const msg = this._errorMsg('Cannot call hash method if transaction is not signed') | ||
if (!this.cache.hash) { | ||
this.cache.hash = Buffer.from(keccak256(RLP.encode(bufArrToArr(this.raw())))) | ||
this.cache.hash = keccak256(RLP.encode(this.raw())) | ||
} | ||
@@ -286,3 +285,3 @@ return this.cache.hash | ||
return Buffer.from(keccak256(RLP.encode(bufArrToArr(this.raw())))) | ||
return keccak256(RLP.encode(this.raw())) | ||
} | ||
@@ -298,4 +297,3 @@ | ||
} | ||
const message = this._getMessageToSign() | ||
return Buffer.from(keccak256(RLP.encode(bufArrToArr(message)))) | ||
return this.getHashedMessageToSign() | ||
} | ||
@@ -306,3 +304,3 @@ | ||
*/ | ||
getSenderPublicKey(): Buffer { | ||
getSenderPublicKey(): Uint8Array { | ||
const msgHash = this.getMessageToVerifySignature() | ||
@@ -318,4 +316,4 @@ | ||
v!, | ||
bigIntToUnpaddedBuffer(r!), | ||
bigIntToUnpaddedBuffer(s!), | ||
bigIntToUnpaddedBytes(r!), | ||
bigIntToUnpaddedBytes(s!), | ||
this.supports(Capability.EIP155ReplayProtection) ? this.common.chainId() : undefined | ||
@@ -332,3 +330,3 @@ ) | ||
*/ | ||
protected _processSignature(v: bigint, r: Buffer, s: Buffer) { | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) { | ||
if (this.supports(Capability.EIP155ReplayProtection)) { | ||
@@ -340,3 +338,3 @@ v += this.common.chainId() * BigInt(2) + BigInt(8) | ||
return Transaction.fromTxData( | ||
return LegacyTransaction.fromTxData( | ||
{ | ||
@@ -350,4 +348,4 @@ nonce: this.nonce, | ||
v, | ||
r: bufferToBigInt(r), | ||
s: bufferToBigInt(s), | ||
r: bytesToBigInt(r), | ||
s: bytesToBigInt(s), | ||
}, | ||
@@ -362,12 +360,6 @@ opts | ||
toJSON(): JsonTx { | ||
const baseJson = super.toJSON() | ||
return { | ||
nonce: bigIntToHex(this.nonce), | ||
...baseJson, | ||
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, | ||
} | ||
@@ -379,3 +371,3 @@ } | ||
*/ | ||
private _validateTxV(_v?: bigint, common?: Common): Common { | ||
protected _validateTxV(_v?: bigint, common?: Common): Common { | ||
let chainIdBigInt | ||
@@ -382,0 +374,0 @@ const v = _v !== undefined ? Number(_v) : undefined |
@@ -1,15 +0,18 @@ | ||
import { bufferToBigInt, fetchFromProvider, getProvider, toBuffer } from '@ethereumjs/util' | ||
import { fetchFromProvider, getProvider } from '@ethereumjs/util' | ||
import { FeeMarketEIP1559Transaction } from './eip1559Transaction' | ||
import { AccessListEIP2930Transaction } from './eip2930Transaction' | ||
import { normalizeTxParams } from './fromRpc' | ||
import { Transaction } from './legacyTransaction' | ||
import { FeeMarketEIP1559Transaction } from './eip1559Transaction.js' | ||
import { AccessListEIP2930Transaction } from './eip2930Transaction.js' | ||
import { BlobEIP4844Transaction } from './eip4844Transaction.js' | ||
import { normalizeTxParams } from './fromRpc.js' | ||
import { LegacyTransaction } from './legacyTransaction.js' | ||
import { | ||
TransactionType, | ||
isAccessListEIP2930TxData, | ||
isBlobEIP4844TxData, | ||
isFeeMarketEIP1559TxData, | ||
isLegacyTxData, | ||
} from './types.js' | ||
import type { | ||
AccessListEIP2930TxData, | ||
FeeMarketEIP1559TxData, | ||
TxData, | ||
TxOptions, | ||
TypedTransaction, | ||
} from './types' | ||
import type { Transaction, TxData, TxOptions, TypedTxData } from './types.js' | ||
import type { EthersProvider } from '@ethereumjs/util' | ||
@@ -26,19 +29,20 @@ export class TransactionFactory { | ||
*/ | ||
public static fromTxData( | ||
txData: TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData, | ||
public static fromTxData<T extends TransactionType>( | ||
txData: TypedTxData, | ||
txOptions: TxOptions = {} | ||
): TypedTransaction { | ||
): Transaction[T] { | ||
if (!('type' in txData) || txData.type === undefined) { | ||
// Assume legacy transaction | ||
return Transaction.fromTxData(<TxData>txData, txOptions) | ||
return LegacyTransaction.fromTxData(txData, txOptions) as Transaction[T] | ||
} else { | ||
const txType = Number(bufferToBigInt(toBuffer(txData.type))) | ||
if (txType === 0) { | ||
return Transaction.fromTxData(<TxData>txData, txOptions) | ||
} else if (txType === 1) { | ||
return AccessListEIP2930Transaction.fromTxData(<AccessListEIP2930TxData>txData, txOptions) | ||
} else if (txType === 2) { | ||
return FeeMarketEIP1559Transaction.fromTxData(<FeeMarketEIP1559TxData>txData, txOptions) | ||
if (isLegacyTxData(txData)) { | ||
return LegacyTransaction.fromTxData(txData, txOptions) as Transaction[T] | ||
} else if (isAccessListEIP2930TxData(txData)) { | ||
return AccessListEIP2930Transaction.fromTxData(txData, txOptions) as Transaction[T] | ||
} else if (isFeeMarketEIP1559TxData(txData)) { | ||
return FeeMarketEIP1559Transaction.fromTxData(txData, txOptions) as Transaction[T] | ||
} else if (isBlobEIP4844TxData(txData)) { | ||
return BlobEIP4844Transaction.fromTxData(txData, txOptions) as Transaction[T] | ||
} else { | ||
throw new Error(`Tx instantiation with type ${txType} not supported`) | ||
throw new Error(`Tx instantiation with type ${(txData as TypedTxData)?.type} not supported`) | ||
} | ||
@@ -51,13 +55,18 @@ } | ||
* | ||
* @param data - The data Buffer | ||
* @param data - The data Uint8Array | ||
* @param txOptions - The transaction options | ||
*/ | ||
public static fromSerializedData(data: Buffer, txOptions: TxOptions = {}): TypedTransaction { | ||
public static fromSerializedData<T extends TransactionType>( | ||
data: Uint8Array, | ||
txOptions: TxOptions = {} | ||
): Transaction[T] { | ||
if (data[0] <= 0x7f) { | ||
// Determine the type. | ||
switch (data[0]) { | ||
case 1: | ||
return AccessListEIP2930Transaction.fromSerializedTx(data, txOptions) | ||
case 2: | ||
return FeeMarketEIP1559Transaction.fromSerializedTx(data, txOptions) | ||
case TransactionType.AccessListEIP2930: | ||
return AccessListEIP2930Transaction.fromSerializedTx(data, txOptions) as Transaction[T] | ||
case TransactionType.FeeMarketEIP1559: | ||
return FeeMarketEIP1559Transaction.fromSerializedTx(data, txOptions) as Transaction[T] | ||
case TransactionType.BlobEIP4844: | ||
return BlobEIP4844Transaction.fromSerializedTx(data, txOptions) as Transaction[T] | ||
default: | ||
@@ -67,3 +76,3 @@ throw new Error(`TypedTransaction with ID ${data[0]} unknown`) | ||
} else { | ||
return Transaction.fromSerializedTx(data, txOptions) | ||
return LegacyTransaction.fromSerializedTx(data, txOptions) as Transaction[T] | ||
} | ||
@@ -74,15 +83,15 @@ } | ||
* 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) | ||
* A Uint8Array (a TypedTransaction - encoded as TransactionType || rlp(TransactionPayload)) | ||
* A Uint8Array[] (Legacy Transaction) | ||
* This method returns the right transaction. | ||
* | ||
* @param data - A Buffer or Buffer[] | ||
* @param data - A Uint8Array or Uint8Array[] | ||
* @param txOptions - The transaction options | ||
*/ | ||
public static fromBlockBodyData(data: Buffer | Buffer[], txOptions: TxOptions = {}) { | ||
if (Buffer.isBuffer(data)) { | ||
public static fromBlockBodyData(data: Uint8Array | Uint8Array[], txOptions: TxOptions = {}) { | ||
if (data instanceof Uint8Array) { | ||
return this.fromSerializedData(data, txOptions) | ||
} else if (Array.isArray(data)) { | ||
// It is a legacy transaction | ||
return Transaction.fromValuesArray(data, txOptions) | ||
return LegacyTransaction.fromValuesArray(data, txOptions) | ||
} else { | ||
@@ -95,3 +104,3 @@ throw new Error('Cannot decode transaction: unknown type input') | ||
* Method to retrieve a transaction from the provider | ||
* @param provider - An Ethers JsonRPCProvider | ||
* @param provider - a url string for a JSON-RPC provider or an Ethers JsonRPCProvider object | ||
* @param txHash - Transaction hash | ||
@@ -101,4 +110,4 @@ * @param txOptions - The transaction options | ||
*/ | ||
public static async fromEthersProvider( | ||
provider: string | any, | ||
public static async fromJsonRpcProvider( | ||
provider: string | EthersProvider, | ||
txHash: string, | ||
@@ -115,3 +124,3 @@ txOptions?: TxOptions | ||
} | ||
return TransactionFactory.fromRPCTx(txData, txOptions) | ||
return TransactionFactory.fromRPC(txData, txOptions) | ||
} | ||
@@ -126,8 +135,8 @@ | ||
*/ | ||
public static async fromRPCTx( | ||
txData: TxData | AccessListEIP2930TxData | FeeMarketEIP1559TxData, | ||
public static async fromRPC<T extends TransactionType>( | ||
txData: TxData[T], | ||
txOptions: TxOptions = {} | ||
) { | ||
): Promise<Transaction[T]> { | ||
return TransactionFactory.fromTxData(normalizeTxParams(txData), txOptions) | ||
} | ||
} |
264
src/types.ts
@@ -1,7 +0,16 @@ | ||
import type { FeeMarketEIP1559Transaction } from './eip1559Transaction' | ||
import type { AccessListEIP2930Transaction } from './eip2930Transaction' | ||
import type { Transaction } from './legacyTransaction' | ||
import type { Common } from '@ethereumjs/common' | ||
import type { AddressLike, BigIntLike, BufferLike, PrefixedHexString } from '@ethereumjs/util' | ||
import { bytesToBigInt, toBytes } from '@ethereumjs/util' | ||
import type { FeeMarketEIP1559Transaction } from './eip1559Transaction.js' | ||
import type { AccessListEIP2930Transaction } from './eip2930Transaction.js' | ||
import type { BlobEIP4844Transaction } from './eip4844Transaction.js' | ||
import type { LegacyTransaction } from './legacyTransaction.js' | ||
import type { AccessList, AccessListBytes, Common } from '@ethereumjs/common' | ||
import type { Address, AddressLike, BigIntLike, BytesLike } from '@ethereumjs/util' | ||
export type { | ||
AccessList, | ||
AccessListBytes, | ||
AccessListBytesItem, | ||
AccessListItem, | ||
} from '@ethereumjs/common' | ||
/** | ||
@@ -72,21 +81,3 @@ * Can be used in conjunction with {@link Transaction.supports} | ||
/* | ||
* 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 { | ||
export function isAccessListBytes(input: AccessListBytes | AccessList): input is AccessListBytes { | ||
if (input.length === 0) { | ||
@@ -102,4 +93,4 @@ return true | ||
export function isAccessList(input: AccessListBuffer | AccessList): input is AccessList { | ||
return !isAccessListBuffer(input) // This is exactly the same method, except the output is negated. | ||
export function isAccessList(input: AccessListBytes | AccessList): input is AccessList { | ||
return !isAccessListBytes(input) // This is exactly the same method, except the output is negated. | ||
} | ||
@@ -109,15 +100,92 @@ | ||
* Encompassing type for all transaction types. | ||
* | ||
* Note that this also includes legacy txs which are | ||
* referenced as {@link Transaction} for compatibility reasons. | ||
*/ | ||
export type TypedTransaction = | ||
| Transaction | ||
| AccessListEIP2930Transaction | ||
| FeeMarketEIP1559Transaction | ||
export enum TransactionType { | ||
Legacy = 0, | ||
AccessListEIP2930 = 1, | ||
FeeMarketEIP1559 = 2, | ||
BlobEIP4844 = 3, | ||
} | ||
export interface Transaction { | ||
[TransactionType.Legacy]: LegacyTransaction | ||
[TransactionType.FeeMarketEIP1559]: FeeMarketEIP1559Transaction | ||
[TransactionType.AccessListEIP2930]: AccessListEIP2930Transaction | ||
[TransactionType.BlobEIP4844]: BlobEIP4844Transaction | ||
} | ||
export type TypedTransaction = Transaction[TransactionType] | ||
export function isLegacyTx(tx: TypedTransaction): tx is LegacyTransaction { | ||
return tx.type === TransactionType.Legacy | ||
} | ||
export function isAccessListEIP2930Tx(tx: TypedTransaction): tx is AccessListEIP2930Transaction { | ||
return tx.type === TransactionType.AccessListEIP2930 | ||
} | ||
export function isFeeMarketEIP1559Tx(tx: TypedTransaction): tx is FeeMarketEIP1559Transaction { | ||
return tx.type === TransactionType.FeeMarketEIP1559 | ||
} | ||
export function isBlobEIP4844Tx(tx: TypedTransaction): tx is BlobEIP4844Transaction { | ||
return tx.type === TransactionType.BlobEIP4844 | ||
} | ||
export interface TransactionInterface<T extends TransactionType> { | ||
supports(capability: Capability): boolean | ||
type: number | ||
getBaseFee(): bigint | ||
getDataFee(): bigint | ||
getUpfrontCost(): bigint | ||
toCreationAddress(): boolean | ||
raw(): TxValuesArray[T] | ||
serialize(): Uint8Array | ||
getMessageToSign(): Uint8Array | Uint8Array[] | ||
getHashedMessageToSign(): Uint8Array | ||
hash(): Uint8Array | ||
getMessageToVerifySignature(): Uint8Array | ||
getValidationErrors(): string[] | ||
isSigned(): boolean | ||
isValid(): boolean | ||
verifySignature(): boolean | ||
getSenderAddress(): Address | ||
getSenderPublicKey(): Uint8Array | ||
sign(privateKey: Uint8Array): Transaction[T] | ||
toJSON(): JsonTx | ||
errorStr(): string | ||
} | ||
export interface TxData { | ||
[TransactionType.Legacy]: LegacyTxData | ||
[TransactionType.AccessListEIP2930]: AccessListEIP2930TxData | ||
[TransactionType.FeeMarketEIP1559]: FeeMarketEIP1559TxData | ||
[TransactionType.BlobEIP4844]: BlobEIP4844TxData | ||
} | ||
export type TypedTxData = TxData[TransactionType] | ||
export function isLegacyTxData(txData: TypedTxData): txData is LegacyTxData { | ||
const txType = Number(bytesToBigInt(toBytes(txData.type))) | ||
return txType === TransactionType.Legacy | ||
} | ||
export function isAccessListEIP2930TxData(txData: TypedTxData): txData is AccessListEIP2930TxData { | ||
const txType = Number(bytesToBigInt(toBytes(txData.type))) | ||
return txType === TransactionType.AccessListEIP2930 | ||
} | ||
export function isFeeMarketEIP1559TxData(txData: TypedTxData): txData is FeeMarketEIP1559TxData { | ||
const txType = Number(bytesToBigInt(toBytes(txData.type))) | ||
return txType === TransactionType.FeeMarketEIP1559 | ||
} | ||
export function isBlobEIP4844TxData(txData: TypedTxData): txData is BlobEIP4844TxData { | ||
const txType = Number(bytesToBigInt(toBytes(txData.type))) | ||
return txType === TransactionType.BlobEIP4844 | ||
} | ||
/** | ||
* Legacy {@link Transaction} Data | ||
*/ | ||
export type TxData = { | ||
export type LegacyTxData = { | ||
/** | ||
@@ -151,3 +219,3 @@ * The transaction's nonce. | ||
*/ | ||
data?: BufferLike | ||
data?: BytesLike | ||
@@ -179,3 +247,3 @@ /** | ||
*/ | ||
export interface AccessListEIP2930TxData extends TxData { | ||
export interface AccessListEIP2930TxData extends LegacyTxData { | ||
/** | ||
@@ -189,3 +257,3 @@ * The transaction's chain ID | ||
*/ | ||
accessList?: AccessListBuffer | AccessList | null | ||
accessList?: AccessListBytes | AccessList | null | ||
} | ||
@@ -213,41 +281,105 @@ | ||
/** | ||
* Buffer values array for a legacy {@link Transaction} | ||
* {@link BlobEIP4844Transaction} data. | ||
*/ | ||
export type TxValuesArray = Buffer[] | ||
export interface BlobEIP4844TxData extends FeeMarketEIP1559TxData { | ||
/** | ||
* The versioned hashes used to validate the blobs attached to a transaction | ||
*/ | ||
versionedHashes?: BytesLike[] | ||
/** | ||
* The maximum fee per data gas paid for the transaction | ||
*/ | ||
maxFeePerDataGas?: BigIntLike | ||
/** | ||
* The blobs associated with a transaction | ||
*/ | ||
blobs?: BytesLike[] | ||
/** | ||
* The KZG commitments corresponding to the versioned hashes for each blob | ||
*/ | ||
kzgCommitments?: BytesLike[] | ||
/** | ||
* The KZG proofs associated with the transaction | ||
*/ | ||
kzgProofs?: BytesLike[] | ||
/** | ||
* An array of arbitrary strings that blobs are to be constructed from | ||
*/ | ||
blobsData?: string[] | ||
} | ||
export interface TxValuesArray { | ||
[TransactionType.Legacy]: LegacyTxValuesArray | ||
[TransactionType.AccessListEIP2930]: AccessListEIP2930TxValuesArray | ||
[TransactionType.FeeMarketEIP1559]: FeeMarketEIP1559TxValuesArray | ||
[TransactionType.BlobEIP4844]: BlobEIP4844TxValuesArray | ||
} | ||
/** | ||
* Buffer values array for an {@link AccessListEIP2930Transaction} | ||
* Bytes values array for a legacy {@link Transaction} | ||
*/ | ||
export type AccessListEIP2930ValuesArray = [ | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
AccessListBuffer, | ||
Buffer?, | ||
Buffer?, | ||
Buffer? | ||
type LegacyTxValuesArray = Uint8Array[] | ||
/** | ||
* Bytes values array for an {@link AccessListEIP2930Transaction} | ||
*/ | ||
type AccessListEIP2930TxValuesArray = [ | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
AccessListBytes, | ||
Uint8Array?, | ||
Uint8Array?, | ||
Uint8Array? | ||
] | ||
/** | ||
* Buffer values array for a {@link FeeMarketEIP1559Transaction} | ||
* Bytes values array for a {@link FeeMarketEIP1559Transaction} | ||
*/ | ||
export type FeeMarketEIP1559ValuesArray = [ | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
Buffer, | ||
AccessListBuffer, | ||
Buffer?, | ||
Buffer?, | ||
Buffer? | ||
type FeeMarketEIP1559TxValuesArray = [ | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
AccessListBytes, | ||
Uint8Array?, | ||
Uint8Array?, | ||
Uint8Array? | ||
] | ||
/** | ||
* Bytes values array for a {@link BlobEIP4844Transaction} | ||
*/ | ||
type BlobEIP4844TxValuesArray = [ | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
Uint8Array, | ||
AccessListBytes, | ||
Uint8Array, | ||
Uint8Array[], | ||
Uint8Array?, | ||
Uint8Array?, | ||
Uint8Array? | ||
] | ||
export type BlobEIP4844NetworkValuesArray = [ | ||
BlobEIP4844TxValuesArray, | ||
Uint8Array[], | ||
Uint8Array[], | ||
Uint8Array[] | ||
] | ||
type JsonAccessListItem = { address: string; storageKeys: string[] } | ||
@@ -254,0 +386,0 @@ |
@@ -1,6 +0,6 @@ | ||
import { bufferToHex, setLengthLeft, toBuffer } from '@ethereumjs/util' | ||
import { bytesToHex, hexToBytes, setLengthLeft } from '@ethereumjs/util' | ||
import { isAccessList } from './types' | ||
import { isAccessList } from './types.js' | ||
import type { AccessList, AccessListBuffer, AccessListItem } from './types' | ||
import type { AccessList, AccessListBytes, AccessListItem } from './types.js' | ||
import type { Common } from '@ethereumjs/common' | ||
@@ -21,3 +21,3 @@ | ||
export class AccessLists { | ||
public static getAccessListData(accessList: AccessListBuffer | AccessList) { | ||
public static getAccessListData(accessList: AccessListBytes | AccessList) { | ||
let AccessListJSON | ||
@@ -27,12 +27,12 @@ let bufferAccessList | ||
AccessListJSON = accessList | ||
const newAccessList: AccessListBuffer = [] | ||
const newAccessList: AccessListBytes = [] | ||
for (let i = 0; i < accessList.length; i++) { | ||
const item: AccessListItem = accessList[i] | ||
const addressBuffer = toBuffer(item.address) | ||
const storageItems: Buffer[] = [] | ||
const addressBytes = hexToBytes(item.address) | ||
const storageItems: Uint8Array[] = [] | ||
for (let index = 0; index < item.storageKeys.length; index++) { | ||
storageItems.push(toBuffer(item.storageKeys[index])) | ||
storageItems.push(hexToBytes(item.storageKeys[index])) | ||
} | ||
newAccessList.push([addressBuffer, storageItems]) | ||
newAccessList.push([addressBytes, storageItems]) | ||
} | ||
@@ -46,6 +46,6 @@ bufferAccessList = newAccessList | ||
const data = bufferAccessList[i] | ||
const address = bufferToHex(data[0]) | ||
const address = bytesToHex(data[0]) | ||
const storageKeys: string[] = [] | ||
for (let item = 0; item < data[1].length; item++) { | ||
storageKeys.push(bufferToHex(data[1][item])) | ||
storageKeys.push(bytesToHex(data[1][item])) | ||
} | ||
@@ -67,7 +67,7 @@ const jsonItem: AccessListItem = { | ||
public static verifyAccessList(accessList: AccessListBuffer) { | ||
public static verifyAccessList(accessList: AccessListBytes) { | ||
for (let key = 0; key < accessList.length; key++) { | ||
const accessListItem = accessList[key] | ||
const address = <Buffer>accessListItem[0] | ||
const storageSlots = <Buffer[]>accessListItem[1] | ||
const address = accessListItem[0] | ||
const storageSlots = accessListItem[1] | ||
if ((<any>accessListItem)[2] !== undefined) { | ||
@@ -89,3 +89,3 @@ throw new Error( | ||
public static getAccessListJSON(accessList: AccessListBuffer) { | ||
public static getAccessListJSON(accessList: AccessListBytes) { | ||
const accessListJSON = [] | ||
@@ -95,9 +95,9 @@ for (let index = 0; index < accessList.length; index++) { | ||
const JSONItem: any = { | ||
address: '0x' + setLengthLeft(<Buffer>item[0], 20).toString('hex'), | ||
address: bytesToHex(setLengthLeft(item[0], 20)), | ||
storageKeys: [], | ||
} | ||
const storageSlots: Buffer[] = item[1] | ||
const storageSlots: Uint8Array[] = item[1] | ||
for (let slot = 0; slot < storageSlots.length; slot++) { | ||
const storageSlot = storageSlots[slot] | ||
JSONItem.storageKeys.push('0x' + setLengthLeft(storageSlot, 32).toString('hex')) | ||
JSONItem.storageKeys.push(bytesToHex(setLengthLeft(storageSlot, 32))) | ||
} | ||
@@ -109,3 +109,3 @@ accessListJSON.push(JSONItem) | ||
public static getDataFeeEIP2930(accessList: AccessListBuffer, common: Common): number { | ||
public static getDataFeeEIP2930(accessList: AccessListBytes, common: Common): number { | ||
const accessListStorageKeyCost = common.param('gasPrices', 'accessListStorageKeyCost') | ||
@@ -112,0 +112,0 @@ const accessListAddressCost = common.param('gasPrices', 'accessListAddressCost') |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
628595
4
106
9311
470
5
1
1
+ Added@ethereumjs/common@4.0.0-rc.1(transitive)
+ Added@ethereumjs/rlp@5.0.0-rc.1(transitive)
+ Added@ethereumjs/util@9.0.0-rc.1(transitive)
+ Addedbindings@1.5.0(transitive)
+ Addedc-kzg@2.1.2(transitive)
+ Addedcrc@4.3.2(transitive)
+ Addedfile-uri-to-path@1.0.0(transitive)
+ Addednode-addon-api@5.1.0(transitive)
- Removed@ethereumjs/common@3.2.0(transitive)
- Removed@ethereumjs/rlp@4.0.1(transitive)
- Removed@ethereumjs/util@8.1.0(transitive)
- Removedcrc-32@1.2.2(transitive)
- Removedmicro-ftch@0.3.1(transitive)
Updated@ethereumjs/rlp@5.0.0-rc.1
Updated@ethereumjs/util@9.0.0-rc.1
Updatedethereum-cryptography@^2.1.2