ink_env::call

Function build_call

source
pub fn build_call<E>() -> CallBuilder<E, Unset<Call>, Unset<ExecutionInput<EmptyArgumentList>>, Unset<ReturnType<()>>>
where E: Environment,
Expand description

Returns a new CallBuilder to build up the parameters to a cross-contract call.

§Example

Note: The shown examples panic because there is currently no cross-calling support in the off-chain testing environment. However, this code should work fine in on-chain environments.

§Example 1: No Return Value

The below example shows calling of a message of another contract that does not return any value back to its caller. The called function:

  • has a selector equal to 0xDEADBEEF
  • is provided with 5000 units of gas for its execution
  • is provided with 10 units of transferred value for the contract instance
  • receives the following arguments in order 1. an i32 with value 42 2. a bool with value true 3. an array of 32 u8 with value 0x10

type AccountId = <DefaultEnvironment as Environment>::AccountId;
build_call::<DefaultEnvironment>()
    .call(H160::from([0x42; 20]))
    .ref_time_limit(5000)
    .transferred_value(ink::U256::from(10))
    .exec_input(
        ExecutionInput::new(Selector::new([0xDE, 0xAD, 0xBE, 0xEF]))
            .push_arg(42u8)
            .push_arg(true)
            .push_arg(&[0x10u8; 32]),
    )
    .returns::<()>()
    .invoke();

§Example 2: With Return Value

The below example shows calling of a message of another contract that does return a i32 value back to its caller. The called function:

  • has a selector equal to 0xDEADBEEF
  • is provided with 5000 units of gas for its execution
  • is provided with 10 units of transferred value for the contract instance
  • receives the following arguments in order 1. an i32 with value 42 2. a bool with value true 3. an array of 32 u8 with value 0x10
let my_return_value: i32 = build_call::<DefaultEnvironment>()
    .call_type(Call::new(ink::H160::from([0x42; 20])))
    .ref_time_limit(5000)
    .transferred_value(ink::U256::from(10))
    .exec_input(
        ExecutionInput::new(Selector::new([0xDE, 0xAD, 0xBE, 0xEF]))
            .push_arg(42u8)
            .push_arg(true)
            .push_arg(&[0x10u8; 32]),
    )
    .returns::<i32>()
    .invoke();

§Example 3: Delegate call

Note: The shown example panics because there is currently no delegate calling support in the off-chain testing environment. However, this code should work fine in on-chain environments.

use ink::H160;
let my_return_value: i32 = build_call::<DefaultEnvironment>()
    .delegate(H160::zero())
    .exec_input(
        ExecutionInput::new(Selector::new([0xDE, 0xAD, 0xBE, 0xEF]))
            .push_arg(42u8)
            .push_arg(true)
            .push_arg(&[0x10u8; 32])
    )
    .returns::<i32>()
    .invoke();

§Handling LangErrors

It is also important to note that there are certain types of errors which can happen during cross-contract calls which can be handled know as [LangError][ink_primitives::LangError].

If you want to handle these errors use the CallBuilder::try_invoke methods instead of the CallBuilder::invoke ones.

Note: The shown examples panic because there is currently no cross-calling support in the off-chain testing environment. However, this code should work fine in on-chain environments.

§Example: Handling a LangError


type AccountId = <DefaultEnvironment as Environment>::AccountId;
let call_result = build_call::<DefaultEnvironment>()
    .call(H160::from([0x42; 20]))
    .ref_time_limit(5000)
    .transferred_value(ink::U256::from(10))
    .try_invoke()
    .expect("Got an error from the Contract's pallet.");

match call_result {
    Ok(_) => unimplemented!(),
    Err(e @ ink_primitives::LangError::CouldNotReadInput) => unimplemented!(),
    Err(_) => unimplemented!(),
}