@ethereumjs/tx
Advanced tools
Comparing version 5.1.0 to 5.2.0
@@ -137,4 +137,13 @@ import { Chain, Common } from '@ethereumjs/common'; | ||
toJSON(): JsonTx; | ||
protected abstract _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): Transaction[T]; | ||
/** | ||
* Returns a new transaction with the same data fields as the current, but now signed | ||
* @param v The `v` value of the signature | ||
* @param r The `r` value of the signature | ||
* @param s The `s` value of the signature | ||
* @param convertV Set this to `true` if the raw output of `ecsign` is used. If this is `false` (default) | ||
* then the raw value passed for `v` will be used for the signature. For legacy transactions, | ||
* if this is set to `true`, it will also set the right `v` value for the chain id. | ||
*/ | ||
abstract addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): Transaction[T]; | ||
/** | ||
* Does chain ID checks on common and returns a common | ||
@@ -141,0 +150,0 @@ * to be used on instantiation |
@@ -205,4 +205,5 @@ "use strict"; | ||
const msgHash = this.getHashedMessageToSign(); | ||
const { v, r, s } = (0, util_1.ecsign)(msgHash, privateKey); | ||
const tx = this._processSignature(v, r, s); | ||
const ecSignFunction = this.common.customCrypto?.ecsign ?? util_1.ecsign; | ||
const { v, r, s } = ecSignFunction(msgHash, privateKey); | ||
const tx = this.addSignature(v, r, s, true); | ||
// Hack part 2 | ||
@@ -247,3 +248,3 @@ if (hackApplied) { | ||
if (common.chainId() !== chainIdBigInt) { | ||
const msg = this._errorMsg('The chain ID does not match the chain ID of Common'); | ||
const msg = this._errorMsg(`The chain ID does not match the chain ID of Common. Got: ${chainIdBigInt}, expected: ${common.chainId}`); | ||
throw new Error(msg); | ||
@@ -250,0 +251,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import type { EIP2718CompatibleTx } from '../types'; | ||
import type { EIP2718CompatibleTx } from '../types.js'; | ||
import type { Input } from '@ethereumjs/rlp'; | ||
@@ -3,0 +3,0 @@ export declare function getHashedMessageToSign(tx: EIP2718CompatibleTx): Uint8Array; |
@@ -10,3 +10,4 @@ "use strict"; | ||
function getHashedMessageToSign(tx) { | ||
return (0, keccak_js_1.keccak256)(tx.getMessageToSign()); | ||
const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak_js_1.keccak256; | ||
return keccakFunction(tx.getMessageToSign()); | ||
} | ||
@@ -13,0 +14,0 @@ exports.getHashedMessageToSign = getHashedMessageToSign; |
@@ -44,9 +44,10 @@ "use strict"; | ||
} | ||
const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak_js_1.keccak256; | ||
if (Object.isFrozen(tx)) { | ||
if (!tx.cache.hash) { | ||
tx.cache.hash = (0, keccak_js_1.keccak256)(tx.serialize()); | ||
tx.cache.hash = keccakFunction(tx.serialize()); | ||
} | ||
return tx.cache.hash; | ||
} | ||
return (0, keccak_js_1.keccak256)(tx.serialize()); | ||
return keccakFunction(tx.serialize()); | ||
} | ||
@@ -74,3 +75,4 @@ exports.hash = hash; | ||
try { | ||
const sender = (0, util_1.ecrecover)(msgHash, v, (0, util_1.bigIntToUnpaddedBytes)(r), (0, util_1.bigIntToUnpaddedBytes)(s), tx.supports(types_js_1.Capability.EIP155ReplayProtection) ? tx.common.chainId() : undefined); | ||
const ecrecoverFunction = tx.common.customCrypto.ecrecover ?? util_1.ecrecover; | ||
const sender = ecrecoverFunction(msgHash, v, (0, util_1.bigIntToUnpaddedBytes)(r), (0, util_1.bigIntToUnpaddedBytes)(s), tx.supports(types_js_1.Capability.EIP155ReplayProtection) ? tx.common.chainId() : undefined); | ||
if (Object.isFrozen(tx)) { | ||
@@ -77,0 +79,0 @@ tx.cache.senderPubKey = sender; |
@@ -5,3 +5,3 @@ /** EIP4844 constants */ | ||
export declare const MAX_VERSIONED_HASHES_LIST_SIZE = 16777216; | ||
export declare const LIMIT_BLOBS_PER_TX = 16777216; | ||
export declare const LIMIT_BLOBS_PER_TX = 6; | ||
export declare const MAX_TX_WRAP_KZG_COMMITMENTS = 16777216; | ||
@@ -8,0 +8,0 @@ export declare const FIELD_ELEMENTS_PER_BLOB = 4096; |
@@ -8,3 +8,3 @@ "use strict"; | ||
exports.MAX_VERSIONED_HASHES_LIST_SIZE = 16777216; // 2 ** 24 | ||
exports.LIMIT_BLOBS_PER_TX = 16777216; // 2 ** 24 | ||
exports.LIMIT_BLOBS_PER_TX = 6; // 786432 / 2^17 (`MAX_BLOB_GAS_PER_BLOCK` / `GAS_PER_BLOB`) | ||
exports.MAX_TX_WRAP_KZG_COMMITMENTS = 16777216; // 2 ** 24 | ||
@@ -11,0 +11,0 @@ exports.FIELD_ELEMENTS_PER_BLOB = 4096; // This is also in the Common 4844 parameters but needed here since types can't access Common params |
@@ -122,3 +122,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
getSenderPublicKey(): Uint8Array; | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): FeeMarketEIP1559Transaction; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): FeeMarketEIP1559Transaction; | ||
/** | ||
@@ -125,0 +125,0 @@ * Returns an object with the JSON representation of the transaction |
@@ -222,3 +222,5 @@ "use strict"; | ||
} | ||
_processSignature(v, r, s) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = (0, util_1.toBytes)(r); | ||
s = (0, util_1.toBytes)(s); | ||
const opts = { ...this.txOptions, common: this.common }; | ||
@@ -235,3 +237,3 @@ return FeeMarketEIP1559Transaction.fromTxData({ | ||
accessList: this.accessList, | ||
v: v - util_1.BIGINT_27, | ||
v: convertV ? v - util_1.BIGINT_27 : v, | ||
r: (0, util_1.bytesToBigInt)(r), | ||
@@ -238,0 +240,0 @@ s: (0, util_1.bytesToBigInt)(s), |
@@ -120,3 +120,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
getSenderPublicKey(): Uint8Array; | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): AccessListEIP2930Transaction; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): AccessListEIP2930Transaction; | ||
/** | ||
@@ -123,0 +123,0 @@ * Returns an object with the JSON representation of the transaction |
@@ -214,3 +214,5 @@ "use strict"; | ||
} | ||
_processSignature(v, r, s) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = (0, util_1.toBytes)(r); | ||
s = (0, util_1.toBytes)(s); | ||
const opts = { ...this.txOptions, common: this.common }; | ||
@@ -226,3 +228,3 @@ return AccessListEIP2930Transaction.fromTxData({ | ||
accessList: this.accessList, | ||
v: v - util_1.BIGINT_27, | ||
v: convertV ? v - util_1.BIGINT_27 : v, | ||
r: (0, util_1.bytesToBigInt)(r), | ||
@@ -229,0 +231,0 @@ s: (0, util_1.bytesToBigInt)(s), |
@@ -134,3 +134,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
toJSON(): JsonTx; | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): BlobEIP4844Transaction; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): BlobEIP4844Transaction; | ||
/** | ||
@@ -137,0 +137,0 @@ * Return a compact error string representation of the object |
@@ -14,3 +14,3 @@ "use strict"; | ||
const util_js_1 = require("./util.js"); | ||
const validateBlobTransactionNetworkWrapper = (blobVersionedHashes, blobs, commitments, kzgProofs, version) => { | ||
const validateBlobTransactionNetworkWrapper = (blobVersionedHashes, blobs, commitments, kzgProofs, version, kzg) => { | ||
if (!(blobVersionedHashes.length === blobs.length && blobs.length === commitments.length)) { | ||
@@ -24,3 +24,3 @@ throw new Error('Number of blobVersionedHashes, blobs, and commitments not all equal'); | ||
try { | ||
isValid = util_1.kzg.verifyBlobKzgProofBatch(blobs, commitments, kzgProofs); | ||
isValid = kzg.verifyBlobKzgProofBatch(blobs, commitments, kzgProofs); | ||
} | ||
@@ -105,2 +105,10 @@ catch (error) { | ||
} | ||
else if (this.blobVersionedHashes.length === 0) { | ||
const msg = this._errorMsg(`tx should contain at least one blob`); | ||
throw new Error(msg); | ||
} | ||
if (this.to === undefined) { | ||
const msg = this._errorMsg(`tx should have a "to" field and cannot be used to create contracts`); | ||
throw new Error(msg); | ||
} | ||
this.blobs = txData.blobs?.map((blob) => (0, util_1.toBytes)(blob)); | ||
@@ -143,2 +151,5 @@ this.kzgCommitments = txData.kzgCommitments?.map((commitment) => (0, util_1.toBytes)(commitment)); | ||
static minimalFromNetworkWrapper(txData, opts) { | ||
if (opts?.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
const tx = BlobEIP4844Transaction.fromTxData({ | ||
@@ -157,2 +168,5 @@ ...txData, | ||
static fromSerializedTx(serialized, opts = {}) { | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
if ((0, util_1.equalsBytes)(serialized.subarray(0, 1), (0, util_js_1.txTypeBytes)(types_js_1.TransactionType.BlobEIP4844)) === false) { | ||
@@ -174,2 +188,5 @@ throw new Error(`Invalid serialized tx input: not an EIP-4844 transaction (wrong tx type, expected: ${types_js_1.TransactionType.BlobEIP4844}, received: ${(0, util_1.bytesToHex)(serialized.subarray(0, 1))}`); | ||
static fromValuesArray(values, opts = {}) { | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
if (values.length !== 11 && values.length !== 14) { | ||
@@ -218,2 +235,5 @@ throw new Error('Invalid EIP-4844 transaction. Only expecting 11 values (for unsigned tx) or 14 values (for signed tx).'); | ||
} | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
if ((0, util_1.equalsBytes)(serialized.subarray(0, 1), (0, util_js_1.txTypeBytes)(types_js_1.TransactionType.BlobEIP4844)) === false) { | ||
@@ -234,3 +254,3 @@ throw new Error(`Invalid serialized tx input: not an EIP-4844 transaction (wrong tx type, expected: ${types_js_1.TransactionType.BlobEIP4844}, received: ${(0, util_1.bytesToHex)(serialized.subarray(0, 1))}`); | ||
const version = Number(opts.common.param('sharding', 'blobCommitmentVersionKzg')); | ||
validateBlobTransactionNetworkWrapper(decodedTx.blobVersionedHashes, blobs, kzgCommitments, kzgProofs, version); | ||
validateBlobTransactionNetworkWrapper(decodedTx.blobVersionedHashes, blobs, kzgCommitments, kzgProofs, version, opts.common.customCrypto.kzg); | ||
// set the network blob data on the tx | ||
@@ -370,3 +390,5 @@ decodedTx.blobs = blobs; | ||
} | ||
_processSignature(v, r, s) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = (0, util_1.toBytes)(r); | ||
s = (0, util_1.toBytes)(s); | ||
const opts = { ...this.txOptions, common: this.common }; | ||
@@ -383,3 +405,3 @@ return BlobEIP4844Transaction.fromTxData({ | ||
accessList: this.accessList, | ||
v: v - util_1.BIGINT_27, | ||
v: convertV ? v - util_1.BIGINT_27 : v, | ||
r: (0, util_1.bytesToBigInt)(r), | ||
@@ -386,0 +408,0 @@ s: (0, util_1.bytesToBigInt)(s), |
@@ -13,2 +13,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
readonly common: Common; | ||
private keccakFunction; | ||
/** | ||
@@ -109,7 +110,4 @@ * Instantiate a transaction from a data dictionary. | ||
getSenderPublicKey(): Uint8Array; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): LegacyTransaction; | ||
/** | ||
* Process the v, r, s values from the `sign` method of the base transaction. | ||
*/ | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): LegacyTransaction; | ||
/** | ||
* Returns an object with the JSON representation of the transaction. | ||
@@ -116,0 +114,0 @@ */ |
@@ -29,2 +29,3 @@ "use strict"; | ||
this.common = this._validateTxV(this.v, opts.common); | ||
this.keccakFunction = this.common.customCrypto.keccak256 ?? keccak_js_1.keccak256; | ||
this.gasPrice = (0, util_1.bytesToBigInt)((0, util_1.toBytes)(txData.gasPrice === '' ? '0x' : txData.gasPrice)); | ||
@@ -179,3 +180,3 @@ if (this.gasPrice * this.gasLimit > util_1.MAX_INTEGER) { | ||
const message = this.getMessageToSign(); | ||
return (0, keccak_js_1.keccak256)(rlp_1.RLP.encode(message)); | ||
return this.keccakFunction(rlp_1.RLP.encode(message)); | ||
} | ||
@@ -219,7 +220,6 @@ /** | ||
} | ||
/** | ||
* Process the v, r, s values from the `sign` method of the base transaction. | ||
*/ | ||
_processSignature(v, r, s) { | ||
if (this.supports(types_js_1.Capability.EIP155ReplayProtection)) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = (0, util_1.toBytes)(r); | ||
s = (0, util_1.toBytes)(s); | ||
if (convertV && this.supports(types_js_1.Capability.EIP155ReplayProtection)) { | ||
v += this.common.chainId() * util_1.BIGINT_2 + util_1.BIGINT_8; | ||
@@ -226,0 +226,0 @@ } |
@@ -137,4 +137,13 @@ import { Chain, Common } from '@ethereumjs/common'; | ||
toJSON(): JsonTx; | ||
protected abstract _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): Transaction[T]; | ||
/** | ||
* Returns a new transaction with the same data fields as the current, but now signed | ||
* @param v The `v` value of the signature | ||
* @param r The `r` value of the signature | ||
* @param s The `s` value of the signature | ||
* @param convertV Set this to `true` if the raw output of `ecsign` is used. If this is `false` (default) | ||
* then the raw value passed for `v` will be used for the signature. For legacy transactions, | ||
* if this is set to `true`, it will also set the right `v` value for the chain id. | ||
*/ | ||
abstract addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): Transaction[T]; | ||
/** | ||
* Does chain ID checks on common and returns a common | ||
@@ -141,0 +150,0 @@ * to be used on instantiation |
@@ -202,4 +202,5 @@ import { Chain, Common } from '@ethereumjs/common'; | ||
const msgHash = this.getHashedMessageToSign(); | ||
const { v, r, s } = ecsign(msgHash, privateKey); | ||
const tx = this._processSignature(v, r, s); | ||
const ecSignFunction = this.common.customCrypto?.ecsign ?? ecsign; | ||
const { v, r, s } = ecSignFunction(msgHash, privateKey); | ||
const tx = this.addSignature(v, r, s, true); | ||
// Hack part 2 | ||
@@ -244,3 +245,3 @@ if (hackApplied) { | ||
if (common.chainId() !== chainIdBigInt) { | ||
const msg = this._errorMsg('The chain ID does not match the chain ID of Common'); | ||
const msg = this._errorMsg(`The chain ID does not match the chain ID of Common. Got: ${chainIdBigInt}, expected: ${common.chainId}`); | ||
throw new Error(msg); | ||
@@ -247,0 +248,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import type { EIP2718CompatibleTx } from '../types'; | ||
import type { EIP2718CompatibleTx } from '../types.js'; | ||
import type { Input } from '@ethereumjs/rlp'; | ||
@@ -3,0 +3,0 @@ export declare function getHashedMessageToSign(tx: EIP2718CompatibleTx): Uint8Array; |
@@ -7,3 +7,4 @@ import { RLP } from '@ethereumjs/rlp'; | ||
export function getHashedMessageToSign(tx) { | ||
return keccak256(tx.getMessageToSign()); | ||
const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak256; | ||
return keccakFunction(tx.getMessageToSign()); | ||
} | ||
@@ -10,0 +11,0 @@ export function serialize(tx, base) { |
@@ -38,9 +38,10 @@ import { SECP256K1_ORDER_DIV_2, bigIntToUnpaddedBytes, ecrecover } from '@ethereumjs/util'; | ||
} | ||
const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak256; | ||
if (Object.isFrozen(tx)) { | ||
if (!tx.cache.hash) { | ||
tx.cache.hash = keccak256(tx.serialize()); | ||
tx.cache.hash = keccakFunction(tx.serialize()); | ||
} | ||
return tx.cache.hash; | ||
} | ||
return keccak256(tx.serialize()); | ||
return keccakFunction(tx.serialize()); | ||
} | ||
@@ -66,3 +67,4 @@ /** | ||
try { | ||
const sender = ecrecover(msgHash, v, bigIntToUnpaddedBytes(r), bigIntToUnpaddedBytes(s), tx.supports(Capability.EIP155ReplayProtection) ? tx.common.chainId() : undefined); | ||
const ecrecoverFunction = tx.common.customCrypto.ecrecover ?? ecrecover; | ||
const sender = ecrecoverFunction(msgHash, v, bigIntToUnpaddedBytes(r), bigIntToUnpaddedBytes(s), tx.supports(Capability.EIP155ReplayProtection) ? tx.common.chainId() : undefined); | ||
if (Object.isFrozen(tx)) { | ||
@@ -69,0 +71,0 @@ tx.cache.senderPubKey = sender; |
@@ -5,3 +5,3 @@ /** EIP4844 constants */ | ||
export declare const MAX_VERSIONED_HASHES_LIST_SIZE = 16777216; | ||
export declare const LIMIT_BLOBS_PER_TX = 16777216; | ||
export declare const LIMIT_BLOBS_PER_TX = 6; | ||
export declare const MAX_TX_WRAP_KZG_COMMITMENTS = 16777216; | ||
@@ -8,0 +8,0 @@ export declare const FIELD_ELEMENTS_PER_BLOB = 4096; |
@@ -5,3 +5,3 @@ /** EIP4844 constants */ | ||
export const MAX_VERSIONED_HASHES_LIST_SIZE = 16777216; // 2 ** 24 | ||
export const LIMIT_BLOBS_PER_TX = 16777216; // 2 ** 24 | ||
export const LIMIT_BLOBS_PER_TX = 6; // 786432 / 2^17 (`MAX_BLOB_GAS_PER_BLOCK` / `GAS_PER_BLOB`) | ||
export const MAX_TX_WRAP_KZG_COMMITMENTS = 16777216; // 2 ** 24 | ||
@@ -8,0 +8,0 @@ export const FIELD_ELEMENTS_PER_BLOB = 4096; // This is also in the Common 4844 parameters but needed here since types can't access Common params |
@@ -122,3 +122,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
getSenderPublicKey(): Uint8Array; | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): FeeMarketEIP1559Transaction; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): FeeMarketEIP1559Transaction; | ||
/** | ||
@@ -125,0 +125,0 @@ * Returns an object with the JSON representation of the transaction |
@@ -219,3 +219,5 @@ import { RLP } from '@ethereumjs/rlp'; | ||
} | ||
_processSignature(v, r, s) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = toBytes(r); | ||
s = toBytes(s); | ||
const opts = { ...this.txOptions, common: this.common }; | ||
@@ -232,3 +234,3 @@ return FeeMarketEIP1559Transaction.fromTxData({ | ||
accessList: this.accessList, | ||
v: v - BIGINT_27, | ||
v: convertV ? v - BIGINT_27 : v, | ||
r: bytesToBigInt(r), | ||
@@ -235,0 +237,0 @@ s: bytesToBigInt(s), |
@@ -120,3 +120,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
getSenderPublicKey(): Uint8Array; | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): AccessListEIP2930Transaction; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): AccessListEIP2930Transaction; | ||
/** | ||
@@ -123,0 +123,0 @@ * Returns an object with the JSON representation of the transaction |
@@ -211,3 +211,5 @@ import { RLP } from '@ethereumjs/rlp'; | ||
} | ||
_processSignature(v, r, s) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = toBytes(r); | ||
s = toBytes(s); | ||
const opts = { ...this.txOptions, common: this.common }; | ||
@@ -223,3 +225,3 @@ return AccessListEIP2930Transaction.fromTxData({ | ||
accessList: this.accessList, | ||
v: v - BIGINT_27, | ||
v: convertV ? v - BIGINT_27 : v, | ||
r: bytesToBigInt(r), | ||
@@ -226,0 +228,0 @@ s: bytesToBigInt(s), |
@@ -134,3 +134,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
toJSON(): JsonTx; | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): BlobEIP4844Transaction; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): BlobEIP4844Transaction; | ||
/** | ||
@@ -137,0 +137,0 @@ * Return a compact error string representation of the object |
import { RLP } from '@ethereumjs/rlp'; | ||
import { BIGINT_0, BIGINT_27, MAX_INTEGER, bigIntToHex, bigIntToUnpaddedBytes, blobsToCommitments, blobsToProofs, bytesToBigInt, bytesToHex, commitmentsToVersionedHashes, computeVersionedHash, equalsBytes, getBlobs, kzg, toBytes, validateNoLeadingZeroes, } from '@ethereumjs/util'; | ||
import { BIGINT_0, BIGINT_27, MAX_INTEGER, bigIntToHex, bigIntToUnpaddedBytes, blobsToCommitments, blobsToProofs, bytesToBigInt, bytesToHex, commitmentsToVersionedHashes, computeVersionedHash, equalsBytes, getBlobs, toBytes, validateNoLeadingZeroes, } from '@ethereumjs/util'; | ||
import { BaseTransaction } from './baseTransaction.js'; | ||
@@ -11,3 +11,3 @@ import * as EIP1559 from './capabilities/eip1559.js'; | ||
import { AccessLists, txTypeBytes } from './util.js'; | ||
const validateBlobTransactionNetworkWrapper = (blobVersionedHashes, blobs, commitments, kzgProofs, version) => { | ||
const validateBlobTransactionNetworkWrapper = (blobVersionedHashes, blobs, commitments, kzgProofs, version, kzg) => { | ||
if (!(blobVersionedHashes.length === blobs.length && blobs.length === commitments.length)) { | ||
@@ -101,2 +101,10 @@ throw new Error('Number of blobVersionedHashes, blobs, and commitments not all equal'); | ||
} | ||
else if (this.blobVersionedHashes.length === 0) { | ||
const msg = this._errorMsg(`tx should contain at least one blob`); | ||
throw new Error(msg); | ||
} | ||
if (this.to === undefined) { | ||
const msg = this._errorMsg(`tx should have a "to" field and cannot be used to create contracts`); | ||
throw new Error(msg); | ||
} | ||
this.blobs = txData.blobs?.map((blob) => toBytes(blob)); | ||
@@ -139,2 +147,5 @@ this.kzgCommitments = txData.kzgCommitments?.map((commitment) => toBytes(commitment)); | ||
static minimalFromNetworkWrapper(txData, opts) { | ||
if (opts?.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
const tx = BlobEIP4844Transaction.fromTxData({ | ||
@@ -153,2 +164,5 @@ ...txData, | ||
static fromSerializedTx(serialized, opts = {}) { | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
if (equalsBytes(serialized.subarray(0, 1), txTypeBytes(TransactionType.BlobEIP4844)) === false) { | ||
@@ -170,2 +184,5 @@ throw new Error(`Invalid serialized tx input: not an EIP-4844 transaction (wrong tx type, expected: ${TransactionType.BlobEIP4844}, received: ${bytesToHex(serialized.subarray(0, 1))}`); | ||
static fromValuesArray(values, opts = {}) { | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
if (values.length !== 11 && values.length !== 14) { | ||
@@ -214,2 +231,5 @@ throw new Error('Invalid EIP-4844 transaction. Only expecting 11 values (for unsigned tx) or 14 values (for signed tx).'); | ||
} | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx'); | ||
} | ||
if (equalsBytes(serialized.subarray(0, 1), txTypeBytes(TransactionType.BlobEIP4844)) === false) { | ||
@@ -230,3 +250,3 @@ throw new Error(`Invalid serialized tx input: not an EIP-4844 transaction (wrong tx type, expected: ${TransactionType.BlobEIP4844}, received: ${bytesToHex(serialized.subarray(0, 1))}`); | ||
const version = Number(opts.common.param('sharding', 'blobCommitmentVersionKzg')); | ||
validateBlobTransactionNetworkWrapper(decodedTx.blobVersionedHashes, blobs, kzgCommitments, kzgProofs, version); | ||
validateBlobTransactionNetworkWrapper(decodedTx.blobVersionedHashes, blobs, kzgCommitments, kzgProofs, version, opts.common.customCrypto.kzg); | ||
// set the network blob data on the tx | ||
@@ -366,3 +386,5 @@ decodedTx.blobs = blobs; | ||
} | ||
_processSignature(v, r, s) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = toBytes(r); | ||
s = toBytes(s); | ||
const opts = { ...this.txOptions, common: this.common }; | ||
@@ -379,3 +401,3 @@ return BlobEIP4844Transaction.fromTxData({ | ||
accessList: this.accessList, | ||
v: v - BIGINT_27, | ||
v: convertV ? v - BIGINT_27 : v, | ||
r: bytesToBigInt(r), | ||
@@ -382,0 +404,0 @@ s: bytesToBigInt(s), |
@@ -13,2 +13,3 @@ import { BaseTransaction } from './baseTransaction.js'; | ||
readonly common: Common; | ||
private keccakFunction; | ||
/** | ||
@@ -109,7 +110,4 @@ * Instantiate a transaction from a data dictionary. | ||
getSenderPublicKey(): Uint8Array; | ||
addSignature(v: bigint, r: Uint8Array | bigint, s: Uint8Array | bigint, convertV?: boolean): LegacyTransaction; | ||
/** | ||
* Process the v, r, s values from the `sign` method of the base transaction. | ||
*/ | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): LegacyTransaction; | ||
/** | ||
* Returns an object with the JSON representation of the transaction. | ||
@@ -116,0 +114,0 @@ */ |
@@ -26,2 +26,3 @@ import { RLP } from '@ethereumjs/rlp'; | ||
this.common = this._validateTxV(this.v, opts.common); | ||
this.keccakFunction = this.common.customCrypto.keccak256 ?? keccak256; | ||
this.gasPrice = bytesToBigInt(toBytes(txData.gasPrice === '' ? '0x' : txData.gasPrice)); | ||
@@ -176,3 +177,3 @@ if (this.gasPrice * this.gasLimit > MAX_INTEGER) { | ||
const message = this.getMessageToSign(); | ||
return keccak256(RLP.encode(message)); | ||
return this.keccakFunction(RLP.encode(message)); | ||
} | ||
@@ -216,7 +217,6 @@ /** | ||
} | ||
/** | ||
* Process the v, r, s values from the `sign` method of the base transaction. | ||
*/ | ||
_processSignature(v, r, s) { | ||
if (this.supports(Capability.EIP155ReplayProtection)) { | ||
addSignature(v, r, s, convertV = false) { | ||
r = toBytes(r); | ||
s = toBytes(s); | ||
if (convertV && this.supports(Capability.EIP155ReplayProtection)) { | ||
v += this.common.chainId() * BIGINT_2 + BIGINT_8; | ||
@@ -223,0 +223,0 @@ } |
{ | ||
"name": "@ethereumjs/tx", | ||
"version": "5.1.0", | ||
"version": "5.2.0", | ||
"description": "Implementation of the various Ethereum Transaction Types", | ||
@@ -48,3 +48,4 @@ "keywords": [ | ||
"docs:build": "typedoc --options typedoc.cjs", | ||
"examples": "ts-node ../../scripts/examples-runner.ts -- tx", | ||
"examples": "tsx ../../scripts/examples-runner.ts -- tx", | ||
"examples:build": "npx embedme README.md", | ||
"lint": "../../config/cli/lint.sh", | ||
@@ -60,6 +61,6 @@ "lint:diff": "../../config/cli/lint-diff.sh", | ||
"dependencies": { | ||
"@ethereumjs/common": "^4.1.0", | ||
"@ethereumjs/rlp": "^5.0.1", | ||
"@ethereumjs/util": "^9.0.1", | ||
"ethereum-cryptography": "^2.1.2" | ||
"@ethereumjs/common": "^4.2.0", | ||
"@ethereumjs/rlp": "^5.0.2", | ||
"@ethereumjs/util": "^9.0.2", | ||
"ethereum-cryptography": "^2.1.3" | ||
}, | ||
@@ -66,0 +67,0 @@ "peerDependencies": { |
165
README.md
@@ -28,3 +28,3 @@ # @ethereumjs/tx | ||
For blob transactions and other KZG related proof functionality (e.g. for EVM precompiles) KZG has to be manually installed and initialized once in a global scope. The functionality is then available for all KZG usages throughout different libraries (Transaction, Block, EVM). | ||
For blob transactions and other KZG related proof functionality (e.g. for EVM precompiles) KZG has to be manually installed and initialized in the `common` instance to be used in instantiating blob transactions. | ||
@@ -38,16 +38,28 @@ #### Manual Installation | ||
#### Global Initialization | ||
#### KZG Initialization | ||
Global initialization can then be done like this (using the `c-kzg` module for our KZG dependency): | ||
Initialization can then be done like this (using the `c-kzg` module for our KZG dependency): | ||
```typescript | ||
import { initKZG } from '@ethereumjs/util' | ||
```ts | ||
// ./examples/initKzg.ts | ||
// Make the kzg library available globally | ||
import * as kzg from 'c-kzg' | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { initKZG } from '@ethereumjs/util' | ||
// Initialize the trusted setup | ||
initKZG(kzg, 'path/to/my/trusted_setup.txt') | ||
// Instantiate KZG | ||
initKZG(kzg, __dirname + '/../../client/src/trustedSetups/official.txt') | ||
// Instantiate `common` | ||
const common = new Common({ | ||
chain: Chain.Mainnet, | ||
hardfork: Hardfork.Cancun, | ||
customCrypto: { kzg }, | ||
}) | ||
console.log(common.customCrypto.kzg) // should output the KZG API as an object | ||
``` | ||
At the moment using the Node.js bindings for the `c-kzg` library is the only option to get KZG related functionality to work, note that this solution is not browser compatible. We are currently working on a WASM build of that respective library which can hopefully be released soon [TM]. | ||
## Usage | ||
@@ -84,2 +96,6 @@ | ||
### WASM Crypto Support | ||
This library by default uses JavaScript implementations for the basic standard crypto primitives like hashing or signature verification. See `@ethereumjs/common` [README](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/common) for instructions on how to replace with e.g. a more performant WASM implementation by using a shared `common` instance. | ||
### Transaction Types | ||
@@ -101,6 +117,4 @@ | ||
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. | ||
This library supports the blob transaction type introduced with [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844). | ||
**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. | ||
@@ -112,11 +126,19 @@ | ||
```typescript | ||
```ts | ||
// ./examples/blobTx.ts | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { BlobEIP4844Transaction } from '@ethereumjs/tx' | ||
import { initKZG } from '@ethereumjs/util' | ||
import { bytesToHex, initKZG } from '@ethereumjs/util' | ||
import * as kzg from 'c-kzg' | ||
initKZG(kzg, 'path/to/my/trusted_setup.txt') | ||
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Shanghai, eips: [4844] }) | ||
initKZG(kzg, __dirname + '/../../client/src/trustedSetups/devnet6.txt') | ||
const common = new Common({ | ||
chain: Chain.Mainnet, | ||
hardfork: Hardfork.Shanghai, | ||
eips: [4844], | ||
customCrypto: { kzg }, | ||
}) | ||
const txData = { | ||
@@ -137,9 +159,8 @@ data: '0x1a8451e600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', | ||
type: '0x05', | ||
versionedHashes: ['0xabc...'], // Test with empty array on a first run | ||
kzgCommitments: ['0xdef...'], // Test with empty array on a first run | ||
blobs: ['0xghi...'], // Test with empty array on a first run | ||
proofs: ['0xabcd...'], // | ||
blobsData: ['abcd'], | ||
} | ||
const tx = BlobEIP4844Transaction.fromTxData(txData, { common }) | ||
console.log(bytesToHex(tx.hash())) //0x3c3e7c5e09c250d2200bcc3530f4a9088d7e3fb4ea3f4fccfd09f535a3539e84 | ||
``` | ||
@@ -161,5 +182,8 @@ | ||
```typescript | ||
```ts | ||
// ./examples/londonTx.ts | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { FeeMarketEIP1559Transaction } from '@ethereumjs/tx' | ||
import { bytesToHex } from '@ethereumjs/util' | ||
@@ -185,2 +209,3 @@ const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) | ||
const tx = FeeMarketEIP1559Transaction.fromTxData(txData, { common }) | ||
console.log(bytesToHex(tx.hash())) // 0x6f9ef69ccb1de1aea64e511efd6542541008ced321887937c95b03779358ec8a | ||
``` | ||
@@ -196,5 +221,8 @@ | ||
```typescript | ||
```ts | ||
// ./examples/accessListTx.ts | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { AccessListEIP2930Transaction } from '@ethereumjs/tx' | ||
import { bytesToHex } from '@ethereumjs/util' | ||
@@ -227,2 +255,3 @@ const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Berlin }) | ||
const tx = AccessListEIP2930Transaction.fromTxData(txData, { common }) | ||
console.log(bytesToHex(tx.hash())) // 0x9150cdebad74e88b038e6c6b964d99af705f9c0883d7f0bbc0f3e072358f5b1d | ||
``` | ||
@@ -242,5 +271,8 @@ | ||
```typescript | ||
```ts | ||
// ./examples/legacyTx.ts | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { LegacyTransaction } from '@ethereumjs/tx' | ||
import { bytesToHex } from '@ethereumjs/util' | ||
@@ -267,2 +299,3 @@ const txParams = { | ||
const serializedTx = signedTx.serialize() | ||
console.log(bytesToHex(signedTx.hash())) // 0x894b72d87f8333fccd29d1b3aca39af69d97a6bc281e7e7a3a60640690a3cd2b | ||
``` | ||
@@ -274,13 +307,17 @@ | ||
```typescript | ||
```ts | ||
// ./examples/txFactory.ts | ||
import { Chain, Common, Hardfork } from '@ethereumjs/common' | ||
import { TransactionFactory } from '@ethereumjs/tx' | ||
import { Capability, EIP1559CompatibleTx, TransactionFactory } from '@ethereumjs/tx' | ||
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.Berlin }) | ||
const common = new Common({ chain: Chain.Mainnet, hardfork: Hardfork.London }) | ||
const txData = {} // Use data from the different tx type examples | ||
const txData = { type: 2, maxFeePerGas: BigInt(20) } // Creates an EIP-1559 compatible transac | ||
const tx = TransactionFactory.fromTxData(txData, { common }) | ||
if (tx.supports(Capability.EIP2930AccessLists)) { | ||
// Do something which only makes sense for txs with support for access lists | ||
if (tx.supports(Capability.EIP1559FeeMarket)) { | ||
console.log( | ||
`The max fee per gas for this transaction is ${(tx as EIP1559CompatibleTx).maxFeePerGas}` | ||
) | ||
} | ||
@@ -304,15 +341,14 @@ ``` | ||
```typescript | ||
import { Common } from '@ethereumjs/common' | ||
```ts | ||
// ./examples/l2tx.ts | ||
import { Common, CustomChain } from '@ethereumjs/common' | ||
import { LegacyTransaction } from '@ethereumjs/tx' | ||
import { hexToBytes } from '@ethereumjs/util' | ||
import { Address, bytesToHex, hexToBytes } from '@ethereumjs/util' | ||
const from = 'PUBLIC_KEY' | ||
const PRIV_KEY = process.argv[2] | ||
const to = 'DESTINATION_ETHEREUM_ADDRESS' | ||
const pk = hexToBytes('0x076247989df60a82f6e86e58104368676096f84e60972282ee00d4673a2bc9b9') | ||
const to = Address.fromString('0x256e8f0ba532ad83a0debde7501669511a41a1f3') | ||
const common = Common.custom(CustomChain.xDaiChain) | ||
const txData = { | ||
from, | ||
nonce: 0, | ||
@@ -326,3 +362,4 @@ gasPrice: 1000000000, | ||
const tx = LegacyTransaction.fromTxData(txData, { common }) | ||
const signedTx = tx.sign(hexToBytes(PRIV_KEY)) | ||
const signedTx = tx.sign(pk) | ||
console.log(bytesToHex(signedTx.hash())) // 0xbf98f6f8700812ed6f2314275070256e11945fa48afd80fb301265f6a41a2dc2 | ||
``` | ||
@@ -346,3 +383,3 @@ | ||
```typescript | ||
```ts | ||
const common = Common.custom({ chainId: 1234 }) | ||
@@ -367,3 +404,3 @@ ``` | ||
```typescript | ||
```ts | ||
import { Chain, Common } from '@ethereumjs/common' | ||
@@ -379,3 +416,3 @@ import { LegacyTransaction, FeeMarketEIP1559Transaction } from '@ethereumjs/tx' | ||
let txData: any = { value: 1 } | ||
let tx: Transaction | FeeMarketEIP1559Transaction | ||
let tx: LegacyTransaction | FeeMarketEIP1559Transaction | ||
let unsignedTx: Uint8Array[] | Uint8Array | ||
@@ -388,9 +425,8 @@ let signedTx: typeof tx | ||
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 = LegacyTransaction.fromTxData(txData, { common }) | ||
let from = bytesToHex(signedTx.getSenderAddress()) | ||
console.log(`signedTx: ${bytesToHex(signedTx.serialize())}\nfrom: ${from}`) | ||
tx = tx.getMessageToSign() | ||
// ledger signTransaction API expects it to be serialized | ||
let { v, r, s } = await eth.signTransaction(bip32Path, RLP.encode(tx)) | ||
tx.addSignature(v, r, s, true) | ||
let from = tx.getSenderAddress().toString() | ||
console.log(`signedTx: ${bytesToHex(tx.serialize())}\nfrom: ${from}`) | ||
@@ -400,8 +436,7 @@ // Signing a 1559 tx | ||
tx = FeeMarketEIP1559Transaction.fromTxData(txData, { common }) | ||
unsignedTx = tx.getMessageToSign() | ||
tx = 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 = bytesToHex(signedTx.getSenderAddress()) | ||
console.log(`signedTx: ${bytesToHex(signedTx.serialize())}\nfrom: ${from}`) | ||
tx.addSignature(v, r, s) | ||
from = tx.getSenderAddress().toString() | ||
console.log(`signedTx: ${bytesToHex(tx.serialize())}\nfrom: ${from}`) | ||
} | ||
@@ -412,24 +447,2 @@ | ||
### Fake Transaction | ||
Creating a fake transaction for use in e.g. `VM.runTx()` is simple, just overwrite `getSenderAddress()` with a custom [`Address`](https://github.com/ethereumjs/ethereumjs-monorepo/blob/master/packages/util/docs/classes/Address.md) like so: | ||
```typescript | ||
import { Address } from '@ethereumjs/util' | ||
import { Transaction } from '@ethereumjs/tx' | ||
_getFakeTransaction(txParams: TxParams): Transaction { | ||
const from = Address.fromString(txParams.from) | ||
delete txParams.from | ||
const opts = { common: this._common, freeze: false } | ||
const tx = LegacyTransaction.fromTxData(txParams, opts) | ||
// override getSenderAddress | ||
tx.getSenderAddress = () => { return from } | ||
return tx | ||
} | ||
``` | ||
## API | ||
@@ -447,3 +460,3 @@ | ||
```typescript | ||
```ts | ||
import { EthereumJSClass } from '@ethereumjs/[PACKAGE_NAME]' | ||
@@ -454,3 +467,3 @@ ``` | ||
```typescript | ||
```ts | ||
const { EthereumJSClass } = require('@ethereumjs/[PACKAGE_NAME]') | ||
@@ -457,0 +470,0 @@ ``` |
@@ -311,4 +311,5 @@ import { Chain, Common } from '@ethereumjs/common' | ||
const msgHash = this.getHashedMessageToSign() | ||
const { v, r, s } = ecsign(msgHash, privateKey) | ||
const tx = this._processSignature(v, r, s) | ||
const ecSignFunction = this.common.customCrypto?.ecsign ?? ecsign | ||
const { v, r, s } = ecSignFunction(msgHash, privateKey) | ||
const tx = this.addSignature(v, r, s, true) | ||
@@ -343,4 +344,17 @@ // Hack part 2 | ||
// 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] | ||
/** | ||
* Returns a new transaction with the same data fields as the current, but now signed | ||
* @param v The `v` value of the signature | ||
* @param r The `r` value of the signature | ||
* @param s The `s` value of the signature | ||
* @param convertV Set this to `true` if the raw output of `ecsign` is used. If this is `false` (default) | ||
* then the raw value passed for `v` will be used for the signature. For legacy transactions, | ||
* if this is set to `true`, it will also set the right `v` value for the chain id. | ||
*/ | ||
abstract addSignature( | ||
v: bigint, | ||
r: Uint8Array | bigint, | ||
s: Uint8Array | bigint, | ||
convertV?: boolean | ||
): Transaction[T] | ||
@@ -361,3 +375,5 @@ /** | ||
if (common.chainId() !== chainIdBigInt) { | ||
const msg = this._errorMsg('The chain ID does not match the chain ID of Common') | ||
const msg = this._errorMsg( | ||
`The chain ID does not match the chain ID of Common. Got: ${chainIdBigInt}, expected: ${common.chainId}` | ||
) | ||
throw new Error(msg) | ||
@@ -364,0 +380,0 @@ } |
@@ -9,7 +9,8 @@ import { RLP } from '@ethereumjs/rlp' | ||
import type { EIP2718CompatibleTx } from '../types' | ||
import type { EIP2718CompatibleTx } from '../types.js' | ||
import type { Input } from '@ethereumjs/rlp' | ||
export function getHashedMessageToSign(tx: EIP2718CompatibleTx): Uint8Array { | ||
return keccak256(tx.getMessageToSign()) | ||
const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak256 | ||
return keccakFunction(tx.getMessageToSign()) | ||
} | ||
@@ -16,0 +17,0 @@ |
@@ -48,5 +48,7 @@ import { SECP256K1_ORDER_DIV_2, bigIntToUnpaddedBytes, ecrecover } from '@ethereumjs/util' | ||
const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak256 | ||
if (Object.isFrozen(tx)) { | ||
if (!tx.cache.hash) { | ||
tx.cache.hash = keccak256(tx.serialize()) | ||
tx.cache.hash = keccakFunction(tx.serialize()) | ||
} | ||
@@ -56,3 +58,3 @@ return tx.cache.hash | ||
return keccak256(tx.serialize()) | ||
return keccakFunction(tx.serialize()) | ||
} | ||
@@ -87,3 +89,4 @@ | ||
try { | ||
const sender = ecrecover( | ||
const ecrecoverFunction = tx.common.customCrypto.ecrecover ?? ecrecover | ||
const sender = ecrecoverFunction( | ||
msgHash, | ||
@@ -90,0 +93,0 @@ v!, |
@@ -6,5 +6,5 @@ /** EIP4844 constants */ | ||
export const MAX_VERSIONED_HASHES_LIST_SIZE = 16777216 // 2 ** 24 | ||
export const LIMIT_BLOBS_PER_TX = 16777216 // 2 ** 24 | ||
export const LIMIT_BLOBS_PER_TX = 6 // 786432 / 2^17 (`MAX_BLOB_GAS_PER_BLOCK` / `GAS_PER_BLOB`) | ||
export const MAX_TX_WRAP_KZG_COMMITMENTS = 16777216 // 2 ** 24 | ||
export const FIELD_ELEMENTS_PER_BLOB = 4096 // This is also in the Common 4844 parameters but needed here since types can't access Common params | ||
export const BYTES_PER_FIELD_ELEMENT = 32 |
@@ -311,3 +311,10 @@ import { RLP } from '@ethereumjs/rlp' | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) { | ||
addSignature( | ||
v: bigint, | ||
r: Uint8Array | bigint, | ||
s: Uint8Array | bigint, | ||
convertV: boolean = false | ||
): FeeMarketEIP1559Transaction { | ||
r = toBytes(r) | ||
s = toBytes(s) | ||
const opts = { ...this.txOptions, common: this.common } | ||
@@ -326,3 +333,3 @@ | ||
accessList: this.accessList, | ||
v: v - BIGINT_27, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
r: bytesToBigInt(r), | ||
@@ -329,0 +336,0 @@ s: bytesToBigInt(s), |
@@ -283,3 +283,10 @@ import { RLP } from '@ethereumjs/rlp' | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) { | ||
addSignature( | ||
v: bigint, | ||
r: Uint8Array | bigint, | ||
s: Uint8Array | bigint, | ||
convertV: boolean = false | ||
): AccessListEIP2930Transaction { | ||
r = toBytes(r) | ||
s = toBytes(s) | ||
const opts = { ...this.txOptions, common: this.common } | ||
@@ -297,3 +304,3 @@ | ||
accessList: this.accessList, | ||
v: v - BIGINT_27, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
r: bytesToBigInt(r), | ||
@@ -300,0 +307,0 @@ s: bytesToBigInt(s), |
@@ -16,3 +16,2 @@ import { RLP } from '@ethereumjs/rlp' | ||
getBlobs, | ||
kzg, | ||
toBytes, | ||
@@ -41,2 +40,3 @@ validateNoLeadingZeroes, | ||
import type { Common } from '@ethereumjs/common' | ||
import type { Kzg } from '@ethereumjs/util' | ||
@@ -51,3 +51,4 @@ type TxData = AllTypesTxData[TransactionType.BlobEIP4844] | ||
kzgProofs: Uint8Array[], | ||
version: number | ||
version: number, | ||
kzg: Kzg | ||
) => { | ||
@@ -174,3 +175,12 @@ if (!(blobVersionedHashes.length === blobs.length && blobs.length === commitments.length)) { | ||
throw new Error(msg) | ||
} else if (this.blobVersionedHashes.length === 0) { | ||
const msg = this._errorMsg(`tx should contain at least one blob`) | ||
throw new Error(msg) | ||
} | ||
if (this.to === undefined) { | ||
const msg = this._errorMsg( | ||
`tx should have a "to" field and cannot be used to create contracts` | ||
) | ||
throw new Error(msg) | ||
} | ||
@@ -225,2 +235,6 @@ this.blobs = txData.blobs?.map((blob) => toBytes(blob)) | ||
): BlobEIP4844Transaction { | ||
if (opts?.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx') | ||
} | ||
const tx = BlobEIP4844Transaction.fromTxData( | ||
@@ -243,2 +257,6 @@ { | ||
public static fromSerializedTx(serialized: Uint8Array, opts: TxOptions = {}) { | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx') | ||
} | ||
if ( | ||
@@ -270,2 +288,6 @@ equalsBytes(serialized.subarray(0, 1), txTypeBytes(TransactionType.BlobEIP4844)) === false | ||
public static fromValuesArray(values: TxValuesArray, opts: TxOptions = {}) { | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx') | ||
} | ||
if (values.length !== 11 && values.length !== 14) { | ||
@@ -343,2 +365,6 @@ throw new Error( | ||
if (opts.common?.customCrypto?.kzg === undefined) { | ||
throw new Error('kzg instance required to instantiate blob tx') | ||
} | ||
if ( | ||
@@ -374,3 +400,4 @@ equalsBytes(serialized.subarray(0, 1), txTypeBytes(TransactionType.BlobEIP4844)) === false | ||
kzgProofs, | ||
version | ||
version, | ||
opts.common.customCrypto.kzg | ||
) | ||
@@ -532,3 +559,10 @@ | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array): BlobEIP4844Transaction { | ||
addSignature( | ||
v: bigint, | ||
r: Uint8Array | bigint, | ||
s: Uint8Array | bigint, | ||
convertV: boolean = false | ||
): BlobEIP4844Transaction { | ||
r = toBytes(r) | ||
s = toBytes(s) | ||
const opts = { ...this.txOptions, common: this.common } | ||
@@ -547,3 +581,3 @@ | ||
accessList: this.accessList, | ||
v: v - BIGINT_27, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
v: convertV ? v - BIGINT_27 : v, // This looks extremely hacky: @ethereumjs/util actually adds 27 to the value, the recovery bit is either 0 or 1. | ||
r: bytesToBigInt(r), | ||
@@ -550,0 +584,0 @@ s: bytesToBigInt(s), |
@@ -43,2 +43,3 @@ import { RLP } from '@ethereumjs/rlp' | ||
public readonly common: Common | ||
private keccakFunction: (msg: Uint8Array) => Uint8Array | ||
@@ -117,3 +118,3 @@ /** | ||
this.common = this._validateTxV(this.v, opts.common) | ||
this.keccakFunction = this.common.customCrypto.keccak256 ?? keccak256 | ||
this.gasPrice = bytesToBigInt(toBytes(txData.gasPrice === '' ? '0x' : txData.gasPrice)) | ||
@@ -229,3 +230,3 @@ | ||
const message = this.getMessageToSign() | ||
return keccak256(RLP.encode(message)) | ||
return this.keccakFunction(RLP.encode(message)) | ||
} | ||
@@ -275,7 +276,11 @@ | ||
/** | ||
* Process the v, r, s values from the `sign` method of the base transaction. | ||
*/ | ||
protected _processSignature(v: bigint, r: Uint8Array, s: Uint8Array) { | ||
if (this.supports(Capability.EIP155ReplayProtection)) { | ||
addSignature( | ||
v: bigint, | ||
r: Uint8Array | bigint, | ||
s: Uint8Array | bigint, | ||
convertV: boolean = false | ||
): LegacyTransaction { | ||
r = toBytes(r) | ||
s = toBytes(s) | ||
if (convertV && this.supports(Capability.EIP155ReplayProtection)) { | ||
v += this.common.chainId() * BIGINT_2 + BIGINT_8 | ||
@@ -282,0 +287,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
656722
9530
481
Updated@ethereumjs/common@^4.2.0
Updated@ethereumjs/rlp@^5.0.2
Updated@ethereumjs/util@^9.0.2
Updatedethereum-cryptography@^2.1.3