An Arbitrum Stylus version implementation of Solidity Multi Call contract that aggregates multiple queries using a for loop and RawCall.
Example implementation of a Multi Call contract written in Rust: Here is the interface for TimeLock.
1/**
2 * This file was automatically generated by Stylus and represents a Rust program.
3 * For more information, please see [The Stylus SDK](https://github.com/OffchainLabs/stylus-sdk-rs).
4 */
5
6// SPDX-License-Identifier: MIT-OR-APACHE-2.0
7pragma solidity ^0.8.23;
8
9interface IMultiCall {
10 function multicall(address[] memory addresses, bytes[] memory data) external view returns (bytes[] memory);
11
12 error ArraySizeNotMatch();
13
14 error CallFailed(uint256);
15}
1/**
2 * This file was automatically generated by Stylus and represents a Rust program.
3 * For more information, please see [The Stylus SDK](https://github.com/OffchainLabs/stylus-sdk-rs).
4 */
5
6// SPDX-License-Identifier: MIT-OR-APACHE-2.0
7pragma solidity ^0.8.23;
8
9interface IMultiCall {
10 function multicall(address[] memory addresses, bytes[] memory data) external view returns (bytes[] memory);
11
12 error ArraySizeNotMatch();
13
14 error CallFailed(uint256);
15}
1#![cfg_attr(not(feature = "export-abi"), no_main)]
2extern crate alloc;
3
4#[global_allocator]
5static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT;
6
7use alloy_primitives::U256;
8use alloy_sol_types::sol;
9use stylus_sdk::{abi::Bytes, alloy_primitives::Address, call::RawCall, prelude::*};
10
11#[solidity_storage]
12#[entrypoint]
13pub struct MultiCall;
14
15// Declare events and Solidity error types
16sol! {
17 error ArraySizeNotMatch();
18 error CallFailed(uint256 call_index);
19}
20
21#[derive(SolidityError)]
22pub enum MultiCallErrors {
23 ArraySizeNotMatch(ArraySizeNotMatch),
24 CallFailed(CallFailed),
25}
26
27#[external]
28impl MultiCall {
29 pub fn multicall(
30 &self,
31 addresses: Vec<Address>,
32 data: Vec<Bytes>,
33 ) -> Result<Vec<Bytes>, MultiCallErrors> {
34 let addr_len = addresses.len();
35 let data_len = data.len();
36 let mut results: Vec<Bytes> = Vec::new();
37 if addr_len != data_len {
38 return Err(MultiCallErrors::ArraySizeNotMatch(ArraySizeNotMatch {}));
39 }
40 for i in 0..addr_len {
41 let result = RawCall::new().call(addresses[i], data[i].to_vec().as_slice())
42 .map_err(|_| MultiCallErrors::CallFailed(CallFailed { call_index: U256::from(i) }))?;
43 results.push(result.into());
44}
45 Ok(results)
46 }
47}
1#![cfg_attr(not(feature = "export-abi"), no_main)]
2extern crate alloc;
3
4#[global_allocator]
5static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT;
6
7use alloy_primitives::U256;
8use alloy_sol_types::sol;
9use stylus_sdk::{abi::Bytes, alloy_primitives::Address, call::RawCall, prelude::*};
10
11#[solidity_storage]
12#[entrypoint]
13pub struct MultiCall;
14
15// Declare events and Solidity error types
16sol! {
17 error ArraySizeNotMatch();
18 error CallFailed(uint256 call_index);
19}
20
21#[derive(SolidityError)]
22pub enum MultiCallErrors {
23 ArraySizeNotMatch(ArraySizeNotMatch),
24 CallFailed(CallFailed),
25}
26
27#[external]
28impl MultiCall {
29 pub fn multicall(
30 &self,
31 addresses: Vec<Address>,
32 data: Vec<Bytes>,
33 ) -> Result<Vec<Bytes>, MultiCallErrors> {
34 let addr_len = addresses.len();
35 let data_len = data.len();
36 let mut results: Vec<Bytes> = Vec::new();
37 if addr_len != data_len {
38 return Err(MultiCallErrors::ArraySizeNotMatch(ArraySizeNotMatch {}));
39 }
40 for i in 0..addr_len {
41 let result = RawCall::new().call(addresses[i], data[i].to_vec().as_slice())
42 .map_err(|_| MultiCallErrors::CallFailed(CallFailed { call_index: U256::from(i) }))?;
43 results.push(result.into());
44}
45 Ok(results)
46 }
47}
1[package]
2name = "stylus-multi-call-contract"
3version = "0.1.5"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6keywords = ["arbitrum", "ethereum", "stylus", "alloy"]
7description = "Stylus multi call example"
8
9[dependencies]
10alloy-primitives = "0.3.1"
11alloy-sol-types = "0.3.1"
12mini-alloc = "0.4.2"
13stylus-sdk = "0.5.0"
14hex = "0.4.3"
15
16[dev-dependencies]
17tokio = { version = "1.12.0", features = ["full"] }
18ethers = "2.0"
19eyre = "0.6.8"
20
21[features]
22export-abi = ["stylus-sdk/export-abi"]
23
24[[bin]]
25name = "stylus-multi-call"
26path = "src/main.rs"
27
28[lib]
29crate-type = ["lib", "cdylib"]
30
31[profile.release]
32codegen-units = 1
33strip = true
34lto = true
35panic = "abort"
36opt-level = "s"
1[package]
2name = "stylus-multi-call-contract"
3version = "0.1.5"
4edition = "2021"
5license = "MIT OR Apache-2.0"
6keywords = ["arbitrum", "ethereum", "stylus", "alloy"]
7description = "Stylus multi call example"
8
9[dependencies]
10alloy-primitives = "0.3.1"
11alloy-sol-types = "0.3.1"
12mini-alloc = "0.4.2"
13stylus-sdk = "0.5.0"
14hex = "0.4.3"
15
16[dev-dependencies]
17tokio = { version = "1.12.0", features = ["full"] }
18ethers = "2.0"
19eyre = "0.6.8"
20
21[features]
22export-abi = ["stylus-sdk/export-abi"]
23
24[[bin]]
25name = "stylus-multi-call"
26path = "src/main.rs"
27
28[lib]
29crate-type = ["lib", "cdylib"]
30
31[profile.release]
32codegen-units = 1
33strip = true
34lto = true
35panic = "abort"
36opt-level = "s"