Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error When Calling Contract Functions Using MultiContractCallHandler #1427

Open
chlenc opened this issue Jun 14, 2024 · 1 comment
Open

Error When Calling Contract Functions Using MultiContractCallHandler #1427

chlenc opened this issue Jun 14, 2024 · 1 comment

Comments

@chlenc
Copy link

chlenc commented Jun 14, 2024

Issue: Error When Calling Contract Functions Using MultiContractCallHandler

Description

When invoking contract functions using MultiContractCallHandler, an error occurs:

called `Result::unwrap()` on an `Err` value: Other("expected `Unit`, got `Tuple([Unit])`")

However, the transaction actually succeeds.

Steps to Reproduce

git clone [email protected]:compolabs/orderbook-contract.git 

cd orderbook-contract/  

git checkout testnet

forc build -v --release

echo "ADMIN=<YOUR PK WITH SOME TEST ETH>" >> .env 

cargo run --bin match_in_pairs_multicall

Error Details

While executing the script, the following error is encountered:

called `Result::unwrap()` on an `Err` value: Other("expected `Unit`, got `Tuple([Unit])`")
image

Despite this error, the transaction is successfully processed.

References

Function being called

https://github.com/compolabs/orderbook-contract/blob/testnet/src/orderbook_utils.rs#L308

 pub async fn match_in_pairs_multicall(
        &self,
        orders: Vec<(Bits256, Bits256)>,
    ) -> Result<FuelCallResponse<()>, fuels::types::errors::Error> {
        let wallet = self.instance.account();
        let mut multi_call_handler = MultiContractCallHandler::new(wallet.clone());

        for (sell_order_id, buy_order_id) in orders {
            let call_handler = self
                .instance
                .methods()
                .match_orders(sell_order_id.clone(), buy_order_id.clone())
                .append_variable_outputs(2)
                .with_tx_policies(TxPolicies::default().with_script_gas_limit(3500000));
            multi_call_handler.add_call(call_handler);
        }

        multi_call_handler
            .with_tx_policies(
                TxPolicies::default()
                    .with_tip(1)
                    .with_script_gas_limit(9_999_000),
            )
            .call()
            .await
    }

Script used to call the function

https://github.com/compolabs/orderbook-contract/blob/testnet/scripts/match_in_pairs_multicall.rs


#[tokio::main]
async fn main() {
    print_title("Match in pairs multicall");
    dotenv().ok();
    let provider = Provider::connect(RPC).await.unwrap();
    let secret = std::env::var("ADMIN").unwrap();
    let wallet =
        WalletUnlocked::new_from_private_key(secret.parse().unwrap(), Some(provider.clone()));
    println!("wallet.address() = {:?}", wallet.address());
    let token_contract = TokenContract::new(
        &ContractId::from_str(TOKEN_CONTRACT_ID).unwrap().into(),
        wallet.clone(),
    );

    let token_contract_id = token_contract.contract_id().into();
    let base_asset = Asset::new(wallet.clone(), token_contract_id, MARKET_SYMBOL);
    let quote_asset = Asset::new(wallet.clone(), token_contract_id, "USDC");

    let orderbook = Orderbook::new(&wallet, ORDERBOOK_CONTRACT_ID).await;
    let price = (BASE_PRICE * 10f64.powf(orderbook.price_decimals as f64)) as u64;

    //mint base asset to sell
    let base_size = base_asset.parse_units(BASE_SIZE as f64) as u64;
    base_asset
        .mint(wallet.address().into(), base_size)
        .await
        .unwrap();

    // sell
    let sell_order_id = orderbook
        .open_order(base_asset.asset_id, -1 * base_size as i64, price - 1)
        .await
        .unwrap()
        .value;
    println!(
        "sell_order = {:?}",
        orderbook.order_by_id(&sell_order_id).await.unwrap().value
    );

    //mint quote asset to buy
    let quote_size = quote_asset.parse_units(BASE_SIZE as f64 * BASE_PRICE as f64);
    quote_asset
        .mint(wallet.address().into(), quote_size as u64)
        .await
        .unwrap();

    //buy
    let buy_order_id = orderbook
        .open_order(base_asset.asset_id, base_size as i64, price)
        .await
        .unwrap()
        .value;

    println!(
        "buy_order = {:?}\n",
        orderbook.order_by_id(&buy_order_id).await.unwrap().value
    );

    orderbook
        .match_in_pairs_multicall(vec![(sell_order_id, buy_order_id)])
        .await
        .unwrap();
}

Expected Behavior

The MultiContractCallHandler should not throw an error if the transaction is successful. The handler should correctly interpret the result type without encountering the Unit vs Tuple([Unit]) mismatch.

@hal3e
Copy link
Contributor

hal3e commented Jun 14, 2024

The problem is that for the MultiContractCallHandler you have to specify the output type of the call. It is a tuple of types of the added calls. Let's say you added 3 calls and each returns an u8 the output type of the multi-call would be (u8, u8, u8)
Please have a look at the docs: https://rust.fuel.network/v0.63.1/calling-contracts/multicalls.html#output-values

As you are dynamically processing orders, I think you will not be able to use MultiCallHandler in this way as you can not dynamically set the output type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants