Using call results
A deferred call's result arrives after the transition that deferred it. then (result : T) { ... } runs a continuation with the decoded result, as a new phase that can write, emit, and defer again.
continuations.lithe
(* A deferred call can be followed by a continuation with `then`. The continuation
runs after the call returns, receives its decoded result, and is a new phase of
the transition: it may write storage, emit, and defer again. *)
interface Exchange is {
function swap(amountIn : uint) : uint;
function split(amount : uint) : (uint, uint);
}
error AlreadyFilled of uint;
event Filled of record {
indexed id : uint;
amountOut : uint;
}
type Order is record {
status : uint8;
amountOut : uint;
}
storage is record {
exchange : Exchange;
orders : map(uint, Order);
left : uint;
right : uint;
}
external function init(const exchange : Exchange) is {
storage.exchange := exchange;
}
external nonreentrant function fill(const id : uint; const amountIn : uint)
raises AlreadyFilled
is {
assert(storage.orders[id].status = uint8(0), AlreadyFilled(id));
(* The exchange sees this order as pending while it runs. *)
storage.orders[id].status := uint8(1);
defer storage.exchange.swap(amountIn)
then (amountOut : uint) {
storage.orders[id].status := uint8(2);
storage.orders[id].amountOut := amountOut;
emit Filled { id = id; amountOut = amountOut; };
};
}
(* A tuple result destructures in the binding. *)
external nonreentrant function split(const amount : uint) is {
defer storage.exchange.split(amount)
then ((a, b) : (uint, uint)) {
storage.left := storage.left + a;
storage.right := storage.right + b;
};
}- Parameters and
constvalues are visible in the continuation. Avarfrom the first phase is not. - If the swap reverts, the whole transaction reverts, including the first phase's writes. To handle the failure instead, see Recovering from failed calls.
- See Continuations and the Order executor.

