1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use crate::pb::eth::rpc::{RpcCall, RpcCalls, RpcResponse, RpcResponses};
use crate::Function;
use substreams::proto;

pub trait RPCDecodable<R> {
    fn output(data: &[u8]) -> Result<R, String>;
}

pub struct RpcBatch {
    store: RpcCalls,
}

pub fn batch() -> RpcBatch {
    RpcBatch {
        store: RpcCalls {
            ..Default::default()
        },
    }
}

impl RpcBatch {
    pub fn new() -> RpcBatch {
        RpcBatch {
            store: RpcCalls { calls: vec![] },
        }
    }

    pub fn add<F: Function>(mut self, call: F, address: Vec<u8>) -> Self {
        self.store.calls.push(RpcCall {
            to_addr: address,
            data: call.encode(),
        });
        self
    }

    pub fn execute(self) -> Result<RpcResponses, String> {
        Ok(eth_call(&self.store))
    }

    pub fn decode<R, T: RPCDecodable<R> + Function>(response: &RpcResponse) -> Option<R> {
        if response.failed {
            return None;
        }

        match T::output(response.raw.as_ref()) {
            Ok(data) => Some(data),
            Err(err) => {
                substreams::log::info!(
                    "Call output for function `{}` failed to decode with error: {}",
                    T::NAME,
                    err
                );
                None
            }
        }
    }
}

#[cfg_attr(not(target_arch = "wasm32"), allow(unused_variables))]
fn eth_call_internal(input: Vec<u8>) -> Vec<u8> {
    #[cfg(target_arch = "wasm32")]
    unsafe {
        use substreams::memory;

        let rpc_response_ptr = memory::alloc(8);
        crate::externs::rpc::eth_call(input.as_ptr(), input.len() as u32, rpc_response_ptr);
        return memory::get_output_data(rpc_response_ptr);
    }

    #[cfg(not(target_arch = "wasm32"))]
    unimplemented!("this method is not implemented outside of 'wasm32' target compilation")
}

pub fn eth_call(input: &RpcCalls) -> RpcResponses {
    let raw_resp: Vec<u8> = eth_call_internal(proto::encode(input).unwrap());
    let resp: RpcResponses = proto::decode(&raw_resp).unwrap();

    return resp;
}