Skip to content

Implement useScaffoldMultiReadContract Hook #575

@metalboyrick

Description

@metalboyrick

Why We Need This

Contract reads typically require one RPC call per operation. When you need to fetch multiple data points or arrays of objects for example when displaying a dashboard, creating individual hooks for each call becomes inefficient and cumbersome. This multiRead hook lets you make type-safe calls to multiple contracts with different entry points and calldata, then automatically parse results based on your calls - all leveraging the ABIs in deployedContracts.

What to Build

  • Create a hook that safely reads from multiple contracts simultaneously using the Multicall contract below
  • Follow the same patterns as useScaffoldMultiWrite() for consistency
  • Ensure full type safety with autocompletion (note: the contract returns only an array of felts, so parsing must happen within the hook, similar to starknet-react's single hook approach)
  • The hook should match the type safety and autocomplete experience of the existing useScaffoldReadContract
  • Test implementation using the bulletproof contracts [here](https://github.com/Scaffold-Stark/scaffold-stark-2/tree/v3-bulletproof-contracts)
  • make this hold result of useScaffoldMultiReadContract(calls: [call1, call2]) == [ result of useScaffoldReadContract(call1), result of useScaffoldReadContract(call2) ]
Sample Multicall Contract [feel free to change the source code like function name the return type from Array to Vec or Span, i.e.]
 use starknet::ContractAddress;
#[starknet::interface]
pub trait IMulticall<T> {
    fn call_contracts(self: @T, contracts: Span<ContractAddress>, entry_point_selectors: Span<felt252>, calldata: Span<Span<felt252>>) -> Array<Span<felt252>>;
}

#[starknet::contract]
pub mod Multicall {
    use starknet::ContractAddress;
    use super::IMulticall;
    use core::array::ArrayTrait;
    use starknet::syscalls::call_contract_syscall;

    #[storage]
    struct Storage {
    }

    #[constructor]
    fn constructor(ref self: ContractState) {}


    #[abi(embed_v0)]
    impl MulticallImpl of IMulticall<ContractState> {
        fn call_contracts(self: @ContractState, contracts: Span<ContractAddress>, entry_point_selectors: Span<felt252>, calldata: Span<Span<felt252>>) -> Array<Span<felt252>> {

            let mut results: Array<Span<felt252>> = ArrayTrait::new();
            for i in 0..contracts.len() {
                let contract = *contracts[i];
                let entry_point_selector = *entry_point_selectors[i];
                let calldata = *calldata[i];
                let result = call_contract_syscall(contract, entry_point_selector, calldata);
                results.append(result.unwrap());
            }
            results
        }
    }
    
}

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions