Skip to main content

reth_rpc_api/
otterscan.rs

1use alloy_eips::{eip1898::LenientBlockNumberOrTag, BlockId};
2use alloy_json_rpc::RpcObject;
3use alloy_primitives::{Address, Bytes, TxHash, B256};
4use alloy_rpc_types_trace::otterscan::{
5    BlockDetails, ContractCreator, InternalOperation, OtsBlockTransactions, TraceEntry,
6    TransactionsWithReceipts,
7};
8use jsonrpsee::{core::RpcResult, proc_macros::rpc};
9
10/// Otterscan RPC interface.
11///
12/// Reth implements a subset of the API. In particular, address history search is unimplemented
13/// even though `getApiLevel` returns 8. Historical queries require the relevant state and history.
14#[cfg_attr(not(feature = "client"), rpc(server, namespace = "ots"))]
15#[cfg_attr(feature = "client", rpc(server, client, namespace = "ots"))]
16pub trait Otterscan<T: RpcObject, H: RpcObject> {
17    /// Get the block header by block number, required by otterscan.
18    /// Otterscan currently requires this endpoint, used as:
19    ///
20    /// 1. check if the node is Erigon or not
21    /// 2. get block header instead of the full block
22    ///
23    /// Ref: <https://github.com/otterscan/otterscan/blob/071d8c55202badf01804f6f8d53ef9311d4a9e47/src/useProvider.ts#L71>
24    #[method(name = "getHeaderByNumber", aliases = ["erigon_getHeaderByNumber"])]
25    async fn get_header_by_number(
26        &self,
27        block_number: LenientBlockNumberOrTag,
28    ) -> RpcResult<Option<H>>;
29
30    /// Check if a certain address contains a deployed code.
31    #[method(name = "hasCode")]
32    async fn has_code(&self, address: Address, block_id: Option<BlockId>) -> RpcResult<bool>;
33
34    /// Returns API level 8 for frontend compatibility, not a guarantee of complete support.
35    /// In particular, both address history search methods remain unimplemented.
36    #[method(name = "getApiLevel")]
37    async fn get_api_level(&self) -> RpcResult<u64>;
38
39    /// Return the internal ETH transfers inside a transaction.
40    #[method(name = "getInternalOperations")]
41    async fn get_internal_operations(&self, tx_hash: TxHash) -> RpcResult<Vec<InternalOperation>>;
42
43    /// Given a transaction hash, returns its raw revert reason.
44    /// Known transactions without revert data return empty bytes; unknown transactions return
45    /// `None`.
46    #[method(name = "getTransactionError")]
47    async fn get_transaction_error(&self, tx_hash: TxHash) -> RpcResult<Option<Bytes>>;
48
49    /// Extract all variations of calls, contract creation and self-destructs and returns a call
50    /// tree.
51    #[method(name = "traceTransaction")]
52    async fn trace_transaction(&self, tx_hash: TxHash) -> RpcResult<Option<Vec<TraceEntry>>>;
53
54    /// Tailor-made and expanded version of `eth_getBlockByNumber` for block details page in
55    /// Otterscan.
56    #[method(name = "getBlockDetails")]
57    async fn get_block_details(
58        &self,
59        block_number: LenientBlockNumberOrTag,
60    ) -> RpcResult<BlockDetails<H>>;
61
62    /// Tailor-made and expanded version of `eth_getBlockByHash` for block details page in
63    /// Otterscan.
64    #[method(name = "getBlockDetailsByHash")]
65    async fn get_block_details_by_hash(&self, block_hash: B256) -> RpcResult<BlockDetails<H>>;
66
67    /// Get paginated transactions for a certain block. Also remove some verbose fields like logs.
68    /// Page zero selects the block's last transactions; each page retains ascending block order.
69    #[method(name = "getBlockTransactions")]
70    async fn get_block_transactions(
71        &self,
72        block_number: LenientBlockNumberOrTag,
73        page_number: usize,
74        page_size: usize,
75    ) -> RpcResult<OtsBlockTransactions<T, H>>;
76
77    /// Gets paginated inbound/outbound transaction calls for a certain address.
78    ///
79    /// Unimplemented: returns JSON-RPC error -32603 with message "unimplemented".
80    /// See <https://github.com/paradigmxyz/reth/issues/13499>.
81    #[method(name = "searchTransactionsBefore")]
82    async fn search_transactions_before(
83        &self,
84        address: Address,
85        block_number: LenientBlockNumberOrTag,
86        page_size: usize,
87    ) -> RpcResult<TransactionsWithReceipts>;
88
89    /// Gets paginated inbound/outbound transaction calls for a certain address.
90    ///
91    /// Unimplemented: returns JSON-RPC error -32603 with message "unimplemented".
92    /// See <https://github.com/paradigmxyz/reth/issues/13499>.
93    #[method(name = "searchTransactionsAfter")]
94    async fn search_transactions_after(
95        &self,
96        address: Address,
97        block_number: LenientBlockNumberOrTag,
98        page_size: usize,
99    ) -> RpcResult<TransactionsWithReceipts>;
100
101    /// Gets the transaction hash for a certain sender address, given its nonce.
102    #[method(name = "getTransactionBySenderAndNonce")]
103    async fn get_transaction_by_sender_and_nonce(
104        &self,
105        sender: Address,
106        nonce: u64,
107    ) -> RpcResult<Option<TxHash>>;
108
109    /// Gets the transaction hash and the address who created a contract.
110    /// Requires historical state. Code-presence binary search is unreliable for destroyed and
111    /// redeployed contracts, and cannot identify genesis allocations or EIP-7702 delegations.
112    #[method(name = "getContractCreator")]
113    async fn get_contract_creator(&self, address: Address) -> RpcResult<Option<ContractCreator>>;
114}