File Listing
Including all files mentioned in this post, the layout should look like this
test.sh
#! /bin/bash
set -e
test_file="$1"
this_script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
techel_lib="$this_script_dir/tests/techel.liq"
# List of all the contracts.
contracts=""
for file in `find "$this_script_dir/contracts" -iname "*.liq"` ; do
contracts="$contracts $file"
done
# File liquidity will compile to.
target="$test_file.techel"
echo "Compiling $test_file..."
echo
liquidity --no-annot --no-simplify --no-peephole $techel_lib $contracts -o $target $test_file
echo
# Running techelson on the target.
echo "Running test $target"
echo
techelson $target
tests/
tests/basic.liq
type storage = unit
let nothing : operation list * unit = [], ()
let%entry test (_param : unit) (_storage : unit) =
let delegate : key_hash option = None in
let operation, address =
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount:13tz
in
(* Apply the operation so that we can interact with the account. *)
Techel.apply_operations [operation];
(* Contract is now live. *)
let balance = Techel.get_balance address in
if balance <> 13tz then (
failwith "balance should be 13tz"
);
let account_contract =
match UnitContract.at address with
| None -> failwith "could not retrieve account"
| Some c -> c
in
let operation = Contract.call ~dest:account_contract ~amount:29tz ~parameter:() in
Techel.apply_operations [operation];
let balance = Techel.get_balance address in
if balance <> 42tz then (
failwith "balance should be 42tz"
);
nothing
tests/basic_err.liq
type storage = unit
let nothing : operation list * unit = [], ()
let%entry test (_param : unit) (_storage : unit) =
let delegate : key_hash option = None in
let operation, address =
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount:13tz
in
(* Apply the operation so that we can interact with the account. *)
Techel.apply_operations [operation];
(* Contract is now live. *)
let balance = Techel.get_balance address in
if balance <> 13tz then (
failwith "balance should be 13tz"
);
let account_contract =
match UnitContract.at address with
| None -> failwith "could not retrieve account"
| Some c -> c
in
let operation = Contract.call ~dest:account_contract ~amount:29tz ~parameter:() in
Techel.apply_operations [operation];
let balance = Techel.get_balance address in
if balance <> 12tz then (
failwith "balance should be 12tz"
);
nothing
tests/empty.liq
type storage = unit
let nothing : operation list * unit = [], ()
let%entry test (_param : unit) (_storage : unit) =
nothing
tests/techel.liq
external get_balance :
[%stack: address] -> [%stack: tez]
= "GET_BALANCE"
external get_storage :
[%type: 'a] -> [%stack: address] -> [%stack: 'a option]
= "GET_STORAGE"
external apply_operations :
[%stack: operation list] -> unit
= "APPLY_OPERATIONS"
external start_set_source :
[%stack: address] -> unit
= "SET_SOURCE { #"
external end_set_source :
unit -> unit
= "}"
external must_fail :
[%stack: string option] -> [%stack: operation] -> [%stack: operation]
= "MUST_FAIL string"
external print_stack :
unit -> unit
= "PRINT_STACK"
external step :
unit -> unit
= "STEP"
tests/test1.liq
let nothing : operation list * unit = [], ()
(* Creates a storage for Multi with one administrator. *)
let one_admin (root : string) (address : address) : Multi.storage = {
Multi.admins =
Map.add root address (Map : (string, address) map) ;
Multi.users =
(Map : (string, (address * tez * UnitContract.instance)) map) ;
}
(* Deploys an account with an arbitrary manager. *)
let deploy_account_op (amount: tez) : operation * address =
let delegate : key_hash option = None in
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount
(* Deploys an instance of multi with an arbitrary manager. *)
let deploy_contract_op (storage : Multi.storage) : operation * address =
let delegate : key_hash option = None in
Contract.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~spendable:false
~amount:0tz
~storage
~code:(contract Multi)
(* Storage of the test is irrelevant. *)
type storage = unit
(* Actual test. *)
let%entry test (_param : unit) (_storage : unit) =
let root_op, root = deploy_account_op 0tz in
let storage = one_admin "root" root in
let main_op, main = deploy_contract_op storage in
(* ask techelson to apply these operations. *)
Techel.apply_operations [ root_op ; main_op ];
(* root and main are live now *)
(* let's check root is an admin, and that the address is correct *)
let storage =
match Techel.get_storage [%type: Multi.storage] main with
| Some storage -> storage
| None -> failwith "can't retrieve contract's storage"
in
(
match Map.find "root" storage.Multi.admins with
| None -> failwith "no root in storage"
| Some address -> (
if address <> root then (
failwith "wrong address for root"
)
)
);
let client_op, client = deploy_account_op 15tz in
(* deploy the client *)
Techel.apply_operations [ client_op ];
(* client is live now *)
(* retrieve client instance for registration *)
let client_instance =
match (Contract.at client : UnitContract.instance option) with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* retrieve multi's instance to call it *)
let main_instance =
match Multi.at main with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* let's add a client *)
let bad_add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
let must_fail = Techel.must_fail None bad_add_client in
Techel.apply_operations [ must_fail ];
nothing
tests/test1_better.liq
let nothing : operation list * unit = [], ()
(* Creates a storage for Multi with one administrator. *)
let one_admin (root : string) (address : address) : Multi.storage = {
Multi.admins =
Map.add root address (Map : (string, address) map) ;
Multi.users =
(Map : (string, (address * tez * UnitContract.instance)) map) ;
}
(* Deploys an account with an arbitrary manager. *)
let deploy_account_op (amount: tez) : operation * address =
let delegate : key_hash option = None in
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount
(* Deploys an instance of multi with an arbitrary manager. *)
let deploy_contract_op (storage : Multi.storage) : operation * address =
let delegate : key_hash option = None in
Contract.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~spendable:false
~amount:0tz
~storage
~code:(contract Multi)
(* Storage of the test is irrelevant. *)
type storage = unit
(* Actual test. *)
let%entry test (_param : unit) (_storage : unit) =
let root_op, root = deploy_account_op 0tz in
let storage = one_admin "root" root in
let main_op, main = deploy_contract_op storage in
(* ask techelson to apply these operations. *)
Techel.apply_operations [ root_op ; main_op ];
(* root and main are live now *)
(* let's check root is an admin, and that the address is correct *)
let storage =
match Techel.get_storage [%type: Multi.storage] main with
| Some storage -> storage
| None -> failwith "can't retrieve contract's storage"
in
(
match Map.find "root" storage.Multi.admins with
| None -> failwith "no root in storage"
| Some address -> (
if address <> root then (
failwith "wrong address for root"
)
)
);
let client_op, client = deploy_account_op 15tz in
(* deploy the client *)
Techel.apply_operations [ client_op ];
(* client is live now *)
(* retrieve client instance for registration *)
let client_instance =
match (Contract.at client : UnitContract.instance option) with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* retrieve multi's instance to call it *)
let main_instance =
match Multi.at main with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* let's add a client *)
let bad_add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
let error_message = Some "illegal access to admin account" in
let must_fail = Techel.must_fail error_message bad_add_client in
Techel.apply_operations [ must_fail ];
nothing
tests/test1_err.liq
let nothing : operation list * unit = [], ()
(* Creates a storage for Multi with one administrator. *)
let one_admin (root : string) (address : address) : Multi.storage = {
Multi.admins =
Map.add root address (Map : (string, address) map) ;
Multi.users =
(Map : (string, (address * tez * UnitContract.instance)) map) ;
}
(* Deploys an account with an arbitrary manager. *)
let deploy_account_op (amount: tez) : operation * address =
let delegate : key_hash option = None in
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount
(* Deploys an instance of multi with an arbitrary manager. *)
let deploy_contract_op (storage : Multi.storage) : operation * address =
let delegate : key_hash option = None in
Contract.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~spendable:false
~amount:0tz
~storage
~code:(contract Multi)
(* Storage of the test is irrelevant. *)
type storage = unit
(* Actual test. *)
let%entry test (_param : unit) (_storage : unit) =
let root_op, root = deploy_account_op 0tz in
let storage = one_admin "root" root in
let main_op, main = deploy_contract_op storage in
(* ask techelson to apply these operations. *)
Techel.apply_operations [ root_op ; main_op ];
(* root and main are live now *)
(* let's check root is an admin, and that the address is correct *)
let storage =
match Techel.get_storage [%type: Multi.storage] main with
| Some storage -> storage
| None -> failwith "can't retrieve contract's storage"
in
(
match Map.find "root" storage.Multi.admins with
| None -> failwith "no root in storage"
| Some address -> (
if address <> root then (
failwith "wrong address for root"
)
)
);
let client_op, client = deploy_account_op 15tz in
(* deploy the client *)
Techel.apply_operations [ client_op ];
(* client is live now *)
(* retrieve client instance for registration *)
let client_instance =
match (Contract.at client : UnitContract.instance option) with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* retrieve multi's instance to call it *)
let main_instance =
match Multi.at main with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* let's add a client *)
let add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
Techel.apply_operations [ add_client ];
nothing
tests/test2.liq
let nothing : operation list * unit = [], ()
(* Creates a storage for Multi with one administrator. *)
let one_admin (root : string) (address : address) : Multi.storage = {
Multi.admins =
Map.add root address (Map : (string, address) map) ;
Multi.users =
(Map : (string, (address * tez * UnitContract.instance)) map) ;
}
(* Deploys an account with an arbitrary manager. *)
let deploy_account_op (amount: tez) : operation * address =
let delegate : key_hash option = None in
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount
(* Deploys an instance of multi with an arbitrary manager. *)
let deploy_contract_op (storage : Multi.storage) : operation * address =
let delegate : key_hash option = None in
Contract.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~spendable:false
~amount:0tz
~storage
~code:(contract Multi)
(* Storage of the test is irrelevant. *)
type storage = unit
(* Actual test. *)
let%entry test (_param : unit) (_storage : unit) =
let root_op, root = deploy_account_op 0tz in
let storage = one_admin "root" root in
let main_op, main = deploy_contract_op storage in
(* ask techelson to apply these operations. *)
Techel.apply_operations [ root_op ; main_op ];
(* root and main are live now *)
(* let's check root is an admin, and that the address is correct *)
let storage =
match Techel.get_storage [%type: Multi.storage] main with
| Some storage -> storage
| None -> failwith "can't retrieve contract's storage"
in
(
match Map.find "root" storage.Multi.admins with
| None -> failwith "no root in storage"
| Some address -> (
if address <> root then (
failwith "wrong address for root"
)
)
);
let client_op, client = deploy_account_op 15tz in
(* deploy the client *)
Techel.apply_operations [ client_op ];
(* client is live now *)
(* retrieve client instance for registration *)
let client_instance =
match (Contract.at client : UnitContract.instance option) with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* retrieve multi's instance to call it *)
let main_instance =
match Multi.at main with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* let's add a client and fail *)
let bad_add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
let error_message = Some "illegal access to admin account" in
let must_fail = Techel.must_fail error_message bad_add_client in
(* let's really add a client now *)
Techel.start_set_source root ;
(* all operations created in here will appear to have been created by `root` *)
let add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
Techel.end_set_source () ;
Techel.apply_operations [ must_fail ; add_client ];
nothing
tests/test3.liq
let nothing : operation list * unit = [], ()
(* Creates a storage for Multi with one administrator. *)
let one_admin (root : string) (address : address) : Multi.storage = {
Multi.admins =
Map.add root address (Map : (string, address) map) ;
Multi.users =
(Map : (string, (address * tez * UnitContract.instance)) map) ;
}
(* Deploys an account with an arbitrary manager. *)
let deploy_account_op (amount: tez) : operation * address =
let delegate : key_hash option = None in
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount
(* Deploys an instance of multi with an arbitrary manager. *)
let deploy_contract_op (storage : Multi.storage) : operation * address =
let delegate : key_hash option = None in
Contract.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~spendable:false
~amount:0tz
~storage
~code:(contract Multi)
(* Storage of the test is irrelevant. *)
type storage = unit
(* Actual test. *)
let%entry test (_param : unit) (_storage : unit) =
let root_op, root = deploy_account_op 0tz in
let storage = one_admin "root" root in
let main_op, main = deploy_contract_op storage in
(* ask techelson to apply these operations. *)
Techel.apply_operations [ root_op ; main_op ];
(* root and main are live now *)
(* let's check root is an admin, and that the address is correct *)
let storage =
match Techel.get_storage [%type: Multi.storage] main with
| Some storage -> storage
| None -> failwith "can't retrieve contract's storage"
in
(
match Map.find "root" storage.Multi.admins with
| None -> failwith "no root in storage"
| Some address -> (
if address <> root then (
failwith "wrong address for root"
)
)
);
let client_op, client = deploy_account_op 15tz in
(* deploy the client *)
Techel.apply_operations [ client_op ];
(* client is live now *)
(* retrieve client instance for registration *)
let client_instance =
match (Contract.at client : UnitContract.instance option) with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* retrieve multi's instance to call it *)
let main_instance =
match Multi.at main with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* let's add a client and fail *)
let bad_add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
let error_message = Some "illegal access to admin account" in
let must_fail = Techel.must_fail error_message bad_add_client in
(* let's really add a client now *)
Techel.start_set_source root ;
(* all operations created in here will appear to have been created by `root` *)
let add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
Techel.end_set_source () ;
Techel.apply_operations [ must_fail ; add_client ];
(* lucy deposits `10tz` *)
Techel.start_set_source client ;
let deposit_money =
Contract.call ~dest:main_instance ~amount:10tz ~entry:deposit ~parameter:"lucy"
in
Techel.end_set_source () ;
Techel.apply_operations [ deposit_money ];
let balance_lucy = Techel.get_balance client in
if balance_lucy <> 5tz then (
failwith "lucy should have 5tz now"
);
(* lucy walks out of the whole thing *)
Techel.start_set_source client ;
let drain =
Contract.call ~dest:main_instance ~amount:0tz ~entry:drain ~parameter:"lucy"
in
Techel.end_set_source () ;
Techel.apply_operations [ drain ] ;
(* lucy should have her money back *)
let balance_lucy = Techel.get_balance client in
if balance_lucy <> 15tz then (
failwith "lucy should have 15tz now"
);
nothing
tests/test3_err.liq
let nothing : operation list * unit = [], ()
(* Creates a storage for Multi with one administrator. *)
let one_admin (root : string) (address : address) : Multi.storage = {
Multi.admins =
Map.add root address (Map : (string, address) map) ;
Multi.users =
(Map : (string, (address * tez * UnitContract.instance)) map) ;
}
(* Deploys an account with an arbitrary manager. *)
let deploy_account_op (amount: tez) : operation * address =
let delegate : key_hash option = None in
Account.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~amount
(* Deploys an instance of multi with an arbitrary manager. *)
let deploy_contract_op (storage : Multi.storage) : operation * address =
let delegate : key_hash option = None in
Contract.create
~manager:tz1YLtLqD1fWHthSVHPD116oYvsd4PTAHUoc
~delegate
~delegatable:true
~spendable:false
~amount:0tz
~storage
~code:(contract Multi)
(* Storage of the test is irrelevant. *)
type storage = unit
(* Actual test. *)
let%entry test (_param : unit) (_storage : unit) =
let root_op, root = deploy_account_op 0tz in
let storage = one_admin "root" root in
let main_op, main = deploy_contract_op storage in
(* ask techelson to apply these operations. *)
Techel.apply_operations [ root_op ; main_op ];
(* root and main are live now *)
(* let's check root is an admin, and that the address is correct *)
let storage =
match Techel.get_storage [%type: Multi.storage] main with
| Some storage -> storage
| None -> failwith "can't retrieve contract's storage"
in
(
match Map.find "root" storage.Multi.admins with
| None -> failwith "no root in storage"
| Some address -> (
if address <> root then (
failwith "wrong address for root"
)
)
);
let client_op, client = deploy_account_op 15tz in
(* deploy the client *)
Techel.apply_operations [ client_op ];
(* client is live now *)
(* retrieve client instance for registration *)
let client_instance =
match (Contract.at client : UnitContract.instance option) with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* retrieve multi's instance to call it *)
let main_instance =
match Multi.at main with
| None -> failwith "could not retrieve main contract"
| Some instance -> instance
in
(* let's add a client and fail *)
let bad_add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
let error_message = Some "illegal access to admin account" in
let must_fail = Techel.must_fail error_message bad_add_client in
(* let's really add a client now *)
Techel.start_set_source root ;
(* all operations created in here will appear to have been created by `root` *)
let add_client =
Contract.call ~dest:main_instance ~amount:0tz ~entry:add_client ~parameter:(
"root", "lucy", client, client_instance
)
in
Techel.end_set_source () ;
Techel.apply_operations [ must_fail ; add_client ];
(* lucy deposits `10tz` *)
Techel.start_set_source client ;
let deposit_money =
Contract.call ~dest:main_instance ~amount:10tz ~entry:deposit ~parameter:"lucy"
in
Techel.end_set_source () ;
Techel.apply_operations [ deposit_money ];
let balance_lucy = Techel.get_balance client in
if balance_lucy <> 5tz then (
failwith "lucy should have 5tz now"
);
(* lucy walks out of the whole thing *)
Techel.start_set_source client ;
let drain =
Contract.call ~dest:main_instance ~amount:0tz ~entry:drain ~parameter:"lucy"
in
Techel.end_set_source () ;
Techel.apply_operations [ drain ] ;
(* lucy should have her money back *)
let balance_lucy = Techel.get_balance client in
if balance_lucy <> 2tz then (
failwith "lucy should have 2tz now"
);
nothing
contracts/
contracts/multi.liq
type storage = {
admins : (string, address) map ;
users : (string, (address * tez * UnitContract.instance)) map ;
}
let admin_check (storage : storage) (name : string) (a : address) : unit =
match Map.find name storage.admins with
| None -> failwith "only admins can perform administrative tasks"
| Some address ->
if address <> a then
failwith "illegal access to admin account"
let%entry add_admin
(
(admin_name, nu_admin_name, nu_admin_address) :
string * string * address
) (
storage : storage
)
: operation list * storage
=
admin_check storage admin_name (Current.sender ());
let storage =
storage.admins <- Map.update nu_admin_name (Some nu_admin_address) storage.admins
in
[], storage
let%entry rm_admin (admin_name, user_name : string * string) (storage : storage) =
admin_check storage admin_name (Current.sender ());
let storage = storage.admins <- Map.update user_name None storage.admins in
[], storage
let%entry add_client (
(admin_name, user_name, user, c) :
string * string * address * UnitContract.instance
) (storage : storage) =
admin_check storage admin_name (Current.sender ());
if Map.mem user_name storage.users then (
failwith "username already taken"
);
let data = Some (user, 0tz, c) in
let storage = storage.users <- Map.update user_name data storage.users in
[], storage
let data_of (storage : storage) (name : string) (user : address) : tez * UnitContract.instance =
match Map.find name storage.users with
| None -> failwith "unknown user"
| Some (address, tez, c) ->
if user <> address then
failwith "illegal access to account"
else (tez, c)
let%entry deposit (name : string) (storage : storage) =
let user = Current.sender () in
let money, c = data_of storage name user in
let amount = Current.amount () in
let nu_data = Some (user, money + amount, c) in
[], storage.users <- Map.update name nu_data storage.users
let%entry withdraw (name, amount : string * tez) (storage : storage) =
let user = Current.sender () in
let money, c = data_of storage name user in
if amount > money then
failwith "insufficient balance"
else (
let nu_data = Some (user, money - amount, c) in
[], storage.users <- Map.update name nu_data storage.users
)
let%entry drain (name : string) (storage : storage) =
let user = Current.sender () in
let money, c = data_of storage name user in
let storage = storage.users <- Map.update name None storage.users in
let ops = [Contract.call ~dest:c ~amount:money ~parameter:()] in
ops, storage