// ./contract_b.swcontract;use contract_a::ContractA;abiContractB {fnmake_call();}const contract_id =0x79fa8779bed2f36c3581d01c79df8da45eee09fac1fd76a5a656e16326317ef0;implContractBforContract {fnmake_call() {let x =abi(ContractA, contract_id);let return_value = x.receive(true, 3); // will be 45 }}
Icon InfoCircle
Note: The ABI is for external calls only therefore you cannot define a method in the ABI and call it in the same contract. If you want to define a function for a contract, but keep it private so that only your contract can call it, you can define it outside of the impl and call it inside the contract, similar to the return_45() function above.
All calls forward a gas stipend, and may additionally forward one native asset with the call.
Here is an example of how to specify the amount of gas (gas), the asset ID of the native asset (asset_id), and the amount of the native asset (coins) to forward:
Another way of avoiding re-entrancy-related attacks is to follow the so-called
CEI pattern. CEI stands for "Checks, Effects, Interactions", meaning that the
contract code should first perform safety checks, also known as
"pre-conditions", then perform effects, i.e. modify or read the contract storage
and execute external contract calls (interaction) only at the very end of the
function/method.
Please see this blog post Icon Link
for more detail on some vulnerabilities in case of storage modification after
interaction and this blog post Icon Link for
more information on storage reads after interaction.
The Sway compiler implements a check that the CEI pattern is not violated in the
user contract and issues warnings if that's the case.
For example, in the following contract the CEI pattern is violated, because an
external contract call is executed before a storage write.
The CEI pattern analyzer issues a warning as follows, pointing to the
interaction before a storage modification:
warning --> /path/to/contract/main.sw:28:9 |26 |27 | let caller = abi(OtherContract, external_contract_id.into());28 | caller.external_call { coins: bal }(); | _________-29 | |30 | | // Storage update _after_ external call31 | | storage.balances.insert(sender, 0); | |__________________________________________- Storage write after external contract interaction in function or method "withdraw". Consider making all storage writes before calling another contract32 | }33 | } |____
In case there is a storage read after an interaction, the CEI analyzer will issue a similar warning.
In addition to storage reads and writes after an interaction, the CEI analyzer reports analogous warnings about:
balance tree updates, i.e. balance tree reads with subsequent writes, which may be produced by the tr and tro ASM instructions or library functions using them under the hood;
balance trees reads with bal instruction;
changes to the output messages that can be produced by the __smo intrinsic function or the smo ASM instruction.
While the Fuel contract calling paradigm is similar to the EVM's (using an ABI, forwarding gas and data), it differs in two key ways:
Native assets: FuelVM calls can forward any native asset not just base asset.
No data serialization: Contract calls in the FuelVM do not need to serialize data to pass it between contracts; instead they simply pass a pointer to the data. This is because the FuelVM has a shared global memory which all call frames can read from.