Finschia / cosmwasm

Fast and reusable WebAssembly smart contract runtime(and library) for finschia-sdk.
Apache License 2.0
27 stars 14 forks source link

Reconsider how to specify callee contract #207

Closed loloicci closed 2 years ago

loloicci commented 2 years ago

Now, the callee contract is specified by storage value. Reconsider it and compare it with other ways, for example specifying by parameter or macro.

loloicci commented 2 years ago

Traditional Way

In the traditional way, the callee contract address is specified with storage value. The key of the address in storage is specified in the dynamic link macro.

// import
#[dynamic_link(contract_name = "callee_contract")]
extern "C" {
    fn pong(a: u64) -> u64;
}

// specify cellee contract + call
fn some_func(deps: DepsMut){
    // specify callee contract
    deps.storage.set(b"callee_contract", &to_vec("address1")?);

    // call "address1"'s pong
    let ret1 = pong(42);

    // change callee contract
    deps.storage.set(b"callee_contract", &to_vec("address2")?);

    // call "address2"'s pong
    let ret2 = pong(42);

    // change callee contract
    deps.storage.set(b"callee_contract", &to_vec("address1")?);

    // call "address1"'s pong using ret2
    let ret3 = pong(ret2);
}

In this way, which contract is called is dependent on a value in storage. So, the value must be renewed each time another contract is called. And, the same pong returns different values depending on storage status (sometimes it looks strange.)

In the example contract, the importing is https://github.com/line/cosmwasm/blob/4a4e15573f061a90788d955ad25664967c97d756/contracts/dynamic-caller-contract/src/contract.rs#L22-L30 and the specifying address is https://github.com/line/cosmwasm/blob/4a4e15573f061a90788d955ad25664967c97d756/contracts/dynamic-caller-contract/src/contract.rs#L41-L42. (But, it uses only one contract, so it may looks having few problems.)

Suggested Way

My suggestion is make the callee contract represented with a struct in following way:

use cosmwasm_std::{Addr, Contract};

#[derive(Contract)]
struct CalleeContract {
    pub address: Addr;
}

#[dynamic_link(CalleeContract)]
trait Callee: Contract {
    fn pong(&self, a: u64) -> u64;
}

// specify callee contract + call
fn some_func(){
    // specify callee contract
    let contract1 = Callee { address: Addr::unchecked("address1") };

    // specify another calle contract
    let contract2 = Callee { address: Addr::unchecked("address2") };

    // call "address1"'s pong
    let ret1 = contract1.pong(42);

    // call "address2"'s pong
    let ret2 = contract2.pong(42);

    // call "address1"'s pong using ret2
    let ret3 = contract1.pong(ret2);
}
loloicci commented 2 years ago

closed via #215