Raw calls
An interface describes calls whose shape is known when the contract is written. A wallet, a timelock, or a multisig runs calls chosen later, so it sends calldata as bytes. Evm.call and Evm.delegateCall are deferred like every state-changing call, and Evm.staticCall is queried.
raw_calls.lithe
(* A wallet that runs whatever calls its owner asks for: any target, any calldata, any
value. `Evm.call` is deferred like every call, so the wallet's own state is written
before the target runs, and the continuation gets the return data as it came back. *)
import "std/bytes";
import "std/evm";
error NotOwner;
error MismatchedLengths;
event Executed of record {
indexed target : address;
value : uint;
result : bytes;
}
storage is record {
owner : address;
nonce : uint;
}
deploy(const owner : address) is {
storage.owner := owner;
}
payable receive is {
skip
}
external nonreentrant function execute(const target : address; const value : uint; const data : bytes)
raises NotOwner
is {
assert(Evm.sender() = storage.owner, NotOwner);
storage.nonce := storage.nonce + 1;
defer Evm.call(target, data) with value = value then (result : bytes) {
emit Executed { target = target; value = value; result = result; };
};
}
(* One call per target, in order. A failed call passes its revert data on unchanged. *)
external nonreentrant function batch(const targets : list(address); const calls : list(bytes))
raises NotOwner | MismatchedLengths | forwarded
is {
assert(Evm.sender() = storage.owner, NotOwner);
assert(targets.length = calls.length, MismatchedLengths);
for (i, target) : (uint, address) in targets do {
defer Evm.call(target, calls[i]) then {
| Ok -> { skip }
| Error(reason : bytes) -> { forward reason; }
};
}
}
(* A read-only call with calldata of your own: here, the SHA-256 precompile. *)
external view function sha256Of(const data : bytes) : bytes32 is
Bytes.word(query Evm.staticCall(0x0000000000000000000000000000000000000002, data), 0)
external view function nonce() : uint is
storage.nonceexecutebumpsnoncebefore the target runs: the deferred call sees the wallet's state already written.- The continuation's
resultis the return data exactly as it came back. Read it withAbi.decodewhen you know its shape. - In
batch, a failed call reverts the whole batch with the target's own revert data, throughforward reason, so it raisesforwarded. Evm.staticCallreaches precompiles, whose input is not ABI-encoded. Address0x…02is SHA-256.payable receivelets the wallet hold the ether it sends.
See Raw calls for the rules, including Evm.delegateCall.

