laksa-core-contract
Version:
Contract instance for laksa
461 lines (454 loc) • 16.7 kB
JavaScript
/* eslint-disable no-tabs */
export const testContract = `scilla_version 0
(* HelloWorld contract *)
import ListUtils
(***************************************************)
(* Associated library *)
(***************************************************)
library HelloWorld
let one_msg =
fun (msg : Message) =>
let nil_msg = Nil {Message} in
Cons {Message} msg nil_msg
let not_owner_code = Int32 1
let set_hello_code = Int32 2
(***************************************************)
(* The contract definition *)
(***************************************************)
contract HelloWorld
(owner: ByStr20)
field welcome_msg : String = ""
transition setHello (msg : String)
is_owner = builtin eq owner _sender;
match is_owner with
| False =>
msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : not_owner_code};
msgs = one_msg msg;
send msgs
| True =>
welcome_msg := msg;
msg = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0; code : set_hello_code};
msgs = one_msg msg;
send msgs
end
end
transition getHello ()
r <- welcome_msg;
e = {_eventname: "getHello()"; msg: r};
event e
end
transition multipleMsgs()
msg1 = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0};
msg2 = {_tag : "Main"; _recipient : _sender; _amount : Uint128 0};
msgs1 = one_msg msg1;
msgs2 = Cons {Message} msg2 msgs1;
send msgs2
end
transition contrAddr()
msg1 = {_eventname : "ContractAddress"; addr : _this_address };
event msg1
end`
export const zrc20 = `scilla_version 0
(* This contract implements a fungible token interface a la ERC20.*)
(***************************************************)
(* Associated library *)
(***************************************************)
library FungibleToken
let min_int =
fun (a : Uint128) => fun (b : Uint128) =>
let alt = builtin lt a b in
match alt with
| True =>
a
| False =>
b
end
let le_int =
fun (a : Uint128) => fun (b : Uint128) =>
let x = builtin lt a b in
match x with
| True => True
| False =>
let y = builtin eq a b in
match y with
| True => True
| False => False
end
end
(***************************************************)
(* The contract definition *)
(***************************************************)
contract FungibleToken
(owner : ByStr20,
total_tokens : Uint128)
(* Initial balance is not stated explicitly: it's initialized when creating the contract. *)
field balances : Map ByStr20 Uint128 =
let m = Emp ByStr20 Uint128 in
builtin put m owner total_tokens
field allowed : Map ByStr20 (Map ByStr20 Uint128) = Emp ByStr20 (Map ByStr20 Uint128)
transition BalanceOf (tokenOwner : ByStr20)
bal <- balances[tokenOwner];
match bal with
| Some v =>
e = {_eventname : "BalanceOf"; address : tokenOwner; balance : v};
event e
| None =>
e = {_eventname : "BalanceOf"; address : tokenOwner; balance : Uint128 0};
event e
end
end
transition TotalSupply ()
e = {_eventname : "TotalSupply"; caller : _sender; balance : total_tokens};
event e
end
transition Transfer (to : ByStr20, tokens : Uint128)
bal <- balances[_sender];
match bal with
| Some b =>
can_do = le_int tokens b;
match can_do with
| True =>
(* subtract tokens from _sender and add it to "to" *)
new_sender_bal = builtin sub b tokens;
balances[_sender] := new_sender_bal;
(* Adds tokens to "to" address *)
to_bal <- balances[to];
new_to_bal = match to_bal with
| Some x => builtin add x tokens
| None => tokens
end;
balances[to] := new_to_bal;
e = {_eventname : "TransferSuccess"; sender : _sender; recipient : to; amount : tokens};
event e
| False =>
(* balance not sufficient. *)
e = {_eventname : "TransferFailure"; sender : _sender; recipient : to; amount : Uint128 0};
event e
end
| None =>
(* no balance record, can't transfer *)
e = {_eventname : "TransferFailure"; sender : _sender; recipient : to; amount : Uint128 0};
event e
end
end
transition TransferFrom (from : ByStr20, to : ByStr20, tokens : Uint128)
bal <- balances[from];
(* Check if _sender has been authorized by "from" *)
sender_allowed_from <- allowed[from][_sender];
match bal with
| Some a =>
match sender_allowed_from with
| Some b =>
(* We can only transfer the minimum of available or authorized tokens *)
t = min_int a b;
can_do = le_int tokens t;
match can_do with
| True =>
(* tokens is what we should subtract from "from" and add to "to" *)
new_from_bal = builtin sub a tokens;
balances[from] := new_from_bal;
to_bal <- balances[to];
match to_bal with
| Some tb =>
new_to_bal = builtin add tb tokens;
balances[to] := new_to_bal
| None =>
(* "to" has no balance. So just set it to tokens *)
balances[to] := tokens
end;
(* reduce "allowed" by "tokens" *)
new_allowed = builtin sub b tokens;
allowed[from][_sender] := new_allowed;
e = {_eventname : "TransferFromSuccess"; sender : from; recipient : to; amount : tokens};
event e
| False =>
e = {_eventname : "TransferFromFailure"; sender : from; recipient : to; amount : Uint128 0};
event e
end
| None =>
e = {_eventname : "TransferFromFailure"; sender : from; recipient : to; amount : Uint128 0};
event e
end
| None =>
e = {_eventname : "TransferFromFailure"; sender : from; recipient : to; amount : Uint128 0};
event e
end
end
transition Approve (spender : ByStr20, tokens : Uint128)
allowed[_sender][spender] := tokens;
e = {_eventname : "ApproveSuccess"; approver : _sender; spender : spender; amount : tokens};
event e
end
transition Allowance (tokenOwner : ByStr20, spender : ByStr20)
spender_allowance <- allowed[tokenOwner][spender];
match spender_allowance with
| Some n =>
e = {_eventname : "Allowance"; owner : tokenOwner; spender : spender; amount : n};
event e
| None =>
e = {_eventname : "Allowance"; owner : tokenOwner; spender : spender; amount : Uint128 0};
event e
end
end`
export const simpleDEX = `
scilla_version 0
import PairUtils
(* Simple DEX : P2P Token Trades *)
(* Disclaimer: This contract is experimental and meant for testing purposes only *)
(* DO NOT USE THIS CONTRACT IN PRODUCTION *)
library SimpleDex
(* Pair helpers *)
let getAddressFromPair = @fst (ByStr20) (Uint128)
let getValueFromPair = @snd (ByStr20) (Uint128)
(* Event for errors *)
let make_error_event =
fun (location: String) =>
fun (msg: String) =>
{ _eventname : "Error" ; raisedAt: location; message: msg}
(* Order = { tokenA, valueA, tokenB, valueB } *)
type Order =
| Order of ByStr20 Uint128 ByStr20 Uint128
(* Create an orderID based on the hash of the parameters *)
let createOrderId =
fun (order: Order) =>
builtin sha256hash order
(* Create one transaction message *)
let transaction_msg =
fun (recipient : ByStr20) =>
fun (tag : String) =>
fun (transferFromAddr: ByStr20) =>
fun (transferToAddr: ByStr20) =>
fun (transferAmt: Uint128) =>
{_tag : tag; _recipient : recipient; _amount : Uint128 0;
from: transferFromAddr; to: transferToAddr; tokens: transferAmt }
(* Wrap one transaction message as singleton list *)
let transaction_msg_as_list =
fun (recipient : ByStr20) =>
fun (tag : String) =>
fun (transferFromAddr: ByStr20) =>
fun (transferToAddr: ByStr20) =>
fun (transferAmt: Uint128) =>
let one_msg =
fun (msg : Message) =>
let nil_msg = Nil {Message} in
Cons {Message} msg nil_msg in
let msg = transaction_msg recipient tag transferFromAddr transferToAddr transferAmt in
one_msg msg
(* Compute the new pending return val *)
(* If no existing records are found, return incomingTokensAmt *)
(* else, return incomingTokenAmt + existing value *)
let computePendingReturnsVal =
fun ( prevVal : Option Uint128 ) =>
fun ( incomingTokensAmt : Uint128 ) =>
match prevVal with
| Some v =>
builtin add v incomingTokensAmt
| None =>
incomingTokensAmt
end
let success = "Success"
(***************************************************)
(* The contract definition *)
(***************************************************)
contract SimpleDex
(contractOwner: ByStr20)
(* Orderbook: mapping (orderIds => ( (tokenA, valueA) (tokenB, valueB) )) *)
(* @param: tokenA: Contract address of token A *)
(* @param: valueA: total units of token A offered by maker *)
(* @param: tokenB: Contract address of token B *)
(* @param: valueB: total units of token B requsted by maker *)
field orderbook : Map ByStr32 Order
= Emp ByStr32 Order
(* Order info stores the mapping ( orderId => (tokenOwnerAddress, expirationBlock)) *)
field orderInfo : Map ByStr32 (Pair (ByStr20)(BNum)) = Emp ByStr32 (Pair (ByStr20) (BNum))
(* Ledger of how much the _sender can claim from the contract *)
(* mapping ( walletAddress => mapping (tokenContracts => amount) ) *)
field pendingReturns : Map ByStr20 (Map ByStr20 Uint128) = Emp ByStr20 (Map ByStr20 Uint128)
(* Maker creates an order to exchange valueA of tokenA for valueB of tokenB *)
transition makeOrder(tokenA: ByStr20, valueA: Uint128, tokenB: ByStr20, valueB: Uint128, expirationBlock: BNum)
currentBlock <- & BLOCKNUMBER;
validExpirationBlock = let minBlocksFromCreation = Uint128 50 in
let minExpiration = builtin badd currentBlock minBlocksFromCreation in
builtin blt minExpiration expirationBlock;
match validExpirationBlock with
| True =>
(* Creates a new order *)
newOrder = Order tokenA valueA tokenB valueB;
orderId = createOrderId newOrder;
orderbook[orderId] := newOrder;
(* Updates orderInfo with maker's address and expiration blocknumber *)
p = Pair {(ByStr20) (BNum)} _sender expirationBlock;
orderInfo[orderId] := p;
e = {_eventname: "Order Created"; hash: orderId };
event e;
(* Transfer tokens from _sender to the contract address *)
msgs = let tag = "TransferFrom" in
let zero = Uint128 0 in
transaction_msg_as_list tokenA tag _sender _this_address valueA;
send msgs
| False =>
e = let func = "makeOrder" in
let error_msg = "Expiration block must be at least 50 blocks more than current block" in
make_error_event func error_msg;
event e
end
end
(* Taker fills an order *)
transition fillOrder(orderId: ByStr32)
getOrder <- orderbook[orderId];
match getOrder with
| Some (Order tokenA valueA tokenB valueB)=>
(* Check the expiration block *)
optionOrderInfo <- orderInfo[orderId];
match optionOrderInfo with
| Some info =>
currentBlock <- & BLOCKNUMBER;
blockBeforeExpiration = let getBNum = @snd (ByStr20) (BNum) in
let expirationBlock = getBNum info in
builtin blt currentBlock expirationBlock;
match blockBeforeExpiration with
| True =>
makerAddr = let getMakerAddr = @fst (ByStr20)(BNum) in
getMakerAddr info;
(* Updates taker with the tokens that he is entitled to claim *)
prevVal <- pendingReturns[_sender][tokenA];
takerAmt = computePendingReturnsVal prevVal valueA;
pendingReturns[_sender][tokenA] := takerAmt;
prevVal <- pendingReturns[makerAddr][tokenB];
makerAmt = computePendingReturnsVal prevVal valueB;
pendingReturns[makerAddr][tokenB] := makerAmt;
(* Delete orders from the orderbook and orderinfo *)
delete orderInfo[orderId];
delete orderbook[orderId];
e = {_eventname: "Order Filled"; hash: orderId };
event e;
(* Transfer tokens from _sender to the contract address *)
msgs = let tag = "TransferFrom" in
transaction_msg_as_list tokenB tag _sender _this_address valueB;
send msgs
| False =>
e = let func = "fillOrder" in
let error_msg = "Current block number exceeds the expiration block set" in
make_error_event func error_msg;
event e
end
| None =>
e = let func = "fillOrder" in
let error_msg = "OrderId not found" in
make_error_event func error_msg;
event e
end
| None =>
e = let func = "fillOrder" in
let error_msg = "OrderId not found" in
make_error_event func error_msg;
event e
end
end
(* Allows users to claim back their tokens from the smart contract *)
transition ClaimBack(token: ByStr20)
getAmtOutstanding <- pendingReturns[_sender][token];
match getAmtOutstanding with
| Some amtOutstanding =>
delete pendingReturns[_sender][token];
e = {_eventname: "Claimback Successful"; caller: _sender; tokenAddr: token; amt: amtOutstanding };
event e;
(* Transfer tokens from _sender to the contract address *)
msgs = let tag = "TransferFrom" in
transaction_msg_as_list token tag _this_address _sender amtOutstanding;
send msgs
| None =>
e = let func = "claimBack" in
let error_msg = "No Pending Returns for Sender and Contract Address found" in
make_error_event func error_msg;
event e
end
end
(* Maker can cancel his order *)
transition cancelOrder(orderId: ByStr32)
getOrderInfo <- orderInfo[orderId];
match getOrderInfo with
| Some orderInfo =>
makerAddr = let getMakerAddr = @fst (ByStr20)(BNum) in
getMakerAddr orderInfo;
checkSender = builtin eq makerAddr _sender;
match checkSender with
| True =>
(* Sender is the maker, proceed with cancellation *)
fetchOrder <- orderbook[orderId];
match fetchOrder with
| Some (Order tokenA valueA _ _)=>
(* Updates taker with the tokens that he is entitled to claim *)
prevVal <- pendingReturns[_sender][tokenA];
takerAmt = computePendingReturnsVal prevVal valueA;
pendingReturns[_sender][tokenA] := takerAmt;
(* Delete orders from the orderbook and orderinfo *)
delete orderInfo[orderId];
delete orderbook[orderId];
e = {_eventname: "Cancel order successful"; hash: orderId };
event e
(* @note: For consistency, we use claimback instead of sending the tokens *)
(* back to the maker *)
| None =>
e = let func = "cancelOrder" in
let error_msg = "OrderID not found" in
make_error_event func error_msg;
event e
end
| False =>
(* Unauthorized transaction *)
e = let func = "cancelOrder" in
let error_msg = "Sender is not maker of the order" in
make_error_event func error_msg;
event e
end
| None =>
(* Order ID not found *)
e = let func = "cancelOrder" in
let error_msg = "OrderID not found" in
make_error_event func error_msg;
event e
end
end`
export const touchAndPay = `
scilla_version 0
(* This contract implements a fungible token interface a la ERC20.*)
(* This contract does not fire events *)
(***************************************************)
(* Associated library *)
(***************************************************)
library Test
let one_msg =
fun (msg : Message) =>
let nil_msg = Nil {Message} in
Cons {Message} msg nil_msg
let touched_code = Int32 0
(***************************************************)
(* The contract definition *)
(***************************************************)
contract Test
()
field touches : Map String Bool =
Emp String Bool
transition Touch(nonce: Uint64)
senderStr = builtin to_string _sender;
nonceStr = builtin to_string nonce;
key = builtin concat senderStr nonceStr;
true = True;
touches[key] := true;
msg = {_tag: "Main"; _recipient: _sender; amount: Uint128 0; code: touched_code};
msgs = one_msg msg;
send msgs
end
transition TouchAndPay(nonce: Uint64)
senderStr = builtin to_string _sender;
nonceStr = builtin to_string nonce;
key = builtin concat senderStr nonceStr;
true = True;
touches[key] := true;
accept;
msg = {_tag: "Main"; _recipient: _sender; amount: Uint128 0; code: touched_code};
msgs = one_msg msg;
send msgs
end
`