UNPKG

ox

Version:

Ethereum Standard Library

952 lines (892 loc) 31.3 kB
import type * as Address from './Address.js' import * as Errors from './Errors.js' import type * as Hash from './Hash.js' import * as Hex from './Hex.js' import type { Compute, UnionPartialBy } from './internal/types.js' import type * as Signature from './Signature.js' import * as Transaction from './Transaction.js' import type * as TransactionRequest from './TransactionRequest.js' import * as TxEnvelopeEip1559 from './TxEnvelopeEip1559.js' import * as TxEnvelopeEip2930 from './TxEnvelopeEip2930.js' import * as TxEnvelopeEip4844 from './TxEnvelopeEip4844.js' import * as TxEnvelopeEip7702 from './TxEnvelopeEip7702.js' import * as TxEnvelopeLegacy from './TxEnvelopeLegacy.js' import * as Value from './Value.js' /** Base type for a Transaction Envelope. Transaction Envelopes inherit this type. */ export type Base< type extends string = string, signed extends boolean = boolean, bigintType = bigint, numberType = number, > = Compute< { /** EIP-155 Chain ID. */ chainId: numberType /** Contract code or a hashed method call with encoded args */ data?: Hex.Hex | undefined /** @alias `data` – added for TransactionEnvelope - Transaction compatibility. */ input?: Hex.Hex | undefined /** * Sender of the transaction. RPC-only metadata; not part of the * serialized envelope. Carried here for parity with * {@link ox#TransactionRequest.TransactionRequest} and * {@link ox#Transaction.Transaction}. */ from?: Address.Address | undefined /** Gas provided for transaction execution */ gas?: bigintType | undefined /** Unique number identifying this transaction */ nonce?: bigintType | undefined /** Transaction recipient */ to?: Address.Address | null | undefined /** Transaction type */ type: type /** Value in wei sent with this transaction */ value?: bigintType | undefined /** ECDSA signature r. */ r?: Hex.Hex | undefined /** ECDSA signature s. */ s?: Hex.Hex | undefined /** ECDSA signature yParity. */ yParity?: numberType | undefined /** @deprecated ECDSA signature v (for backwards compatibility). */ v?: numberType | undefined } & (signed extends true ? { r: Hex.Hex; s: Hex.Hex } : {}) > /** RPC representation of a {@link ox#(TransactionEnvelope:namespace).Base}. */ export type BaseRpc< type extends string = string, signed extends boolean = boolean, > = Base<type, signed, Hex.Hex, Hex.Hex> /** Signed representation of a {@link ox#(TransactionEnvelope:namespace).Base}. */ export type BaseSigned<type extends string = string> = Base<type, true> /** Transaction Envelope. */ export type TxEnvelope< signed extends boolean = false, bigintType = bigint, numberType = number, > = UnionPartialBy< | TxEnvelopeLegacy.TxEnvelopeLegacy<signed, bigintType, numberType> | TxEnvelopeEip2930.TxEnvelopeEip2930<signed, bigintType, numberType> | TxEnvelopeEip1559.TxEnvelopeEip1559<signed, bigintType, numberType> | TxEnvelopeEip4844.TxEnvelopeEip4844<signed, bigintType, numberType> | TxEnvelopeEip7702.TxEnvelopeEip7702<signed, bigintType, numberType>, 'type' > /** RPC representation of a {@link ox#(TransactionEnvelope:namespace).TxEnvelope}. */ export type Rpc<signed extends boolean = false> = | TxEnvelopeLegacy.Rpc<signed> | TxEnvelopeEip2930.Rpc<signed> | TxEnvelopeEip1559.Rpc<signed> | TxEnvelopeEip4844.Rpc<signed> | TxEnvelopeEip7702.Rpc<signed> /** Serialized Transaction Envelope. */ export type Serialized = | TxEnvelopeLegacy.Serialized | TxEnvelopeEip2930.Serialized | TxEnvelopeEip1559.Serialized | TxEnvelopeEip4844.Serialized | TxEnvelopeEip7702.Serialized /** Transaction Envelope type. */ export type Type = | TxEnvelopeLegacy.Type | TxEnvelopeEip2930.Type | TxEnvelopeEip1559.Type | TxEnvelopeEip4844.Type | TxEnvelopeEip7702.Type type Typeable = | TxEnvelope | { readonly [key: string]: unknown readonly type?: string | undefined } type HasDefined<envelope, key extends string> = envelope extends { [_ in key]: infer value } ? [Exclude<value, undefined>] extends [never] ? false : true : false /** * Asserts a {@link ox#(TransactionEnvelope:namespace).TxEnvelope} is valid. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * TransactionEnvelope.assert({ * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }) * ``` * * @param envelope - The transaction envelope to assert. */ export function assert(envelope: TxEnvelope) { const type = getType(envelope) as Type | string if (type === 'legacy') return TxEnvelopeLegacy.assert(envelope as never) if (type === 'eip2930') return TxEnvelopeEip2930.assert(envelope as never) if (type === 'eip1559') return TxEnvelopeEip1559.assert(envelope as never) if (type === 'eip4844') return TxEnvelopeEip4844.assert(envelope as never) if (type === 'eip7702') return TxEnvelopeEip7702.assert(envelope as never) return TxEnvelopeEip1559.assert(envelope as never) } export declare namespace assert { type ErrorType = | TxEnvelopeLegacy.assert.ErrorType | TxEnvelopeEip2930.assert.ErrorType | TxEnvelopeEip1559.assert.ErrorType | TxEnvelopeEip4844.assert.ErrorType | TxEnvelopeEip7702.assert.ErrorType | InvalidTypeError | Errors.GlobalErrorType } /** * Deserializes a {@link ox#(TransactionEnvelope:namespace).TxEnvelope} from its serialized form. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const envelope = TransactionEnvelope.deserialize( * '0x02df0180808080808080c0' as TransactionEnvelope.Serialized * ) * ``` * * @param serialized - The serialized transaction envelope. * @returns Deserialized Transaction Envelope. */ export function deserialize<const serialized extends Serialized | Hex.Hex>( serialized: serialized | Serialized | Hex.Hex, ): deserialize.ReturnType<serialized> { const type = getSerializedType(serialized) if (type === 'legacy') return TxEnvelopeLegacy.deserialize(serialized) as never if (type === 'eip2930') return TxEnvelopeEip2930.deserialize(serialized as never) as never if (type === 'eip1559') return TxEnvelopeEip1559.deserialize(serialized as never) as never if (type === 'eip4844') return TxEnvelopeEip4844.deserialize(serialized as never) as never return TxEnvelopeEip7702.deserialize(serialized as never) as never } export declare namespace deserialize { type ReturnType<serialized extends Serialized | Hex.Hex = Serialized> = serialized extends TxEnvelopeLegacy.Serialized ? TxEnvelopeLegacy.TxEnvelopeLegacy : serialized extends TxEnvelopeEip2930.Serialized ? TxEnvelopeEip2930.TxEnvelopeEip2930 : serialized extends TxEnvelopeEip1559.Serialized ? TxEnvelopeEip1559.TxEnvelopeEip1559 : serialized extends TxEnvelopeEip4844.Serialized ? TxEnvelopeEip4844.TxEnvelopeEip4844 : serialized extends TxEnvelopeEip7702.Serialized ? TxEnvelopeEip7702.TxEnvelopeEip7702 : TxEnvelope type ErrorType = | getSerializedType.ErrorType | TxEnvelopeLegacy.deserialize.ErrorType | TxEnvelopeEip2930.deserialize.ErrorType | TxEnvelopeEip1559.deserialize.ErrorType | TxEnvelopeEip4844.deserialize.ErrorType | TxEnvelopeEip7702.deserialize.ErrorType | Errors.GlobalErrorType } /** * Converts an arbitrary transaction object or serialized transaction into a Transaction Envelope. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const envelope = TransactionEnvelope.from({ * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }) * ``` * * @param envelope - The transaction envelope. * @param options - Options. * @returns Transaction Envelope. */ export function from< const envelope extends Typeable | Hex.Hex, const signature extends Signature.Signature | undefined = undefined, >( envelope: envelope | Typeable | Hex.Hex, options: from.Options<signature> = {}, ): from.ReturnType<envelope> { if (typeof envelope === 'string') return deserialize(envelope) as never const type = getType(envelope) as Type | string if (type === 'legacy') return TxEnvelopeLegacy.from(envelope as never, options) as never if (type === 'eip2930') return TxEnvelopeEip2930.from(envelope as never, options) as never if (type === 'eip1559') return TxEnvelopeEip1559.from(envelope as never, options) as never if (type === 'eip4844') return TxEnvelopeEip4844.from(envelope as never, options) as never if (type === 'eip7702') return TxEnvelopeEip7702.from(envelope as never, options) as never return TxEnvelopeEip1559.from(envelope as never, options) as never } export declare namespace from { type Options<signature extends Signature.Signature | undefined = undefined> = { /** Signature to append to the Transaction Envelope. */ signature?: signature | Signature.Signature | undefined } type ReturnType< envelope extends Typeable | Hex.Hex = TxEnvelope | Hex.Hex, signature extends Signature.Signature | undefined = undefined, > = envelope extends Hex.Hex ? deserialize.ReturnType<envelope> : ReturnType_object<Extract<envelope, Typeable>, signature> type ReturnType_object< envelope extends Typeable, signature extends Signature.Signature | undefined = undefined, > = getType.ReturnType<envelope> extends 'legacy' ? TxEnvelopeLegacy.from.ReturnType< envelope & TxEnvelopeLegacy.TxEnvelopeLegacy, signature > : getType.ReturnType<envelope> extends 'eip2930' ? TxEnvelopeEip2930.from.ReturnType< envelope & TxEnvelopeEip2930.TxEnvelopeEip2930, signature > : getType.ReturnType<envelope> extends 'eip4844' ? TxEnvelopeEip4844.from.ReturnType< envelope & TxEnvelopeEip4844.TxEnvelopeEip4844, signature > : getType.ReturnType<envelope> extends 'eip7702' ? TxEnvelopeEip7702.from.ReturnType< envelope & TxEnvelopeEip7702.TxEnvelopeEip7702, signature > : TxEnvelopeEip1559.from.ReturnType< Omit<envelope, 'type'> & TxEnvelopeEip1559.TxEnvelopeEip1559, signature > type ErrorType = | deserialize.ErrorType | TxEnvelopeLegacy.from.ErrorType | TxEnvelopeEip2930.from.ErrorType | TxEnvelopeEip1559.from.ErrorType | TxEnvelopeEip4844.from.ErrorType | TxEnvelopeEip7702.from.ErrorType | InvalidTypeError | Errors.GlobalErrorType } /** * Returns the payload to sign for a {@link ox#(TransactionEnvelope:namespace).TxEnvelope}. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const payload = TransactionEnvelope.getSignPayload({ * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }) * ``` * * @param envelope - The transaction envelope. * @returns The sign payload. */ export function getSignPayload(envelope: TxEnvelope<false>): Hex.Hex { const type = getType(envelope) as Type | string if (type === 'legacy') return TxEnvelopeLegacy.getSignPayload(envelope as never) if (type === 'eip2930') return TxEnvelopeEip2930.getSignPayload(envelope as never) if (type === 'eip1559') return TxEnvelopeEip1559.getSignPayload(envelope as never) if (type === 'eip4844') return TxEnvelopeEip4844.getSignPayload(envelope as never) if (type === 'eip7702') return TxEnvelopeEip7702.getSignPayload(envelope as never) return TxEnvelopeEip1559.getSignPayload(envelope as never) } export declare namespace getSignPayload { type ReturnType = Hex.Hex type ErrorType = | TxEnvelopeLegacy.getSignPayload.ErrorType | TxEnvelopeEip2930.getSignPayload.ErrorType | TxEnvelopeEip1559.getSignPayload.ErrorType | TxEnvelopeEip4844.getSignPayload.ErrorType | TxEnvelopeEip7702.getSignPayload.ErrorType | InvalidTypeError | Errors.GlobalErrorType } /** * Returns the type of a Transaction Envelope. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const type = TransactionEnvelope.getType({ * maxFeePerGas: 1n * }) * // @log: 'eip1559' * ``` * * @param envelope - The transaction envelope. * @returns Transaction Envelope type. */ export function getType<const envelope extends Typeable>( envelope: envelope | Typeable, ): getType.ReturnType<envelope> { const type = envelope.type if (type) { // Guard against accidental RPC-style type strings that map to a known // canonical envelope type ('0x0'…'0x4'). Canonical envelopes use // 'legacy' | 'eip2930' | 'eip1559' | 'eip4844' | 'eip7702'. RPC payloads // should be normalized through `TransactionRequest.fromRpc` (which // translates via `Transaction.fromRpcType`) before reaching the envelope // layer. Other custom `0x*` types (e.g. OP-Stack `0x7e`) pass through. if (typeof type === 'string' && type in Transaction.fromRpcType) throw new InvalidTypeError({ type }) return type as never } if ( 'authorizationList' in envelope && envelope.authorizationList !== undefined ) return 'eip7702' as never if ( ('blobs' in envelope && envelope.blobs !== undefined) || ('blobVersionedHashes' in envelope && envelope.blobVersionedHashes !== undefined) || ('sidecars' in envelope && envelope.sidecars !== undefined) || ('maxFeePerBlobGas' in envelope && envelope.maxFeePerBlobGas !== undefined) ) return 'eip4844' as never if ( ('maxFeePerGas' in envelope && envelope.maxFeePerGas !== undefined) || ('maxPriorityFeePerGas' in envelope && envelope.maxPriorityFeePerGas !== undefined) ) return 'eip1559' as never if ('gasPrice' in envelope && envelope.gasPrice !== undefined) { if ('accessList' in envelope && envelope.accessList !== undefined) return 'eip2930' as never return 'legacy' as never } return 'eip1559' as never } export declare namespace getType { type ReturnType<envelope extends Typeable> = envelope extends { type: infer type extends string } ? type : HasDefined<envelope, 'authorizationList'> extends true ? TxEnvelopeEip7702.Type : HasDefined<envelope, 'blobs'> extends true ? TxEnvelopeEip4844.Type : HasDefined<envelope, 'blobVersionedHashes'> extends true ? TxEnvelopeEip4844.Type : HasDefined<envelope, 'sidecars'> extends true ? TxEnvelopeEip4844.Type : HasDefined<envelope, 'maxFeePerBlobGas'> extends true ? TxEnvelopeEip4844.Type : HasDefined<envelope, 'maxFeePerGas'> extends true ? TxEnvelopeEip1559.Type : HasDefined<envelope, 'maxPriorityFeePerGas'> extends true ? TxEnvelopeEip1559.Type : HasDefined<envelope, 'gasPrice'> extends true ? HasDefined<envelope, 'accessList'> extends true ? TxEnvelopeEip2930.Type : TxEnvelopeLegacy.Type : TxEnvelopeEip1559.Type type ErrorType = InvalidTypeError | Errors.GlobalErrorType } /** * Returns the type of a serialized Transaction Envelope. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const type = TransactionEnvelope.getSerializedType( * '0x02df0180808080808080c0' * ) * // @log: 'eip1559' * ``` * * @param serialized - The serialized transaction envelope. * @returns Transaction Envelope type. */ export function getSerializedType< const serialized extends Serialized | Hex.Hex, >( serialized: serialized | Serialized | Hex.Hex, ): getSerializedType.ReturnType<serialized> { if (Hex.size(serialized) === 0) throw new InvalidSerializedTypeError({ serialized }) const serializedType = Hex.slice(serialized, 0, 1) if (serializedType === TxEnvelopeEip2930.serializedType) return 'eip2930' as never if (serializedType === TxEnvelopeEip1559.serializedType) return 'eip1559' as never if (serializedType === TxEnvelopeEip4844.serializedType) return 'eip4844' as never if (serializedType === TxEnvelopeEip7702.serializedType) return 'eip7702' as never if (Hex.toNumber(serializedType) >= 0xc0) return 'legacy' as never throw new InvalidSerializedTypeError({ serialized }) } export declare namespace getSerializedType { type ReturnType<serialized extends Serialized | Hex.Hex = Serialized> = serialized extends TxEnvelopeEip2930.Serialized ? TxEnvelopeEip2930.Type : serialized extends TxEnvelopeEip1559.Serialized ? TxEnvelopeEip1559.Type : serialized extends TxEnvelopeEip4844.Serialized ? TxEnvelopeEip4844.Type : serialized extends TxEnvelopeEip7702.Serialized ? TxEnvelopeEip7702.Type : serialized extends TxEnvelopeLegacy.Serialized ? TxEnvelopeLegacy.Type : Type type ErrorType = | Hex.size.ErrorType | Hex.slice.ErrorType | Hex.toNumber.ErrorType | InvalidSerializedTypeError | Errors.GlobalErrorType } /** * Hashes a {@link ox#(TransactionEnvelope:namespace).TxEnvelope}. This is the "transaction hash". * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const hash = TransactionEnvelope.hash( * { * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }, * { presign: true } * ) * ``` * * @param envelope - The transaction envelope to hash. * @param options - Options. * @returns The hash of the transaction envelope. */ export function hash<presign extends boolean = false>( envelope: TxEnvelope<presign extends true ? false : true>, options: hash.Options<presign> = {}, ): hash.ReturnType { const type = getType(envelope) as Type | string if (type === 'legacy') return TxEnvelopeLegacy.hash(envelope as never, options) if (type === 'eip2930') return TxEnvelopeEip2930.hash(envelope as never, options) if (type === 'eip1559') return TxEnvelopeEip1559.hash(envelope as never, options) if (type === 'eip4844') return TxEnvelopeEip4844.hash(envelope as never, options) if (type === 'eip7702') return TxEnvelopeEip7702.hash(envelope as never, options) return TxEnvelopeEip1559.hash(envelope as never, options) } export declare namespace hash { type Options<presign extends boolean = false> = { /** Whether to hash this transaction for signing. @default false */ presign?: presign | boolean | undefined } type ReturnType = Hex.Hex type ErrorType = | Hash.keccak256.ErrorType | serialize.ErrorType | InvalidTypeError | Errors.GlobalErrorType } /** * Serializes a {@link ox#(TransactionEnvelope:namespace).TxEnvelope}. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const serialized = TransactionEnvelope.serialize({ * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }) * ``` * * @param envelope - The transaction envelope to serialize. * @param options - Options. * @returns Serialized transaction envelope. */ export function serialize<const envelope extends Typeable>( envelope: envelope | Typeable, options: serialize.Options = {}, ): serialize.ReturnType<envelope> { const type = getType(envelope) as Type | string if (type === 'legacy') return TxEnvelopeLegacy.serialize(envelope as never, options) as never if (type === 'eip2930') return TxEnvelopeEip2930.serialize(envelope as never, options) as never if (type === 'eip1559') return TxEnvelopeEip1559.serialize(envelope as never, options) as never if (type === 'eip4844') return TxEnvelopeEip4844.serialize(envelope as never, options) as never if (type === 'eip7702') return TxEnvelopeEip7702.serialize(envelope as never, options) as never return TxEnvelopeEip1559.serialize(envelope as never, options) as never } export declare namespace serialize { type Options = { /** Signature to append to the serialized Transaction Envelope. */ signature?: Signature.Signature | undefined /** PeerDAS sidecars to append, producing the 5-element network wrapper. */ sidecars?: TxEnvelopeEip4844.Sidecars<Hex.Hex> | undefined } type ReturnType<envelope extends Typeable = TxEnvelope> = getType.ReturnType<envelope> extends 'legacy' ? TxEnvelopeLegacy.Serialized : getType.ReturnType<envelope> extends 'eip2930' ? TxEnvelopeEip2930.Serialized : getType.ReturnType<envelope> extends 'eip4844' ? TxEnvelopeEip4844.Serialized : getType.ReturnType<envelope> extends 'eip7702' ? TxEnvelopeEip7702.Serialized : TxEnvelopeEip1559.Serialized type ErrorType = | TxEnvelopeLegacy.serialize.ErrorType | TxEnvelopeEip2930.serialize.ErrorType | TxEnvelopeEip1559.serialize.ErrorType | TxEnvelopeEip4844.serialize.ErrorType | TxEnvelopeEip7702.serialize.ErrorType | InvalidTypeError | Errors.GlobalErrorType } /** * Converts a {@link ox#(TransactionEnvelope:namespace).TxEnvelope} to an {@link ox#(TransactionEnvelope:namespace).Rpc}. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const envelope_rpc = TransactionEnvelope.toRpc({ * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }) * ``` * * @param envelope - The transaction envelope. * @returns RPC representation. */ export function toRpc<const envelope extends toRpc.Input>( envelope: envelope | toRpc.Input, ): toRpc.ReturnType<envelope> { const type = getType(envelope) as Type | string if (type === 'legacy') return TxEnvelopeLegacy.toRpc(envelope as never) as never if (type === 'eip2930') return TxEnvelopeEip2930.toRpc(envelope as never) as never if (type === 'eip1559') return TxEnvelopeEip1559.toRpc(envelope as never) as never if (type === 'eip4844') return TxEnvelopeEip4844.toRpc(envelope as never) as never if (type === 'eip7702') return TxEnvelopeEip7702.toRpc(envelope as never) as never return TxEnvelopeEip1559.toRpc(envelope as never) as never } export declare namespace toRpc { /** Numberish input accepted by {@link ox#(TransactionEnvelope:namespace).(toRpc:function)}. */ export type Input = TxEnvelope< boolean, Hex.Hex | bigint | number, Hex.Hex | number > export type ReturnType<envelope extends Typeable = TxEnvelope> = getType.ReturnType<envelope> extends 'legacy' ? TxEnvelopeLegacy.Rpc : getType.ReturnType<envelope> extends 'eip2930' ? TxEnvelopeEip2930.Rpc : getType.ReturnType<envelope> extends 'eip4844' ? TxEnvelopeEip4844.Rpc : getType.ReturnType<envelope> extends 'eip7702' ? TxEnvelopeEip7702.Rpc : TxEnvelopeEip1559.Rpc export type ErrorType = | TxEnvelopeLegacy.toRpc.ErrorType | TxEnvelopeEip2930.toRpc.ErrorType | TxEnvelopeEip1559.toRpc.ErrorType | TxEnvelopeEip4844.toRpc.ErrorType | TxEnvelopeEip7702.toRpc.ErrorType | InvalidTypeError | Errors.GlobalErrorType } /** * Converts a {@link ox#(TransactionEnvelope:namespace).TxEnvelope} to a {@link ox#TransactionRequest.TransactionRequest}. * * Flattens any EIP-7594 `sidecars` back into the top-level `blobs` field. * Signature fields (`r`, `s`, `yParity`, `v`) are preserved — Ox's * `TransactionRequest` extends the Execution API `GenericTransaction` * shape to optionally carry signed payloads. Pair with * {@link ox#TransactionRequest.(toRpc:function)} to produce an * `eth_sendTransaction`-shaped payload. * * Note: the 4844 round-trip * `TxEnvelope → TransactionRequest → TxEnvelope` is **lossy** — * `sidecars.commitments` and `sidecars.cellProofs` are not preserved on * the `TransactionRequest` shape. Callers that need full round-trip * parity must carry sidecars out of band. * * @example * ```ts twoslash * import { TransactionEnvelope, TxEnvelopeEip1559 } from 'ox' * * const envelope = TxEnvelopeEip1559.from({ * chainId: 1, * maxFeePerGas: 1n, * to: '0x0000000000000000000000000000000000000000', * value: 1n * }) * * const request = * TransactionEnvelope.toTransactionRequest(envelope) * // @log: { * // @log: chainId: 1, * // @log: maxFeePerGas: 1n, * // @log: to: '0x0000000000000000000000000000000000000000', * // @log: type: 'eip1559', * // @log: value: 1n, * // @log: } * ``` * * @param envelope - The transaction envelope to convert. * @returns A transaction request. */ export function toTransactionRequest( envelope: TxEnvelope, ): TransactionRequest.TransactionRequest { const { // Flatten sidecars; surface their `blobs` payload instead. sidecars, blobs, ...rest } = envelope as TxEnvelope & { sidecars?: TxEnvelopeEip4844.Sidecars<Hex.Hex> | undefined blobs?: readonly Hex.Hex[] | undefined } const request: TransactionRequest.TransactionRequest = { ...rest } const blobs_ = blobs ?? sidecars?.blobs if (blobs_) request.blobs = blobs_ return request } export declare namespace toTransactionRequest { type ErrorType = Errors.GlobalErrorType } /** * Validates a {@link ox#(TransactionEnvelope:namespace).TxEnvelope}. Returns `true` if the envelope is valid, `false` otherwise. * * @example * ```ts twoslash * import { TransactionEnvelope } from 'ox' * * const valid = TransactionEnvelope.validate({ * chainId: 1, * maxFeePerGas: 1n, * type: 'eip1559' * }) * // @log: true * ``` * * @param envelope - The transaction envelope to validate. */ export function validate(envelope: TxEnvelope) { try { assert(envelope) return true } catch { return false } } export declare namespace validate { type ErrorType = Errors.GlobalErrorType } /** * Thrown when a fee cap is too high. * * @example * ```ts twoslash * import { TxEnvelopeEip1559 } from 'ox' * * TxEnvelopeEip1559.assert({ * maxFeePerGas: 2n ** 256n - 1n + 1n, * chainId: 1 * }) * // @error: TransactionEnvelope.FeeCapTooHighError: The fee cap (`maxFeePerGas`/`maxPriorityFeePerGas` = 115792089237316195423570985008687907853269984665640564039457584007913.129639936 gwei) cannot be higher than the maximum allowed value (2^256-1). * ``` */ export class FeeCapTooHighError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.FeeCapTooHighError' constructor({ feeCap, }: { feeCap?: bigint | undefined } = {}) { super( `The fee cap (\`maxFeePerGas\`/\`maxPriorityFeePerGas\`${ feeCap ? ` = ${Value.formatGwei(feeCap)} gwei` : '' }) cannot be higher than the maximum allowed value (2^256-1).`, ) } } /** * Thrown when a gas price is too high. * * @example * ```ts twoslash * import { TxEnvelopeLegacy } from 'ox' * * TxEnvelopeLegacy.assert({ * gasPrice: 2n ** 256n - 1n + 1n, * chainId: 1 * }) * // @error: TransactionEnvelope.GasPriceTooHighError: The gas price (`gasPrice` = 115792089237316195423570985008687907853269984665640564039457584007913.129639936 gwei) cannot be higher than the maximum allowed value (2^256-1). * ``` */ export class GasPriceTooHighError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.GasPriceTooHighError' constructor({ gasPrice, }: { gasPrice?: bigint | undefined } = {}) { super( `The gas price (\`gasPrice\`${ gasPrice ? ` = ${Value.formatGwei(gasPrice)} gwei` : '' }) cannot be higher than the maximum allowed value (2^256-1).`, ) } } /** * Thrown when a chain ID is invalid. * * @example * ```ts twoslash * import { TxEnvelopeEip1559 } from 'ox' * * TxEnvelopeEip1559.assert({ chainId: 0 }) * // @error: TransactionEnvelope.InvalidChainIdError: Chain ID "0" is invalid. * ``` */ export class InvalidChainIdError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.InvalidChainIdError' constructor({ chainId }: { chainId?: number | undefined }) { super( typeof chainId !== 'undefined' ? `Chain ID "${chainId}" is invalid.` : 'Chain ID is invalid.', ) } } /** * Thrown when a serialized transaction is invalid. * * @example * ```ts twoslash * import { TxEnvelopeEip1559 } from 'ox' * * TxEnvelopeEip1559.deserialize('0x02c0') * // @error: TransactionEnvelope.InvalidSerializedError: Invalid serialized transaction of type "eip1559" was provided. * // @error: Serialized Transaction: "0x02c0" * // @error: Missing Attributes: chainId, nonce, maxPriorityFeePerGas, maxFeePerGas, gas, to, value, data, accessList * ``` */ export class InvalidSerializedError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.InvalidSerializedError' constructor({ attributes, serialized, type, }: { attributes: Record<string, unknown> serialized: Hex.Hex type: string }) { 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: "${serialized}"`, missing.length > 0 ? `Missing Attributes: ${missing.join(', ')}` : '', ].filter(Boolean), }) } } /** Thrown when a serialized transaction type cannot be resolved. */ export class InvalidSerializedTypeError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.InvalidSerializedTypeError' constructor({ serialized }: { serialized: Hex.Hex }) { super('Serialized transaction type is invalid.', { metaMessages: [`Serialized Transaction: "${serialized}"`], }) } } /** Thrown when a transaction envelope type cannot be resolved. */ export class InvalidTypeError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.InvalidTypeError' constructor({ type }: { type?: string | undefined } = {}) { super( type ? `Transaction type "${type}" is invalid.` : 'Cannot infer transaction type from provided envelope.', ) } } /** * Thrown when a tip is higher than a fee cap. * * @example * ```ts twoslash * import { TxEnvelopeEip1559 } from 'ox' * * TxEnvelopeEip1559.assert({ * chainId: 1, * maxFeePerGas: 10n, * maxPriorityFeePerGas: 11n * }) * // @error: TransactionEnvelope.TipAboveFeeCapError: The provided tip (`maxPriorityFeePerGas` = 11 gwei) cannot be higher than the fee cap (`maxFeePerGas` = 10 gwei). * ``` */ export class TipAboveFeeCapError extends Errors.BaseError { override readonly name = 'TransactionEnvelope.TipAboveFeeCapError' constructor({ maxPriorityFeePerGas, maxFeePerGas, }: { maxPriorityFeePerGas?: bigint | undefined maxFeePerGas?: bigint | undefined } = {}) { super( [ `The provided tip (\`maxPriorityFeePerGas\`${ maxPriorityFeePerGas ? ` = ${Value.formatGwei(maxPriorityFeePerGas)} gwei` : '' }) cannot be higher than the fee cap (\`maxFeePerGas\`${ maxFeePerGas ? ` = ${Value.formatGwei(maxFeePerGas)} gwei` : '' }).`, ].join('\n'), ) } }