Skip to main content

Calling Functions

Synchronous function calls between smart contracts act very similar to how normal function calls work in any programming language, but with a slight twist. With normal function calls you share all the global memory that you can access with every function that you call. However, when calling a smart contract function you can only access the memory assigned to that specific smart contract. Remember, each smart contract runs in its own sandbox environment. Therefore, the only way to share data between smart contracts that call each other is through function parameters and return values.

Synchronous calls can only be made between contracts that are running on the same contract chain. The IOTA Smart Contracts host knows about all the contracts it is running on a chain, and therefore is able to dispatch the call to the correct contract function. The function descriptor is used to specify the call parameters (if any) through its params proxy, and to invoke the function through its func interface.

In addition, when the function that is called is not a View, it is possible to pass tokens to the function call through this interface. Note that the only way to call a function and properly pass tokens to it within the same chain is through the function descriptor. Otherwise, the incoming() function will not register any incoming tokens.

When the call is made, the calling function will be paused and wait for the called function to complete. After completion, it may access the returned values (if any) through the results proxy of the function descriptor.

When calling a function from a View function, it is only possible to call other View functions. The ScFuncs interface enforces this at compile-time through the IOTA Smart Contracts function context that needs to be passed to the function that creates the function descriptor.

Here's how a smart contract would tell a dividend contract on the same chain to divide the 1000 tokens it passes to the function:

f := dividend.ScFuncs.Divide(ctx)
f.Func.TransferIotas(1000).Call()

And here is how a smart contract would ask a dividend contract on the same chain to return the dispersion factor for a specific address:

f := dividend.ScFuncs.GetFactor(ctx)
f.Params.Address().SetValue(address)
f.Func.Call()
factor := f.Results.Factor().Value()
  1. Create a function descriptor for the desired function.
  2. Use the params proxy in the function descriptor to set any required parameters.
  3. Direct the func member of the function descriptor to call the associated function
  4. Use the results proxy in the function descriptor to retrieve any results we are interested in.

The function descriptors assume that the function to be called is associated with the default Hname of the contract, in this case ScHname::new("dividend"). If you deployed the contract that contains the function you want to call under a different name, then you would have to provide its associated Hname to the func member through the of_contract() member function like this:

altContract := NewScHname("alternateName")
f := dividend.ScFuncs.Divide(ctx)
f.Func.OfContract(altContract).TransferIotas(1000).Call()

In the next section we will look at how we can request smart contract functions in a different chain to be executed in a similar way.