Cross-Contract Calls
Contracts may call each other using the runtime library and indicating the
- Contract Id: the callee's contract address;
- Method Name: the name of the method which is to be called;
- Method Args: the JSON-serialized arguments for the above method; fields of the JSON need to be in snake case.
- Rust
- Golang
- AssemblyScript
- CPP
Cross-contract calls are made through function Runtime::call_contract()
fn call_contract(contract_id: String, method_name: String, method_args: Option<String>) -> anyhow::Result<R>
Cross-contract calls are made through function runtime.CallContract()
func CallContract[T any](contractId string, methodName string, methodArgs string) (*T, error)
Notice that it return a tuple of (*T, error)
, where T
is the return type of he function being called.
If the second element of the tuple is nil
, then the pointer in the first points to the actual result of the call.
For example, the following function from the Cross-contract call tutorial calls the get_count
function of the applet whose contract Id is c.ContractId
, without any parameters.
func (c *Counter) getCount() (*uint, error) {
resp, err := runtime.CallContract[uint](c.ContractId, "get_count", "")
if err != nil {
return nil, err
} else {
return resp, nil
}
}
static callContract<R>(
contractId: string,
methodName: string,
methodArgs: string | null = null
): Result<Box<R>, WeilError> {
Cross-contract calls are made through function Runtime::callContract()
std::pair<int,std::string> Runtime::callContract(const std::string contract_id,
const std::string method_name,
const std::string method_args)
Notice that it returns a std::pair<int, std::string>.
The first item in the result signifies whether the cross contract call returned any error.
- If the value is 1, then the call failed and the second item in the result will contain the error message.
- If the value is 0, then the call was successfull and the second item will be a serialized value of the returned result (which can then be deserialized to match the required type)
Example intended usage
std::pair<int,std::string> result = weilsdk::Runtime::callContract("0x12345", "getApples", "red");
if(result.first){
//some error occurred
std::string error = result.second;
std::cout<<error<<std::endl;
//We don't sell red apples
}
else{
std::string numApplesStr = result.second;
int apples = std::stoi(numApplesStr);
std::cout<<"Num of red apples were "<<std::endl;
std::cout<<apples<<std::endl;
}
Security Restrictions
Some restrictions on making cross-contract calls are in place:
- The active cross-contract call frame should not exceed
5
This is to erroneous or malicious behavior that could exhaust all the resources and fuel. - Reentrancy is not enabled allowed by default . This means that there cannot exist a cycle in cross-contract calling sequence and is enforced to avoid the well-known
Reentrancy Attack
.