@tevm/tx
Version:
A custom implementation of ethereumjs tx
79 lines (76 loc) • 2.31 kB
JavaScript
import { FeeMarket1559Tx } from '@ethereumjs/tx'
import { InternalError, InvalidGasLimitError } from '@tevm/errors'
import { EthjsAddress, keccak256 } from '@tevm/utils'
/**
* @typedef {InternalError | InvalidGasLimitError} CreateImpersonatedTxError
*/
/**
* Creates an impersonated tx that wraps {@link FeeMarket1559Tx}.
* Wraps following methods
* - 'isImpersonated'
* - 'hash'
* - 'isSigned'
* - 'getSenderAddress'
* @throws {CreateImpersonatedTxError} Error if the constructor for {@link FeeMarket1559Tx} throws
* @param {import("@ethereumjs/tx").FeeMarketEIP1559TxData & {impersonatedAddress: EthjsAddress}} txData
* @param {import("@ethereumjs/tx").TxOptions} [opts]
* @returns {import('./ImpersonatedTx.js').ImpersonatedTx}
*/
export const createImpersonatedTx = (txData, opts) => {
/**
* @type {FeeMarket1559Tx}
*/
let tx
try {
tx = new FeeMarket1559Tx(txData, opts)
} catch (e) {
if (!(e instanceof Error)) {
throw new InternalError('Unknown Error', { cause: /** @type any*/ (e) })
}
if (e.message.includes('EIP-1559 not enabled on Common')) {
throw new InternalError(
'EIP-1559 is not enabled on Common. Tevm currently only supports 1559 and it should be enabled by default',
{ cause: e },
)
}
if (
e.message.includes('gasLimit cannot exceed MAX_UINT64 (2^64-1)') ||
e.message.includes('gasLimit * maxFeePerGas cannot exceed MAX_INTEGER (2^256-1)')
) {
throw new InvalidGasLimitError(e.message, { cause: e })
}
if (
e.message.includes(
'maxFeePerGas cannot be less than maxPriorityFeePerGas (The total must be the larger of the two)',
)
) {
throw new InvalidGasLimitError(e.message, { cause: e })
}
throw new InternalError(e.message, { cause: e })
}
return /** @type {import('./ImpersonatedTx.js').ImpersonatedTx}*/ (
new Proxy(tx, {
get(target, prop) {
if (prop === 'isImpersonated') {
return true
}
if (prop === 'hash') {
return () => {
try {
return target.hash()
} catch (_e) {
return keccak256(target.getHashedMessageToSign(), 'bytes')
}
}
}
if (prop === 'isSigned') {
return () => true
}
if (prop === 'getSenderAddress') {
return () => txData.impersonatedAddress
}
return Reflect.get(target, prop)
},
})
)
}