Low-level calls
With low-level calls, you can specify the parameters of your calls at runtime and make indirect calls through other contracts.
Your caller contract should call std::low_level_call::call_with_function_selector
, providing:
- target contract ID
- function selector encoded as
Bytes
- calldata encoded as
Bytes
- whether the calldata contains only a single value argument (e.g. a
u64
) std::low_level_call::CallParams
fn call_low_level_call(
target: ContractId,
function_selector: Bytes,
calldata: Bytes,
single_value_type_arg: bool,
) {
let call_params = CallParams {
coins: 0,
asset_id: BASE_ASSET_ID,
gas: 10_000,
};
call_with_function_selector(
target,
function_selector,
calldata,
single_value_type_arg,
call_params,
);
}
On the SDK side, you can construct an encoded function selector using the fuels::core::fn_selector!
macro, and encoded calldata using the fuels::core::calldata!
macro.
E.g. to call the following function on the target contract:
#[storage(write)]
fn set_value_multiple_complex(a: MyStruct, b: str[4]);
you would construct the function selector and the calldata as such, and provide them to the caller contract (like the one above):
let function_selector =
fn_selector!(set_value_multiple_complex(MyStruct, SizedAsciiString::<4>));
let call_data = calldata!(
MyStruct {
a: true,
b: [1, 2, 3],
},
SizedAsciiString::<4>::try_from("fuel")?
)?;
caller_contract_instance
.methods()
.call_low_level_call(
target_contract_instance.id(),
Bytes(function_selector),
Bytes(call_data),
false,
)
.estimate_tx_dependencies(None)
.await?
.call()
.await?;