viem
Version:
260 lines (241 loc) • 8.12 kB
text/typescript
import type { Account } from '../accounts/types.js'
import type { SendTransactionParameters } from '../actions/wallet/sendTransaction.js'
import type { BlockTag } from '../types/block.js'
import type { Chain } from '../types/chain.js'
import type { Hash, Hex } from '../types/misc.js'
import type { TransactionType } from '../types/transaction.js'
import { formatEther } from '../utils/unit/formatEther.js'
import { formatGwei } from '../utils/unit/formatGwei.js'
import { BaseError } from './base.js'
export function prettyPrint(
args: Record<string, bigint | number | string | undefined | false | unknown>,
) {
const entries = Object.entries(args)
.map(([key, value]) => {
if (value === undefined || value === false) return null
return [key, value]
})
.filter(Boolean) as [string, string][]
const maxLength = entries.reduce((acc, [key]) => Math.max(acc, key.length), 0)
return entries
.map(([key, value]) => ` ${`${key}:`.padEnd(maxLength + 1)} ${value}`)
.join('\n')
}
export type FeeConflictErrorType = FeeConflictError & {
name: 'FeeConflictError'
}
export class FeeConflictError extends BaseError {
constructor() {
super(
[
'Cannot specify both a `gasPrice` and a `maxFeePerGas`/`maxPriorityFeePerGas`.',
'Use `maxFeePerGas`/`maxPriorityFeePerGas` for EIP-1559 compatible networks, and `gasPrice` for others.',
].join('\n'),
{ name: 'FeeConflictError' },
)
}
}
export type InvalidLegacyVErrorType = InvalidLegacyVError & {
name: 'InvalidLegacyVError'
}
export class InvalidLegacyVError extends BaseError {
constructor({ v }: { v: bigint }) {
super(`Invalid \`v\` value "${v}". Expected 27 or 28.`, {
name: 'InvalidLegacyVError',
})
}
}
export type InvalidSerializableTransactionErrorType =
InvalidSerializableTransactionError & {
name: 'InvalidSerializableTransactionError'
}
export class InvalidSerializableTransactionError extends BaseError {
constructor({ transaction }: { transaction: Record<string, unknown> }) {
super('Cannot infer a transaction type from provided transaction.', {
metaMessages: [
'Provided Transaction:',
'{',
prettyPrint(transaction),
'}',
'',
'To infer the type, either provide:',
'- a `type` to the Transaction, or',
'- an EIP-1559 Transaction with `maxFeePerGas`, or',
'- an EIP-2930 Transaction with `gasPrice` & `accessList`, or',
'- an EIP-4844 Transaction with `blobs`, `blobVersionedHashes`, `sidecars`, or',
'- an EIP-7702 Transaction with `authorizationList`, or',
'- a Legacy Transaction with `gasPrice`',
],
name: 'InvalidSerializableTransactionError',
})
}
}
export type InvalidSerializedTransactionTypeErrorType =
InvalidSerializedTransactionTypeError & {
name: 'InvalidSerializedTransactionTypeError'
}
export class InvalidSerializedTransactionTypeError extends BaseError {
serializedType: Hex
constructor({ serializedType }: { serializedType: Hex }) {
super(`Serialized transaction type "${serializedType}" is invalid.`, {
name: 'InvalidSerializedTransactionType',
})
this.serializedType = serializedType
}
}
export type InvalidSerializedTransactionErrorType =
InvalidSerializedTransactionError & {
name: 'InvalidSerializedTransactionError'
}
export class InvalidSerializedTransactionError extends BaseError {
serializedTransaction: Hex
type: TransactionType
constructor({
attributes,
serializedTransaction,
type,
}: {
attributes: Record<string, unknown>
serializedTransaction: Hex
type: TransactionType
}) {
const missing = Object.entries(attributes)
.map(([key, value]) => (typeof value === 'undefined' ? key : undefined))
.filter(Boolean)
super(`Invalid serialized transaction of type "${type}" was provided.`, {
metaMessages: [
`Serialized Transaction: "${serializedTransaction}"`,
missing.length > 0 ? `Missing Attributes: ${missing.join(', ')}` : '',
].filter(Boolean),
name: 'InvalidSerializedTransactionError',
})
this.serializedTransaction = serializedTransaction
this.type = type
}
}
export type InvalidStorageKeySizeErrorType = InvalidStorageKeySizeError & {
name: 'InvalidStorageKeySizeError'
}
export class InvalidStorageKeySizeError extends BaseError {
constructor({ storageKey }: { storageKey: Hex }) {
super(
`Size for storage key "${storageKey}" is invalid. Expected 32 bytes. Got ${Math.floor(
(storageKey.length - 2) / 2,
)} bytes.`,
{ name: 'InvalidStorageKeySizeError' },
)
}
}
export type TransactionExecutionErrorType = TransactionExecutionError & {
name: 'TransactionExecutionError'
}
export class TransactionExecutionError extends BaseError {
override cause: BaseError
constructor(
cause: BaseError,
{
account,
docsPath,
chain,
data,
gas,
gasPrice,
maxFeePerGas,
maxPriorityFeePerGas,
nonce,
to,
value,
}: Omit<SendTransactionParameters, 'account' | 'chain'> & {
account: Account | null
chain?: Chain | undefined
docsPath?: string | undefined
},
) {
const prettyArgs = prettyPrint({
chain: chain && `${chain?.name} (id: ${chain?.id})`,
from: account?.address,
to,
value:
typeof value !== 'undefined' &&
`${formatEther(value)} ${chain?.nativeCurrency?.symbol || 'ETH'}`,
data,
gas,
gasPrice:
typeof gasPrice !== 'undefined' && `${formatGwei(gasPrice)} gwei`,
maxFeePerGas:
typeof maxFeePerGas !== 'undefined' &&
`${formatGwei(maxFeePerGas)} gwei`,
maxPriorityFeePerGas:
typeof maxPriorityFeePerGas !== 'undefined' &&
`${formatGwei(maxPriorityFeePerGas)} gwei`,
nonce,
})
super(cause.shortMessage, {
cause,
docsPath,
metaMessages: [
...(cause.metaMessages ? [...cause.metaMessages, ' '] : []),
'Request Arguments:',
prettyArgs,
].filter(Boolean) as string[],
name: 'TransactionExecutionError',
})
this.cause = cause
}
}
export type TransactionNotFoundErrorType = TransactionNotFoundError & {
name: 'TransactionNotFoundError'
}
export class TransactionNotFoundError extends BaseError {
constructor({
blockHash,
blockNumber,
blockTag,
hash,
index,
}: {
blockHash?: Hash | undefined
blockNumber?: bigint | undefined
blockTag?: BlockTag | undefined
hash?: Hash | undefined
index?: number | undefined
}) {
let identifier = 'Transaction'
if (blockTag && index !== undefined)
identifier = `Transaction at block time "${blockTag}" at index "${index}"`
if (blockHash && index !== undefined)
identifier = `Transaction at block hash "${blockHash}" at index "${index}"`
if (blockNumber && index !== undefined)
identifier = `Transaction at block number "${blockNumber}" at index "${index}"`
if (hash) identifier = `Transaction with hash "${hash}"`
super(`${identifier} could not be found.`, {
name: 'TransactionNotFoundError',
})
}
}
export type TransactionReceiptNotFoundErrorType =
TransactionReceiptNotFoundError & {
name: 'TransactionReceiptNotFoundError'
}
export class TransactionReceiptNotFoundError extends BaseError {
constructor({ hash }: { hash: Hash }) {
super(
`Transaction receipt with hash "${hash}" could not be found. The Transaction may not be processed on a block yet.`,
{
name: 'TransactionReceiptNotFoundError',
},
)
}
}
export type WaitForTransactionReceiptTimeoutErrorType =
WaitForTransactionReceiptTimeoutError & {
name: 'WaitForTransactionReceiptTimeoutError'
}
export class WaitForTransactionReceiptTimeoutError extends BaseError {
constructor({ hash }: { hash: Hash }) {
super(
`Timed out while waiting for transaction with hash "${hash}" to be confirmed.`,
{ name: 'WaitForTransactionReceiptTimeoutError' },
)
}
}