11use std:: { sync:: Arc , time:: Instant } ;
22
3+ use async_trait:: async_trait;
4+
35use crate :: adapter:: EthereumRpcError ;
46use crate :: {
57 capabilities:: NodeCapabilities , network:: EthereumNetworkAdapters , Chain , ContractCallError ,
@@ -9,7 +11,7 @@ use anyhow::{anyhow, Context, Error};
911use blockchain:: HostFn ;
1012use graph:: abi;
1113use graph:: abi:: DynSolValueExt ;
12- use graph:: blockchain:: ChainIdentifier ;
14+ use graph:: blockchain:: { ChainIdentifier , RawEthCall } ;
1315use graph:: components:: subgraph:: HostMetrics ;
1416use graph:: data:: store:: ethereum:: call;
1517use graph:: data:: store:: scalar:: BigInt ;
@@ -18,7 +20,7 @@ use graph::data_source;
1820use graph:: data_source:: common:: { ContractCall , MappingABI } ;
1921use graph:: runtime:: gas:: Gas ;
2022use graph:: runtime:: { AscIndexId , IndexForAscTypeId } ;
21- use graph:: slog:: debug;
23+ use graph:: slog:: { debug, o , Discard } ;
2224use graph:: {
2325 blockchain:: { self , BlockPtr , HostFnCtx } ,
2426 cheap_clone:: CheapClone ,
@@ -185,6 +187,101 @@ impl blockchain::RuntimeAdapter<Chain> for RuntimeAdapter {
185187
186188 Ok ( host_fns)
187189 }
190+
191+ fn raw_eth_call ( & self ) -> Option < Arc < dyn RawEthCall > > {
192+ Some ( Arc :: new ( EthereumRawEthCall {
193+ eth_adapters : self . eth_adapters . cheap_clone ( ) ,
194+ call_cache : self . call_cache . cheap_clone ( ) ,
195+ eth_call_gas : eth_call_gas ( & self . chain_identifier ) ,
196+ } ) )
197+ }
198+ }
199+
200+ /// Implementation of RawEthCall for Ethereum chains.
201+ /// Used by Rust ABI subgraphs for making raw eth_call without ABI encoding.
202+ pub struct EthereumRawEthCall {
203+ eth_adapters : Arc < EthereumNetworkAdapters > ,
204+ call_cache : Arc < dyn EthereumCallCache > ,
205+ eth_call_gas : Option < u32 > ,
206+ }
207+
208+ #[ async_trait]
209+ impl RawEthCall for EthereumRawEthCall {
210+ async fn call (
211+ & self ,
212+ address : [ u8 ; 20 ] ,
213+ calldata : & [ u8 ] ,
214+ block_ptr : & BlockPtr ,
215+ gas : Option < u32 > ,
216+ ) -> Result < Option < Vec < u8 > > , HostExportError > {
217+ // Get an adapter suitable for calls (non-archive is fine)
218+ let eth_adapter = self
219+ . eth_adapters
220+ . call_or_cheapest ( Some ( & NodeCapabilities {
221+ archive : false ,
222+ traces : false ,
223+ } ) )
224+ . map_err ( |e| HostExportError :: Unknown ( e. into ( ) ) ) ?;
225+
226+ // Create a raw call request
227+ let req = call:: Request :: new ( Address :: from ( address) , calldata. to_vec ( ) , 0 ) ;
228+
229+ // Check cache first
230+ let ( cached, _missing) = self
231+ . call_cache
232+ . get_calls ( & [ req. cheap_clone ( ) ] , block_ptr. cheap_clone ( ) )
233+ . await
234+ . unwrap_or_else ( |_| ( Vec :: new ( ) , vec ! [ req. cheap_clone( ) ] ) ) ;
235+
236+ if let Some ( resp) = cached. into_iter ( ) . next ( ) {
237+ return match resp. retval {
238+ call:: Retval :: Value ( bytes) => Ok ( Some ( bytes. to_vec ( ) ) ) ,
239+ call:: Retval :: Null => Ok ( None ) ,
240+ } ;
241+ }
242+
243+ // Make the actual call
244+ let result = eth_adapter
245+ . raw_call (
246+ req. cheap_clone ( ) ,
247+ block_ptr. cheap_clone ( ) ,
248+ gas. or ( self . eth_call_gas ) ,
249+ )
250+ . await ;
251+
252+ match result {
253+ Ok ( retval) => {
254+ // Cache the result
255+ let cache = self . call_cache . cheap_clone ( ) ;
256+ let _ = cache
257+ . set_call (
258+ & Logger :: root ( Discard , o ! ( ) ) ,
259+ req,
260+ block_ptr. cheap_clone ( ) ,
261+ retval. clone ( ) ,
262+ )
263+ . await ;
264+
265+ match retval {
266+ call:: Retval :: Value ( bytes) => Ok ( Some ( bytes. to_vec ( ) ) ) ,
267+ call:: Retval :: Null => Ok ( None ) ,
268+ }
269+ }
270+ Err ( ContractCallError :: AlloyError ( e) ) => {
271+ Err ( HostExportError :: PossibleReorg ( anyhow:: anyhow!(
272+ "eth_call RPC error: {}" ,
273+ e
274+ ) ) )
275+ }
276+ Err ( ContractCallError :: Timeout ) => Err ( HostExportError :: PossibleReorg ( anyhow:: anyhow!(
277+ "eth_call timed out"
278+ ) ) ) ,
279+ Err ( e) => Err ( HostExportError :: Unknown ( anyhow:: anyhow!(
280+ "eth_call failed: {}" ,
281+ e
282+ ) ) ) ,
283+ }
284+ }
188285}
189286
190287/// function ethereum.call(call: SmartContractCall): Array<Token> | null
0 commit comments