namillum
Version:
Bubble Protocol SDK
121 lines (97 loc) • 3.75 kB
Markdown
tags:
- funds
- accept
- zil
- token
# Funds
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.
:::danger
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.
```ocaml
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 msgs
end
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 =>
end
end
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
end
end
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 ev
end
```
## 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.
```ocaml
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 =>
end
end
```
## Further reading
[Scilla Documentation - Money Idioms](https://scilla.readthedocs.io/en/latest/scilla-tips-and-tricks.html?highlight=funds#money-idioms)
[Scilla Documentation - Units](https://scilla.readthedocs.io/en/latest/scilla-in-depth.html?highlight=funds#mutable-fields)