77 * efficient access to transaction details, internal operations,
88 * and paginated transaction history.
99 *
10- * @_section : api/providers/otterscan :Otterscan Provider [about-otterscanProvider ]
10+ * @_subsection : api/providers/thirdparty :Otterscan [providers-otterscan ]
1111 */
1212
1313import { Interface } from "../abi/index.js" ;
@@ -17,8 +17,84 @@ import { JsonRpcProvider } from "./provider-jsonrpc.js";
1717import type { JsonRpcApiProviderOptions } from "./provider-jsonrpc.js" ;
1818import type { Networkish } from "./network.js" ;
1919import type { FetchRequest } from "../utils/index.js" ;
20+ import type { BlockParams } from "./formatting.js" ;
21+ import type { Fragment } from "../abi/index.js" ;
22+ import type { AccessList } from "../transaction/index.js" ;
23+ import type { HexString } from "../utils/data.js" ;
2024
21- export type Hex = `0x${string } `;
25+ // Log entry in transaction receipts - matches ethers LogParams but with hex strings from raw RPC
26+ export interface OtsLog {
27+ address : string ;
28+ topics : ReadonlyArray < string > ;
29+ data : string ;
30+ blockNumber : string ; // hex string from RPC, not parsed number
31+ transactionHash : string ;
32+ transactionIndex : string ; // hex string from RPC, not parsed number
33+ blockHash : string ;
34+ logIndex : string ; // hex string from RPC, not parsed number
35+ removed : boolean ;
36+ }
37+
38+ // Otterscan transaction type - raw RPC response with hex-encoded values
39+ export interface OtsTransaction {
40+ // Core transaction fields (always present)
41+ blockHash : string ;
42+ blockNumber : string ; // hex-encoded number
43+ from : string ;
44+ gas : string ; // hex-encoded gasLimit
45+ gasPrice : string ; // hex-encoded bigint
46+ hash : string ;
47+ input : string ; // transaction data
48+ nonce : string ; // hex-encoded number
49+ to : string ;
50+ transactionIndex : string ; // hex-encoded number
51+ value : string ; // hex-encoded bigint
52+ type : string ; // hex-encoded transaction type (0x0, 0x1, 0x2, etc.)
53+ chainId : string ; // hex-encoded bigint
54+
55+ // Signature components (always present)
56+ v : string ; // hex-encoded
57+ r : string ; // hex signature component
58+ s : string ; // hex signature component
59+
60+ // EIP-1559 fields (present in type 0x2 transactions)
61+ maxPriorityFeePerGas ?: string ; // hex-encoded bigint
62+ maxFeePerGas ?: string ; // hex-encoded bigint
63+ yParity ?: string ; // hex-encoded (0x0 or 0x1)
64+
65+ // EIP-2930/EIP-1559 field
66+ accessList ?: AccessList ;
67+ }
68+
69+ // Otterscan receipt type - raw RPC response format
70+ export interface OtsReceipt {
71+ // Core receipt fields
72+ blockHash : string ;
73+ blockNumber : string ; // hex-encoded number
74+ contractAddress : string | null ; // null for non-contract-creating txs
75+ cumulativeGasUsed : string ; // hex-encoded bigint
76+ effectiveGasPrice : string ; // hex-encoded bigint
77+ from : string ;
78+ gasUsed : string ; // hex-encoded bigint
79+ logs : OtsLog [ ] ;
80+ logsBloom : string ; // hex-encoded bloom filter
81+ status : string ; // hex-encoded: "0x1" success, "0x0" failure
82+ to : string ;
83+ transactionHash : string ;
84+ transactionIndex : string ; // hex-encoded number
85+ type : string ; // hex-encoded transaction type
86+
87+ // Otterscan-specific extension
88+ timestamp : number ; // Unix timestamp as actual number (not hex)
89+ }
90+
91+ // Otterscan search page result
92+ export interface OtsSearchResult {
93+ txs : OtsTransaction [ ] ;
94+ receipts : OtsReceipt [ ] ;
95+ firstPage : boolean ;
96+ lastPage : boolean ;
97+ }
2298
2399/**
24100 * Internal operation types returned by ots_getInternalOperations
@@ -31,45 +107,45 @@ export interface OtsInternalOp {
31107 /** Target address (null for self-destruct operations) */
32108 to : string | null ;
33109 /** Value transferred (hex quantity) */
34- value : Hex ;
110+ value : HexString ;
35111}
36112
37113/**
38114 * Block details with issuance and fee information
39115 */
40116export interface OtsBlockDetails {
41117 /** Raw block data */
42- block : any ;
118+ block : BlockParams ;
43119 /** Number of transactions in the block */
44120 transactionCount : number ;
45121 /** Block reward information (optional) */
46122 issuance ?: {
47- blockReward : Hex ;
48- uncleReward : Hex ;
49- issuance : Hex ;
123+ blockReward : HexString ;
124+ uncleReward : HexString ;
125+ issuance : HexString ;
50126 } ;
51127 /** Total fees collected in the block */
52- totalFees ?: Hex ;
128+ totalFees ?: HexString ;
53129}
54130
55131/**
56132 * Paginated block transactions with receipts
57133 */
58134export interface OtsBlockTxPage {
59135 /** Transaction bodies with input truncated to 4-byte selector */
60- transactions : Array < any > ;
136+ transactions : Array < OtsTransaction > ;
61137 /** Receipts with logs and bloom set to null */
62- receipts : Array < any > ;
138+ receipts : Array < OtsReceipt > ;
63139}
64140
65141/**
66142 * Paginated search results for address transaction history
67143 */
68144export interface OtsSearchPage {
69145 /** Array of transactions */
70- txs : Array < any > ;
146+ txs : OtsTransaction [ ] ;
71147 /** Array of corresponding receipts */
72- receipts : Array < any > ;
148+ receipts : OtsReceipt [ ] ;
73149 /** Whether this is the first page */
74150 firstPage : boolean ;
75151 /** Whether this is the last page */
@@ -89,15 +165,14 @@ export interface OtsContractCreator {
89165/**
90166 * The OtterscanProvider extends JsonRpcProvider to add support for
91167 * Erigon's OTS (Otterscan) namespace methods.
92- *
168+ *
93169 * These methods provide efficient access to blockchain data optimized
94170 * for explorer applications.
95- *
171+ *
96172 * **Note**: OTS methods are only available on Erigon nodes with the
97173 * ots namespace enabled via --http.api "eth,erigon,trace,ots"
98174 */
99175export class OtterscanProvider extends JsonRpcProvider {
100-
101176 constructor ( url ?: string | FetchRequest , network ?: Networkish , options ?: JsonRpcApiProviderOptions ) {
102177 super ( url , network , options ) ;
103178 }
@@ -135,7 +210,7 @@ export class OtterscanProvider extends JsonRpcProvider {
135210 * @param txHash - Transaction hash
136211 * @returns Raw revert data as hex string, "0x" if no error
137212 */
138- async getTransactionErrorData ( txHash : string ) : Promise < Hex > {
213+ async getTransactionErrorData ( txHash : string ) : Promise < HexString > {
139214 return await this . send ( "ots_getTransactionError" , [ txHash ] ) ;
140215 }
141216
@@ -145,7 +220,7 @@ export class OtterscanProvider extends JsonRpcProvider {
145220 * @param customAbi - Optional custom ABI for decoding custom errors
146221 * @returns Decoded error message or null if no error
147222 */
148- async getTransactionRevertReason ( txHash : string , customAbi ?: any [ ] ) : Promise < string | null > {
223+ async getTransactionRevertReason ( txHash : string , customAbi ?: Fragment [ ] ) : Promise < string | null > {
149224 const data : string = await this . getTransactionErrorData ( txHash ) ;
150225 if ( data === "0x" ) return null ;
151226
@@ -167,13 +242,15 @@ export class OtterscanProvider extends JsonRpcProvider {
167242 const iface = new Interface ( customAbi ) ;
168243 const parsed = iface . parseError ( data ) ;
169244 if ( parsed ) {
170- return `${ parsed . name } (${ parsed . args . map ( ( a ) => {
171- try {
172- return JSON . stringify ( a ) ;
173- } catch {
174- return String ( a ) ;
175- }
176- } ) . join ( "," ) } )`;
245+ return `${ parsed . name } (${ parsed . args
246+ . map ( a => {
247+ try {
248+ return JSON . stringify ( a ) ;
249+ } catch {
250+ return String ( a ) ;
251+ }
252+ } )
253+ . join ( "," ) } )`;
177254 }
178255 } catch {
179256 // Fall through to selector display
@@ -220,7 +297,7 @@ export class OtterscanProvider extends JsonRpcProvider {
220297 * @param pageSize - Maximum results to return
221298 * @returns Page of transactions
222299 */
223- async searchTransactionsBefore ( address : string , blockNumber : number , pageSize : number ) : Promise < OtsSearchPage > {
300+ async searchTransactionsBefore ( address : string , blockNumber : number , pageSize : number ) : Promise < OtsSearchResult > {
224301 return await this . send ( "ots_searchTransactionsBefore" , [ address , blockNumber , pageSize ] ) ;
225302 }
226303
@@ -231,7 +308,7 @@ export class OtterscanProvider extends JsonRpcProvider {
231308 * @param pageSize - Maximum results to return
232309 * @returns Page of transactions
233310 */
234- async searchTransactionsAfter ( address : string , blockNumber : number , pageSize : number ) : Promise < OtsSearchPage > {
311+ async searchTransactionsAfter ( address : string , blockNumber : number , pageSize : number ) : Promise < OtsSearchResult > {
235312 return await this . send ( "ots_searchTransactionsAfter" , [ address , blockNumber , pageSize ] ) ;
236313 }
237314
@@ -265,8 +342,9 @@ export class OtterscanProvider extends JsonRpcProvider {
265342 if ( level < minLevel ) {
266343 throw new Error ( `ots_getApiLevel ${ level } < required ${ minLevel } ` ) ;
267344 }
268- } catch ( error : any ) {
269- const err = new Error ( `Erigon OTS namespace unavailable or too old: ${ error ?. message ?? error } ` ) ;
345+ } catch ( error : unknown ) {
346+ const errorMsg = error instanceof Error ? error . message : String ( error ) ;
347+ const err = new Error ( `Erigon OTS namespace unavailable or too old: ${ errorMsg } ` ) ;
270348 ( err as any ) . code = "OTS_UNAVAILABLE" ;
271349 throw err ;
272350 }
@@ -285,13 +363,14 @@ export class OtterscanProvider extends JsonRpcProvider {
285363 direction : "before" | "after" ,
286364 startBlock : number ,
287365 pageSize : number = 500
288- ) : AsyncGenerator < { tx : any ; receipt : any } , void , unknown > {
366+ ) : AsyncGenerator < { tx : OtsTransaction ; receipt : OtsReceipt } , void , unknown > {
289367 let currentBlock = startBlock ;
290368
291369 while ( true ) {
292- const page = direction === "before"
293- ? await this . searchTransactionsBefore ( address , currentBlock , pageSize )
294- : await this . searchTransactionsAfter ( address , currentBlock , pageSize ) ;
370+ const page =
371+ direction === "before"
372+ ? await this . searchTransactionsBefore ( address , currentBlock , pageSize )
373+ : await this . searchTransactionsAfter ( address , currentBlock , pageSize ) ;
295374
296375 // Yield each transaction with its receipt
297376 for ( let i = 0 ; i < page . txs . length ; i ++ ) {
@@ -309,13 +388,13 @@ export class OtterscanProvider extends JsonRpcProvider {
309388 if ( ! lastTx ) break ;
310389
311390 const nextBlock = Number ( lastTx . blockNumber ) ;
312-
391+
313392 // Prevent infinite loops from malformed API responses
314393 if ( nextBlock === currentBlock ) {
315394 throw new Error ( `Iterator stuck on block ${ currentBlock } . API returned same block number.` ) ;
316395 }
317-
396+
318397 currentBlock = nextBlock ;
319398 }
320399 }
321- }
400+ }
0 commit comments