Calling other contracts
A call that changes another contract's state is deferred with defer. It runs after this entrypoint's writes and events. Use with value = ... to attach ether.
calling-contracts.lithe
(* A state-changing call to another contract is deferred: it runs after this
entrypoint's writes and events, never in the middle of them. *)
import "std/evm";
interface Token is {
view function balanceOf(owner : address) : uint;
function transfer(to : address; amount : uint) : bool;
}
interface Pool is {
payable function deposit(beneficiary : address);
}
error Empty;
storage is record {
token : Token;
pool : Pool;
swept : uint;
}
external function init(const token : Token; const pool : Pool) is {
storage.token := token;
storage.pool := pool;
}
external function sweep(const to : address)
raises Empty
is {
const held : uint := query storage.token.balanceOf(Evm.self());
assert(held > 0, Empty);
storage.swept := storage.swept + held;
defer storage.token.transfer(to, held);
}
(* Attach ether with `with value = ...`. The value is a `uint` of wei, and only a
method the interface declares `payable function` takes it. *)
external payable function forward() is {
defer storage.pool.deposit(Evm.sender()) with value = uint(Evm.value());
}- The arguments are evaluated at the
defer, soheldis the balance read at that point. depositis declaredpayable functionbecausePoolaccepts ether with it.with valueon a method that isn'tpayable, such astransfer, is a compile error.- The compiler warns that
sweepandforwardcould be re-entered while their calls run. Addnonreentrantwhere that matters.

