2

I want to build a delegator contract to an deployed callee contract without knowing the source code details of the callee contract.

Related part of my delegator contract is as below:

#[ink(message)]
        pub fn call_to_contracts(&self, callee_account: AccountId, msg: ink_prelude::string::String) -> ink_prelude::string::String{
            
            let my_return_value: ink_prelude::string::String =  ink_env::call::build_call::<ink_env::DefaultEnvironment>()
                .call_type(
                    ink_env::call::Call::new()
                        .callee(callee_account)
                        .gas_limit(0)
                        .transferred_value(0))
                .exec_input(
                    ink_env::call::ExecutionInput::new(ink_env::call::Selector::new([0xa9, 0x45, 0xce, 0xc7]))
                    .push_arg(msg.into_bytes())
                )
                .returns::<ink_prelude::string::String>()
                .fire()
                .unwrap();
            my_return_value
        }

Related part of my callee contract is as below:

#[derive(Debug, PartialEq, Eq, scale::Encode, scale::Decode)]
    #[cfg_attr(feature = "std", derive(::scale_info::TypeInfo))]
    pub struct MessageDetail{
        name: ink_prelude::string::String,
        age: u32,
        phones: ink_prelude::vec::Vec<ink_prelude::string::String>,
    }

/// test cross contract call
        #[ink(message)]
        pub fn encode_user_defined_struct(&self, msg: MessageDetail) -> ink_prelude::string::String{
            ink_prelude::format!("{:?}", msg)
        }

First, I use ContractUI to make a test. I have tried the following input of the parameter msg when calling call_to_contracts:

  • {{\"name\":\"nika\",\"age\":18,\"phones\":[\"hello\",\"nika\"]}}
  • {\"name\":\"nika\",\"age\":18,\"phones\":[\"hello\",\"nika\"]}
  • {"name":"nika","age":18,"phones":["hello","nika"]}

Besides, I have tried to replace the .push_arg(msg.into_bytes()) with .push_arg(msg).

But it's not working, I cannot see any error messages through ContractUI.

I'm sure if I defined the same MessageDetail in delegator contract, and change the parameter msg from String to MessageDetail, everything's OK.

But my purpose is to build a general delegator contract without knowing the source code details of the callee, is there any way I can try in ink!?

5
  • Have you checked out the delegator example? May 11, 2022 at 18:05
  • I think it's not suitable for my situation. I think the delegator example is suitable for 'static' scenarios. But anyway, I have solved the problem. Thank you all the same.
    – Shawn Z
    May 13, 2022 at 14:12
  • You can post an answer and accept it yourself it this case. May 13, 2022 at 21:31
  • Can you share the solution, I am stuck in same situation
    – nicky
    May 26, 2022 at 6:54
  • It's a long time to be back here~ OK, I will share my solution below~
    – Shawn Z
    May 29, 2022 at 3:57

1 Answer 1

0

The first thing is encoding the user-defined struct in off-chain node.js, it will be like this:

...
/// encode user-defined data with ink api.
/// the `{"name": "Nika", "age": 18, "phones": ["123", "456"]}, "someone", 666` is user-defined parameters, there're three here
const calleeEncode = calleeABI.findMessage('encode_user_multi_params').toU8a([{"name": "Nika", "age": 18, "phones": ["123", "456"]}, "someone", 666]);

// it cannot be used until now, we should make more encoding manually
let ecdStr = '0x';
for (let i = 1; i < calleeEncode.length; ++i){
  let stemp = calleeEncode[i].toString(16);
  if (stemp.length < 2){
    stemp = '0' + stemp;
  }
  ecdStr += stemp;
}

...
/// Next, we can call *delegator contract* to make a delegate call to any callee contract.
/// the `contract` is the *delegator contract* instance
/// the `callToContracts` is the proxy call method
/// `5CgMjHnZm7VAi8x9HrB4b8FXYytnUj1pqNUH92yUmY9A7g8C` is the callee contract address
/// `ecdStr` is the encoded parameters and related method selector of the user-defined *callee contract*
const { gasConsumed, result, output } = await contract.query['callToContracts'](sender.address, {value, gasLimit }, 
                                       "5CgMjHnZm7VAi8x9HrB4b8FXYytnUj1pqNUH92yUmY9A7g8C", ecdStr);

The second thing is the related delegator contract method

...
/// because in our case we have more than one parameters for callee, so we need a `Wrapper` manually:
 struct Wrapper {
        data: ink_prelude::vec::Vec::<u8>,
    }
    
    impl Wrapper {
        pub fn new(data: ink_prelude::vec::Vec::<u8>) -> Self {
            Self {
                data,
            }
        }
    }
    
    impl scale::Encode for Wrapper {
        #[inline]
        fn size_hint(&self) -> usize {
            scale::Encode::size_hint(&self.data)
        }
    
        #[inline]
        fn encode_to<O: scale::Output + ?Sized>(&self, output: &mut O) {
            output.write(&self.data);
        }
    }

...
/// this is the delegate call
fn call_to_contracts(& self, callee_account: AccountId, msg: ink_prelude::vec::Vec::<u8>) -> ink_prelude::string::String{
            let data: ink_prelude::vec::Vec::<u8> = msg.clone().drain(4..).collect();
            let wrapped_data = Wrapper::new(data);
            
            let my_return_value: ink_prelude::string::String =  ink_env::call::build_call::<ink_env::DefaultEnvironment>()
                .call_type(
                    ink_env::call::Call::new()
                        .callee(callee_account)
                        .gas_limit(0)
                        .transferred_value(0))
                .exec_input(
                    ink_env::call::ExecutionInput::new(ink_env::call::Selector::new([msg[0], msg[1], msg[2], msg[3]]))
                    .push_arg(wrapped_data)
                )
                .returns::<ink_prelude::string::String>()
                .fire()
                .unwrap();
            my_return_value
        }
...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.