Handling Nested Smart Contract Dependencies in TypeScript SDK Calls

Hey everyone, I’m in the process of building a project that involves a system of 5 interconnected smart contracts. Previously, when I worked on a lending protocol project, I had to instantiate the dependent Oracle contract in my frontend code to make function calls, like so:

// Example code snippet from a previous project
const { addressInput, provider } = this.rootStore.accountStore;
if (addressInput == null || provider == null) return;
const { priceOracle } = this.rootStore.settingsStore.currentVersionConfig;
const oracle = new Contract(priceOracle, OracleAbi__factory.abi, provider);
const { value } = await marketContract.functions
  .available_to_borrow(addressInput)
  .addContracts([oracle])
  .simulate();

My question is, for a system with multiple layers of contract dependencies, is it necessary to instantiate and pass all related contracts when making calls through the TypeScript SDK? Or is there a streamlined way to manage these nested dependencies? Would love to get insights into how others are handling this scenario.

I have found this doc, but it doesn’t say much

Hi there @sway!
This example might be helpful.

  const { minGasPrice } = provider.getGasConfig();

    const { value: results } = await counterContract
      .multiCall([
        counterContract.functions.get_count(),
        counterContract.functions.increment_count(2),
        counterContract.functions.increment_count(4),
      ])
      .txParams({ gasPrice: minGasPrice })
      .call();

    const initialValue = new BN(results[0]).toNumber();
    const incrementedValue1 = new BN(results[1]).toNumber();
    const incrementedValue2 = new BN(results[2]).toNumber();

    expect(incrementedValue1).toEqual(initialValue + 2);
    expect(incrementedValue2).toEqual(incrementedValue1 + 4);
    // #endregion multicall-1

Let me know if this helps!

3 Likes

@sway You’ll also find more examples in this page.

2 Likes

Hi all, I think there was a bit of confusion regarding my earlier query. To clarify, I’m not focusing on multi-call scenarios but rather on the correct approach to including dependent smart contracts in a function call via TypeScript SDK.

In a previous project, as illustrated in my example, I had to use the addContract method, passing the oracle instance to make the function call successfully. Without this, the requests would fail. Here’s the relevant snippet for reference:

// Example from a previous project
const { addressInput, provider } = this.rootStore.accountStore;
if (addressInput == null || provider == null) return;
const { priceOracle } = this.rootStore.settingsStore.currentVersionConfig;
const oracle = new Contract(priceOracle, OracleAbi__factory.abi, provider);
const { value } = await marketContract.functions
  .available_to_borrow(addressInput)
  .addContracts([oracle])
  .simulate();

My current project involves a system of 5 interlinked smart contracts, where one contract might call functions of others in a nested manner (e.g., Contract 1 interacts with Contracts 2 and 3, and Contract 3 might call Contract 4). My question is: In such a setup with nested dependencies, do I need to pass instances of all related smart contracts when making a call? How should I handle these dependencies in TypeScript SDK to ensure successful transaction simulations? Any insights or best practices would be greatly appreciated!

Hi there!

Sorry for the delay, I was OOO during devconnect.
Thanks for providing more context on your question.

In such a setup with nested dependencies, do I need to pass instances of all related smart contracts when making a call?

Yes, every instance that is going to be invocated must be added to the call context.

How should I handle these dependencies in TypeScript SDK to ensure successful transaction simulations?

This example might be useful

https://github.com/FuelLabs/fuels-ts/blob/master/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts

No insights on my side, however, I’ve requested some help from the Fuels-TS team. Expect more information soon.

Let me know if this solves your question :palm_tree:

1 Like

@sway Yes, every time you call a function on a contract that interacts with other Contracts, you’ll have to reference that other contract just as you did in your last example.

You could have individual files, one per contract, exporting a ready-to-use Contract instance. Then, whenever you’d do a call, you could import the related contract and pass it along.

import { marketContract } from './market.ts';
import { oracleContract } from './oracle.ts';

const { value } = await marketContract.functions
  .available_to_borrow(addressInput)
  .addContracts([oracleContract])
  .simulate();


thanks, We have checked in real code already)

1 Like