Skip to main content


One unit of ZIL as a native token is equal to 1000000000000 QA. (1 ZIL = 10^12 QA). When we deal with ZIL as a unit in Scilla, it is represented as an Uint128. The below example shows how to accept/send funds to/from a smart contract.


The example does not implement ownership logic, therefore anyone can withdraw funds. Do not use this contract.

Accept ZIL contract#

Deposit takes any ZIL presented to it with the accept keyword.

Withdraw checks the amount wanting to be withdrawn against what the contract currently has.

Empty sends all of the contract funds to the _sender of the function.

scilla_version 0(*********************************************************************************)(* Receive, store and send funds [QA = 10^{-12} ZIL, LI = 10^{-6} ZIL = 10^6 QA] *)(* in a smart contract                                                           *)(*********************************************************************************)import IntUtils
library Funds
let one_msg = (* Wrap single message into singleton list *)  fun (msg : Message) =>    let nil_msg = Nil {Message} in    Cons {Message} msg nil_msg
let msg_as_list_wo_tag = (* Create transaction message as singleton list without a tag *)  fun (recipient : ByStr20) =>  fun (amount : Uint128) =>    let msg = {_tag : ""; _recipient : recipient; _amount : amount } in    one_msg msg
let is_positive = (* check if a uint is > 0 *)  fun (n : Uint128) =>    let zero = Uint128 0 in    uint128_gt n zero
contract Funds()
procedure TransferTo(to : ByStr20, amount : Uint128)  msgs = msg_as_list_wo_tag to amount;  send msgsend
transition Deposit() (* send QA to contract to receive and store it in contract *)  received = is_positive _amount;  match received with  |True  =>    accept;    b <- _balance;    ev = {_eventname: "DepositSuccess"; amount_received: _amount; new_balance: b};    event ev  |False =>  endend
transition Withdraw(amount : Uint128) (* withdraw an amount from the contract *)  b <- _balance;  is_more_than_balance = uint128_gt amount b;  match is_more_than_balance with  |True => (* requested more than the balance, do not fullfil request *)    ev = {_eventname: "WithdrawFailue"; amount_requested: amount; new_balance: b};    event ev  |False =>    new_b = builtin sub b amount;    TransferTo _sender amount;    ev = {_eventname: "WithdrawSuccess"; amount_withdrawn: amount; new_balance: new_b};    event ev  endend
transition Empty() (* withdraw everything *)  b <- _balance;  zero = Uint128 0;  TransferTo _sender b;  new_b <- _balance;  ev = {_eventname: "EmptySuccess"; amount_withdrawn: b; new_balance: new_b};  event evend

Refund mechanism#

This function checks the _amount against a passed parameter cap. If the amount sent is less than cap, the procedure does nothing, but in the case where you send more than cap, it can calculate the difference equal to where you send exactly the right amount and returns the excess amount to the user.

procedure AcceptWithCap (cap : Uint128)  sent_more_than_necessary = builtin lt cap _amount;  match sent_more_than_necessary with  | True =>      amount_to_refund = builtin sub _amount cap;      accept;      msg = { _tag : ""; _recipient: _sender; _amount: amount_to_refund };      msgs = one_msg msg;      send msgs  | False =>  endend

Further reading#

Scilla Documentation - Money Idioms

Scilla Documentation - Units