UNPKG

@nomicfoundation/ethereumjs-tx

Version:
112 lines (92 loc) 2.95 kB
import { SECP256K1_ORDER_DIV_2, bigIntToUnpaddedBytes, ecrecover, } from '@nomicfoundation/ethereumjs-util' import { keccak256 as bufferKeccak256 } from 'ethereum-cryptography/keccak.js' import { BaseTransaction } from '../baseTransaction.js' import { Capability } from '../types.js' import type { LegacyTxInterface } from '../types.js' function keccak256(msg: Uint8Array): Uint8Array { return new Uint8Array(bufferKeccak256(Buffer.from(msg))) } export function errorMsg(tx: LegacyTxInterface, msg: string) { return `${msg} (${tx.errorStr()})` } export function isSigned(tx: LegacyTxInterface): boolean { const { v, r, s } = tx if (v === undefined || r === undefined || s === undefined) { return false } else { return true } } /** * The amount of gas paid for the data in this tx */ export function getDataFee(tx: LegacyTxInterface, extraCost?: bigint): bigint { if (tx.cache.dataFee && tx.cache.dataFee.hardfork === tx.common.hardfork()) { return tx.cache.dataFee.value } const cost = BaseTransaction.prototype.getDataFee.bind(tx)() + (extraCost ?? 0n) if (Object.isFrozen(tx)) { tx.cache.dataFee = { value: cost, hardfork: tx.common.hardfork(), } } return cost } export function hash(tx: LegacyTxInterface): Uint8Array { if (!tx.isSigned()) { const msg = errorMsg(tx, 'Cannot call hash method if transaction is not signed') throw new Error(msg) } const keccakFunction = tx.common.customCrypto.keccak256 ?? keccak256 if (Object.isFrozen(tx)) { if (!tx.cache.hash) { tx.cache.hash = keccakFunction(tx.serialize()) } return tx.cache.hash } return keccakFunction(tx.serialize()) } /** * EIP-2: All transaction signatures whose s-value is greater than secp256k1n/2are considered invalid. * Reasoning: https://ethereum.stackexchange.com/a/55728 */ export function validateHighS(tx: LegacyTxInterface): void { const { s } = tx if (tx.common.gteHardfork('homestead') && s !== undefined && s > SECP256K1_ORDER_DIV_2) { const msg = errorMsg( tx, 'Invalid Signature: s-values greater than secp256k1n/2 are considered invalid' ) throw new Error(msg) } } export function getSenderPublicKey(tx: LegacyTxInterface): Uint8Array { if (tx.cache.senderPubKey !== undefined) { return tx.cache.senderPubKey } const msgHash = tx.getMessageToVerifySignature() const { v, r, s } = tx validateHighS(tx) try { 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)) { tx.cache.senderPubKey = sender } return sender } catch (e: any) { const msg = errorMsg(tx, 'Invalid Signature') throw new Error(msg) } }