ox
Version:
334 lines (318 loc) • 13.5 kB
text/typescript
import type * as Address from './Address.js'
import type * as Errors from './Errors.js'
import * as Hex from './Hex.js'
import type { Compute } from './internal/types.js'
import * as Log from './Log.js'
/** An Transaction Receipt as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.yaml). */
export type TransactionReceipt<
status = Status,
type = Type,
bigintType = bigint,
numberType = number,
> = Compute<{
/** The actual value per gas deducted from the sender's account for blob gas. Only specified for blob transactions as defined by EIP-4844. */
blobGasPrice?: bigintType | undefined
/** The amount of blob gas used. Only specified for blob transactions as defined by EIP-4844. */
blobGasUsed?: bigintType | undefined
/** Hash of block containing this transaction */
blockHash: Hex.Hex
/** Number of block containing this transaction */
blockNumber: bigintType
/** Address of new contract or `null` if no contract was created */
contractAddress?: Address.Address | null | undefined
/** Gas used by this and all preceding transactions in this block */
cumulativeGasUsed: bigintType
/** Pre-London, it is equal to the transaction's gasPrice. Post-London, it is equal to the actual gas price paid for inclusion. */
effectiveGasPrice: bigintType
/** Transaction sender */
from: Address.Address
/** Gas used by this transaction */
gasUsed: bigintType
/** List of log objects generated by this transaction */
logs: Log.Log<false, bigintType, numberType>[]
/** Logs bloom filter */
logsBloom: Hex.Hex
/** The post-transaction state root. Only specified for transactions included before the Byzantium upgrade. */
root?: Hex.Hex | undefined
/** `success` if this transaction was successful or `reverted` if it failed */
status: status
/** Transaction recipient or `null` if deploying a contract */
to: Address.Address | null
/** Hash of this transaction */
transactionHash: Hex.Hex
/** Index of this transaction in the block */
transactionIndex: numberType
/** Transaction type */
type: type
}>
/** An RPC Transaction Receipt as defined in the [Execution API specification](https://github.com/ethereum/execution-apis/blob/main/src/schemas/receipt.yaml). */
export type Rpc = TransactionReceipt<RpcStatus, RpcType, Hex.Hex, Hex.Hex>
/**
* Union of Transaction Receipt statuses.
*
* - `success`
* - `reverted`
*/
export type Status = 'success' | 'reverted'
/**
* Union of RPC Transaction Receipt statuses.
*
* - `0x0`
* - `0x1`
*/
export type RpcStatus = '0x0' | '0x1'
/**
* Union of Transaction Receipt types.
*
* - `legacy`
* - `eip1559`
* - `eip2930`
* - `eip4844`
* - `eip7702`
* - any other string
*/
export type Type =
| 'legacy'
| 'eip1559'
| 'eip2930'
| 'eip4844'
| 'eip7702'
| (string & {})
/**
* Union of RPC Transaction Receipt types.
*
* - `0x0`: legacy transactions
* - `0x1`: EIP-1559 transactions
* - `0x2`: EIP-2930 transactions
* - `0x3`: EIP-4844 transactions
* - `0x4`: EIP-7702 transactions
* - any other string
*/
export type RpcType = '0x0' | '0x1' | '0x2' | '0x3' | '0x4' | (string & {})
/** RPC status to status mapping. */
export const fromRpcStatus = {
'0x0': 'reverted',
'0x1': 'success',
} as const
/** Status to RPC status mapping. */
export const toRpcStatus = {
reverted: '0x0',
success: '0x1',
} as const
/** RPC type to type mapping. */
export const fromRpcType = {
'0x0': 'legacy',
'0x1': 'eip2930',
'0x2': 'eip1559',
'0x3': 'eip4844',
'0x4': 'eip7702',
} as const
/** Type to RPC type mapping. */
export const toRpcType = {
legacy: '0x0',
eip2930: '0x1',
eip1559: '0x2',
eip4844: '0x3',
eip7702: '0x4',
} as const
/**
* Converts a {@link ox#TransactionReceipt.Rpc} to an {@link ox#TransactionReceipt.TransactionReceipt}.
*
* @example
* ```ts twoslash
* import { TransactionReceipt } from 'ox'
*
* const receipt = TransactionReceipt.fromRpc({
* blobGasPrice: '0x42069',
* blobGasUsed: '0x1337',
* blockHash:
* '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
* blockNumber: '0x12f296f',
* contractAddress: null,
* cumulativeGasUsed: '0x82515',
* effectiveGasPrice: '0x21c2f6c09',
* from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6',
* gasUsed: '0x2abba',
* logs: [],
* logsBloom:
* '0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000',
* status: '0x1',
* to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
* transactionHash:
* '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* transactionIndex: '0x2',
* type: '0x2',
* })
* // @log: {
* // @log: blobGasPrice: 270441n,
* // @log: blobGasUsed: 4919n,
* // @log: blockHash: "0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b",
* // @log: blockNumber: 19868015n,
* // @log: contractAddress: null,
* // @log: cumulativeGasUsed: 533781n,
* // @log: effectiveGasPrice: 9062804489n,
* // @log: from: "0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6",
* // @log: gasUsed: 175034n,
* // @log: logs: [],
* // @log: logsBloom: "0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000",
* // @log: root: undefined,
* // @log: status: "success",
* // @log: to: "0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad",
* // @log: transactionHash: "0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0",
* // @log: transactionIndex: 2,
* // @log: type: "eip1559",
* // @log: }
* ```
*
* @example
* ### End-to-end
*
* Below is an example of how to use the `TransactionReceipt.fromRpc` method to convert an RPC transaction receipt to a {@link ox#TransactionReceipt.TransactionReceipt} object.
*
* ```ts twoslash
* import 'ox/window'
* import { TransactionReceipt } from 'ox'
*
* const receipt = await window.ethereum!
* .request({
* method: 'eth_getTransactionReceipt',
* params: [
* '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* ],
* })
* .then(TransactionReceipt.fromRpc) // [!code hl]
* // @log: {
* // @log: blobGasPrice: 270441n,
* // @log: blobGasUsed: 4919n,
* // @log: blockHash: "0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b",
* // @log: blockNumber: 19868015n,
* // @log: contractAddress: null,
* // @log: cumulativeGasUsed: 533781n,
* // @log: effectiveGasPrice: 9062804489n,
* // @log: from: "0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6",
* // @log: gasUsed: 175034n,
* // @log: logs: [],
* // @log: logsBloom: "0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000",
* // @log: root: undefined,
* // @log: status: "success",
* // @log: to: "0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad",
* // @log: transactionHash: "0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0",
* // @log: transactionIndex: 2,
* // @log: type: "eip1559",
* // @log: }
* ```
*
* :::note
*
* For simplicity, the above example uses `window.ethereum.request`, but you can use any
* type of JSON-RPC interface.
*
* :::
*
* @param receipt - The RPC receipt to convert.
* @returns An instantiated {@link ox#TransactionReceipt.TransactionReceipt}.
*/
export function fromRpc<const receipt extends Rpc | null>(
receipt: receipt | Rpc | null,
): receipt extends Rpc ? TransactionReceipt : null {
if (!receipt) return null as never
return {
...receipt,
blobGasPrice: receipt.blobGasPrice
? BigInt(receipt.blobGasPrice)
: undefined,
blobGasUsed: receipt.blobGasUsed ? BigInt(receipt.blobGasUsed) : undefined,
blockNumber: BigInt(receipt.blockNumber ?? 0n),
cumulativeGasUsed: BigInt(receipt.cumulativeGasUsed ?? 0n),
effectiveGasPrice: BigInt(receipt.effectiveGasPrice ?? 0n),
gasUsed: BigInt(receipt.gasUsed ?? 0n),
logs: receipt.logs.map((log) => Log.fromRpc(log, { pending: false })),
status: fromRpcStatus[receipt.status],
transactionIndex: Number(receipt.transactionIndex ?? 0),
type: (fromRpcType as any)[receipt.type] || receipt.type,
} as never
}
export declare namespace fromRpc {
export type ErrorType = Log.fromRpc.ErrorType | Errors.GlobalErrorType
}
/**
* Converts a {@link ox#TransactionReceipt.TransactionReceipt} to a {@link ox#TransactionReceipt.Rpc}.
*
* @example
* ```ts twoslash
* import { TransactionReceipt } from 'ox'
*
* const receipt = TransactionReceipt.toRpc({
* blobGasPrice: 270441n,
* blobGasUsed: 4919n,
* blockHash:
* '0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b',
* blockNumber: 19868015n,
* contractAddress: null,
* cumulativeGasUsed: 533781n,
* effectiveGasPrice: 9062804489n,
* from: '0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6',
* gasUsed: 175034n,
* logs: [],
* logsBloom:
* '0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000',
* root: undefined,
* status: 'success',
* to: '0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad',
* transactionHash:
* '0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0',
* transactionIndex: 2,
* type: 'eip1559',
* })
* // @log: {
* // @log: blobGasPrice: "0x042069",
* // @log: blobGasUsed: "0x1337",
* // @log: blockHash: "0xc350d807505fb835650f0013632c5515592987ba169bbc6626d9fc54d91f0f0b",
* // @log: blockNumber: "0x012f296f",
* // @log: contractAddress: null,
* // @log: cumulativeGasUsed: "0x082515",
* // @log: effectiveGasPrice: "0x021c2f6c09",
* // @log: from: "0x814e5e0e31016b9a7f138c76b7e7b2bb5c1ab6a6",
* // @log: gasUsed: "0x02abba",
* // @log: logs: [],
* // @log: logsBloom: "0x00200000000000000000008080000000000000000040000000000000000000000000000000000000000000000000000022000000080000000000000000000000000000080000000000000008000000200000000000000000000200008020400000000000000000280000000000100000000000000000000000000010000000000000000000020000000000000020000000000001000000080000004000000000000000000000000000000000000000000000400000000000001000000000000000000002000000000000000020000000000000000000001000000000000000000000200000000000000000000000000000001000000000c00000000000000000",
* // @log: root: undefined,
* // @log: status: "0x1",
* // @log: to: "0x3fc91a3afd70395cd496c647d5a6cc9d4b2b7fad",
* // @log: transactionHash: "0x353fdfc38a2f26115daadee9f5b8392ce62b84f410957967e2ed56b35338cdd0",
* // @log: transactionIndex: "0x02",
* // @log: type: "eip1559",
* // @log: }
* ```
*
* @param receipt - The receipt to convert.
* @returns An RPC receipt.
*/
export function toRpc(receipt: TransactionReceipt): Rpc {
return {
blobGasPrice: receipt.blobGasPrice
? Hex.fromNumber(receipt.blobGasPrice)
: undefined,
blobGasUsed: receipt.blobGasUsed
? Hex.fromNumber(receipt.blobGasUsed)
: undefined,
blockHash: receipt.blockHash,
blockNumber: Hex.fromNumber(receipt.blockNumber),
contractAddress: receipt.contractAddress,
cumulativeGasUsed: Hex.fromNumber(receipt.cumulativeGasUsed),
effectiveGasPrice: Hex.fromNumber(receipt.effectiveGasPrice),
from: receipt.from,
gasUsed: Hex.fromNumber(receipt.gasUsed),
logs: receipt.logs.map(Log.toRpc as never),
logsBloom: receipt.logsBloom,
root: receipt.root,
status: toRpcStatus[receipt.status],
to: receipt.to,
transactionHash: receipt.transactionHash,
transactionIndex: Hex.fromNumber(receipt.transactionIndex),
type: (toRpcType as any)[receipt.type] ?? receipt.type,
}
}
export declare namespace toRpc {
export type ErrorType = Hex.fromNumber.ErrorType | Errors.GlobalErrorType
}