Contract Calls
Contract calls let you invoke view (read-only) functions on any contract during indexing. They require a running Ethereum node — they are not available in native cargo test without mocking.
Making a Call
#![allow(unused)] fn main() { use graphite::ethereum::{self, EthereumValue}; use graphite::call::ContractCall; #[handler] pub fn handle_transfer(event: &ERC20TransferEvent, ctx: &graphite::EventContext) { // Call balanceOf(address) on the token contract let result = ContractCall::new(ctx.address, "balanceOf(address)") .arg(EthereumValue::Address(event.to)) .call(); if let Some(values) = result { let balance = values[0].clone(); // EthereumValue::Uint(...) // use balance... } } }
ContractCall API
#![allow(unused)] fn main() { use graphite::call::ContractCall; use graphite::ethereum::EthereumValue; let result: Option<Vec<EthereumValue>> = ContractCall::new( contract_address, // [u8; 20] "functionName(type1,type2)" // function signature ) .arg(EthereumValue::Address(addr)) .arg(EthereumValue::Uint(amount_bytes)) .call(); }
call() returns None if the call reverts or the function is not found. It returns Some(Vec<EthereumValue>) with the decoded return values on success.
ABI Encoding and Decoding
For manual encoding:
#![allow(unused)] fn main() { use graphite::ethereum::{self, EthereumValue}; // Encode a value to ABI bytes let encoded: Vec<u8> = ethereum::encode(&EthereumValue::Uint(value_bytes))?; // Decode ABI bytes to a value let value: EthereumValue = ethereum::decode("uint256", &encoded)?; }
Mocking Contract Calls in Tests
In tests, use mock::set_call_result to provide a return value for a call:
#![allow(unused)] fn main() { use graphite::mock; use graphite::ethereum::EthereumValue; mock::set_call_result( contract_address, "balanceOf(address)", Some(alloc::vec![EthereumValue::Uint(alloc::vec![200, 0, 0, 0])]), ); handle_transfer_impl(&event, &graphite::EventContext::default()); }
Pass None to simulate a reverted call.
Notes
- Contract calls are only available when graph-node has an Ethereum node configured. Not all networks support them.
- Calls are expensive — they require an archive node for historical state. Use them sparingly.
- Each call is synchronous and blocks the handler until the result arrives.