From 96953d98955c44a008fe2f659c4e99ff45823db6 Mon Sep 17 00:00:00 2001 From: Milo Davis Date: Mon, 30 Oct 2017 10:22:16 +0100 Subject: [PATCH] Michelson: Adds typechecking test for michelson-lang.com contracts --- test/contracts/accounts.tz | 42 ++++++++++++++++++++++ test/contracts/add1.tz | 10 ++++++ test/contracts/add1_list.tz | 9 +++++ test/contracts/after_strategy.tz | 4 +++ test/contracts/always.tz | 6 ++++ test/contracts/append.tz | 15 ++++++++ test/contracts/at_least.tz | 7 ++++ test/contracts/auction.tz | 9 +++++ test/contracts/bad_lockup.tz | 6 ++++ test/contracts/concat.tz | 11 ++++++ test/contracts/conditionals.tz | 11 ++++++ test/contracts/cons_twice.tz | 12 +++++++ test/contracts/create_add1_lists.tz | 22 ++++++++++++ test/contracts/data_publisher.tz | 15 ++++++++ test/contracts/dispatch.tz | 9 +++++ test/contracts/empty.tz | 5 +++ test/contracts/id.tz | 5 +++ test/contracts/infinite_loop.tz | 4 +++ test/contracts/insertion_sort.tz | 27 ++++++++++++++ test/contracts/int_publisher.tz | 21 +++++++++++ test/contracts/king_of_tez.tz | 18 ++++++++++ test/contracts/list_of_transactions.tz | 9 +++++ test/contracts/lockup.tz | 18 ++++++++++ test/contracts/min.tz | 13 +++++++ test/contracts/parameterizable_payments.tz | 26 ++++++++++++++ test/contracts/parameterized_multisig.tz | 24 +++++++++++++ test/contracts/publisher_payouts.tz | 17 +++++++++ test/contracts/queue.tz | 24 +++++++++++++ test/contracts/reduce_map.tz | 22 ++++++++++++ test/contracts/reentrancy.tz | 6 ++++ test/contracts/spawn_identities.tz | 27 ++++++++++++++ test/contracts/strategy_proxy.tz | 9 +++++ test/contracts/subset.tz | 18 ++++++++++ test/contracts/swap_storage_input.tz | 9 +++++ test/contracts/swap_storage_input_dip.tz | 8 +++++ test/contracts/take_my_money.tz | 9 +++++ test/contracts/two_vulnerabilities.tz | 7 ++++ test/test_contracts.sh | 6 ++++ 38 files changed, 520 insertions(+) create mode 100644 test/contracts/accounts.tz create mode 100644 test/contracts/add1.tz create mode 100644 test/contracts/add1_list.tz create mode 100644 test/contracts/after_strategy.tz create mode 100644 test/contracts/always.tz create mode 100644 test/contracts/append.tz create mode 100644 test/contracts/at_least.tz create mode 100644 test/contracts/auction.tz create mode 100644 test/contracts/bad_lockup.tz create mode 100644 test/contracts/concat.tz create mode 100644 test/contracts/conditionals.tz create mode 100644 test/contracts/cons_twice.tz create mode 100644 test/contracts/create_add1_lists.tz create mode 100644 test/contracts/data_publisher.tz create mode 100644 test/contracts/dispatch.tz create mode 100644 test/contracts/empty.tz create mode 100644 test/contracts/id.tz create mode 100644 test/contracts/infinite_loop.tz create mode 100644 test/contracts/insertion_sort.tz create mode 100644 test/contracts/int_publisher.tz create mode 100644 test/contracts/king_of_tez.tz create mode 100644 test/contracts/list_of_transactions.tz create mode 100644 test/contracts/lockup.tz create mode 100644 test/contracts/min.tz create mode 100644 test/contracts/parameterizable_payments.tz create mode 100644 test/contracts/parameterized_multisig.tz create mode 100644 test/contracts/publisher_payouts.tz create mode 100644 test/contracts/queue.tz create mode 100644 test/contracts/reduce_map.tz create mode 100644 test/contracts/reentrancy.tz create mode 100644 test/contracts/spawn_identities.tz create mode 100644 test/contracts/strategy_proxy.tz create mode 100644 test/contracts/subset.tz create mode 100644 test/contracts/swap_storage_input.tz create mode 100644 test/contracts/swap_storage_input_dip.tz create mode 100644 test/contracts/take_my_money.tz create mode 100644 test/contracts/two_vulnerabilities.tz diff --git a/test/contracts/accounts.tz b/test/contracts/accounts.tz new file mode 100644 index 000000000..fe1a45da8 --- /dev/null +++ b/test/contracts/accounts.tz @@ -0,0 +1,42 @@ +# This is a very simple accounts system. +# (Left key) initializes or deposits into an account +# (Right key (pair tez (signed tez))) withdraws tez amount to a +# DEFAULT_ACCOUNT created from the key if the balance is available +# and the key is correctly signed +parameter (or key_hash (pair key (pair tez signature))); +# Maps the key to the balance they have stored +storage (map key_hash tez); +return unit; +code { DUP; CAR; + # Deposit into account + IF_LEFT { DUP; DIIP{ CDR; DUP }; + DIP{ SWAP }; GET; + # Create the account + IF_NONE { DIP{ AMOUNT; SOME }; UPDATE; UNIT; PAIR } + # Add to an existing account + { AMOUNT; ADD; SOME; SWAP; UPDATE; UNIT; PAIR }} + # Withdrawl + { DUP; DUP; DUP; DUP; + # Check signature on data + CAR; DIIP{ CDAR; H }; DIP{ CDDR; PAIR }; CHECK_SIGNATURE; + IF {} { FAIL }; + # Get user account information + DIIP{ CDR; DUP }; CAR; HASH_KEY; DIP{ SWAP }; GET; + # Account does not exist + IF_NONE { FAIL } + # Account exists + { DUP; DIIP{ DUP; CDAR; DUP }; + # Ensure funds are available + DIP{ CMPLT }; SWAP; + IF { FAIL } + { SUB; DIP{ DUP; DIP{ SWAP }}; DUP; + # Delete account if balance is 0 + PUSH tez "0.00"; CMPEQ; + IF { DROP; NONE tez } + # Otherwise update storage with new balance + { SOME }; + SWAP; CAR; HASH_KEY; UPDATE; + SWAP; DUP; CDAR; + # Execute the transfer + DIP{ CAR; HASH_KEY; DEFAULT_ACCOUNT }; UNIT; TRANSFER_TOKENS; + PAIR }}}} diff --git a/test/contracts/add1.tz b/test/contracts/add1.tz new file mode 100644 index 000000000..858f70263 --- /dev/null +++ b/test/contracts/add1.tz @@ -0,0 +1,10 @@ + +parameter int; +storage unit; +return int; +code {CAR; # Get the parameter + PUSH int 1; # We're adding 1, so we need to put 1 on the stack + ADD; # Add the two numbers + UNIT; # We need to put the storage value on the stack + SWAP; # The values must be rearranged to match the return calling convention + PAIR} # Create the end value diff --git a/test/contracts/add1_list.tz b/test/contracts/add1_list.tz new file mode 100644 index 000000000..811ba38b1 --- /dev/null +++ b/test/contracts/add1_list.tz @@ -0,0 +1,9 @@ +parameter (list int); +storage unit; +return (list int); +code { CAR; # Get the parameter + LAMBDA int int { PUSH int 1; ADD }; # Create a lambda that adds 1 + MAP; # Map over the list + UNIT; # Push Unit + SWAP; # Reorder the stack for the PAIR + PAIR } # Match the calling convetion diff --git a/test/contracts/after_strategy.tz b/test/contracts/after_strategy.tz new file mode 100644 index 000000000..51e199707 --- /dev/null +++ b/test/contracts/after_strategy.tz @@ -0,0 +1,4 @@ +parameter nat; +storage timestamp; +return (pair nat bool); +code {DUP; CAR; DIP{CDR; DUP; NOW; CMPGT}; PAIR; PAIR}; diff --git a/test/contracts/always.tz b/test/contracts/always.tz new file mode 100644 index 000000000..a578996b2 --- /dev/null +++ b/test/contracts/always.tz @@ -0,0 +1,6 @@ + +parameter nat; +return (pair nat bool); +storage unit; +code { CAR; PUSH bool True; SWAP; + PAIR; UNIT; SWAP; PAIR} diff --git a/test/contracts/append.tz b/test/contracts/append.tz new file mode 100644 index 000000000..e3dcbc1b9 --- /dev/null +++ b/test/contracts/append.tz @@ -0,0 +1,15 @@ + +parameter (pair (list int) (list int)); +return (list int); +storage unit; +code { CAR; DUP; DIP{CDR}; CAR; # Unpack lists + NIL int; SWAP; # Setup reverse accumulator + LAMBDA (pair int (list int)) + (list int) + {DUP; CAR; DIP{CDR}; CONS}; + REDUCE; # Reverse list + LAMBDA (pair int (list int)) + (list int) + {DUP; CAR; DIP{CDR}; CONS}; + REDUCE; # Append reversed list + UNIT; SWAP; PAIR} # Calling convention diff --git a/test/contracts/at_least.tz b/test/contracts/at_least.tz new file mode 100644 index 000000000..ae2180860 --- /dev/null +++ b/test/contracts/at_least.tz @@ -0,0 +1,7 @@ + +parameter unit; +return unit; +storage tez; # How much you have to send me +code {CDR; DUP; # Get the amount required (once for comparison, once to save back in storage) + AMOUNT; CMPLT; # Check to make sure no one is wasting my time + IF {FAIL} {UNIT; PAIR}} # Finish the transaction or reject the person diff --git a/test/contracts/auction.tz b/test/contracts/auction.tz new file mode 100644 index 000000000..5ebbfd2f6 --- /dev/null +++ b/test/contracts/auction.tz @@ -0,0 +1,9 @@ +parameter key_hash; +storage (pair timestamp (pair tez key_hash)); +return unit; +code { DUP; CDAR; DUP; NOW; CMPGT; IF {FAIL} {}; SWAP; # Check if auction has ended + DUP; CAR; DIP{CDDR}; AMOUNT; PAIR; SWAP; DIP{SWAP; PAIR}; # Setup replacement storage + DUP; CAR; AMOUNT; CMPLE; IF {FAIL} {}; # Check to make sure that the new amount is greater + DUP; CAR; # Get amount of refund + DIP{CDR; DEFAULT_ACCOUNT}; UNIT; TRANSFER_TOKENS; # Make refund + PAIR} # Calling convention diff --git a/test/contracts/bad_lockup.tz b/test/contracts/bad_lockup.tz new file mode 100644 index 000000000..7ccd27993 --- /dev/null +++ b/test/contracts/bad_lockup.tz @@ -0,0 +1,6 @@ +parameter unit; +storage (pair timestamp (pair (contract unit unit) (contract unit unit))); +return unit; +code { CDR; DUP; CAR; NOW; CMPLT; IF {FAIL} {}; + DUP; CDAR; PUSH tez "100"; UNIT; TRANSFER_TOKENS; DROP; + DUP; CDDR; PUSH tez "100"; UNIT; TRANSFER_TOKENS; PAIR } diff --git a/test/contracts/concat.tz b/test/contracts/concat.tz new file mode 100644 index 000000000..203d03b12 --- /dev/null +++ b/test/contracts/concat.tz @@ -0,0 +1,11 @@ + +parameter string; +storage string; +return string; +code {DUP; # We're going to need both the storage and parameter + CAR; # Get the parameter + DIP{CDR; # Get the storage value + DUP}; # We need to replace it in the storage, so we dup it + SWAP; # Get the order we want (this is optional) + CONCAT; # Concatenate the strings + PAIR} # Pair them up, matching the calling convention diff --git a/test/contracts/conditionals.tz b/test/contracts/conditionals.tz new file mode 100644 index 000000000..740e6bc82 --- /dev/null +++ b/test/contracts/conditionals.tz @@ -0,0 +1,11 @@ + +parameter (or string (option int)); +storage unit; +return string; +code { CAR; # Access the storage + IF_LEFT {} # The string is on top of the stack, nothing to do + { IF_NONE { FAIL} # Fail if None + { PUSH int 0; CMPGT; # Check for negative number + IF {FAIL} # Fail if negative + {PUSH string ""}}}; # Push the empty string + UNIT; SWAP; PAIR} # Calling convention diff --git a/test/contracts/cons_twice.tz b/test/contracts/cons_twice.tz new file mode 100644 index 000000000..d0894f00f --- /dev/null +++ b/test/contracts/cons_twice.tz @@ -0,0 +1,12 @@ + +parameter nat; +storage (list nat); +return unit; +code { DUP; # Duplicate the storage and parameter + CAR; # Extract the parameter + DIP{CDR}; # Extract the storage + DUP; # Duplicate the parameter + DIP{CONS}; # Add the first instance of the parameter to the list + CONS; # Add the second instance of the parameter to the list + PUSH unit Unit; # Put the value Unit on the stack (calling convention) + PAIR} # Finish the calling convention diff --git a/test/contracts/create_add1_lists.tz b/test/contracts/create_add1_lists.tz new file mode 100644 index 000000000..43ea501d6 --- /dev/null +++ b/test/contracts/create_add1_lists.tz @@ -0,0 +1,22 @@ +parameter unit; +return (contract (list int) (list int)); +storage unit; +code { CAR; # Get the UNIT value (starting storage for contract) + LAMBDA (pair (list int) unit) # Start of stack for contract (see above) + (pair (list int) unit) # End of stack for contract (see above) + # See the contract above. I copied and pasted + { CAR; + LAMBDA int int {PUSH int 1; ADD}; + MAP; + UNIT; + SWAP; + PAIR }; + AMOUNT; # Push the starting balance + PUSH bool False; # Not spendable + DUP; # Or delegatable + NONE key_hash; # No delegate + PUSH key_hash "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"; + CREATE_CONTRACT; # Create the contract + UNIT; # Ending calling convention stuff + SWAP; + PAIR} diff --git a/test/contracts/data_publisher.tz b/test/contracts/data_publisher.tz new file mode 100644 index 000000000..25f7b0c82 --- /dev/null +++ b/test/contracts/data_publisher.tz @@ -0,0 +1,15 @@ + +# NONE if user wants to get the value +# SOME (signed hash of the string, string) +parameter (option (pair signature (pair string nat))); +return string; +storage (pair (pair key nat) string); +code { DUP; CAR; DIP{CDR; DUP}; + IF_NONE { AMOUNT; PUSH tez "1.00"; # The fee I'm charging for queries + CMPLE; IF {} {FAIL}; + CDR; PAIR} + { SWAP; DIP{DUP}; CAAR; DIP{DUP; CAR; DIP{CDR; H}; PAIR}; + CHECK_SIGNATURE; + IF { CDR; DUP; DIP{CAR; DIP{CAAR}}; CDR; PUSH nat 1; ADD; + DIP{SWAP}; SWAP; PAIR; PAIR; PUSH string ""; PAIR} + {FAIL}}} diff --git a/test/contracts/dispatch.tz b/test/contracts/dispatch.tz new file mode 100644 index 000000000..6f4fc468e --- /dev/null +++ b/test/contracts/dispatch.tz @@ -0,0 +1,9 @@ +parameter (or string (pair string (lambda unit string))); +return string; +storage (map string (lambda unit string)); +code { DUP; DIP{CDR}; CAR; # Unpack stack + IF_LEFT { DIP{DUP}; GET; # Get lambda if it exists + IF_NONE {FAIL} {}; # Fail if it doesn't + UNIT; EXEC } # Execute the lambda + { DUP; CAR; DIP {CDR; SOME}; UPDATE; PUSH string ""}; # Update the storage + PAIR} # Calling convention diff --git a/test/contracts/empty.tz b/test/contracts/empty.tz new file mode 100644 index 000000000..0edda09b3 --- /dev/null +++ b/test/contracts/empty.tz @@ -0,0 +1,5 @@ + +parameter unit; +storage unit; +return unit; +code {} diff --git a/test/contracts/id.tz b/test/contracts/id.tz new file mode 100644 index 000000000..ae9b9612e --- /dev/null +++ b/test/contracts/id.tz @@ -0,0 +1,5 @@ + +parameter string; +return string; +storage unit; +code {}; diff --git a/test/contracts/infinite_loop.tz b/test/contracts/infinite_loop.tz new file mode 100644 index 000000000..dc78d4d33 --- /dev/null +++ b/test/contracts/infinite_loop.tz @@ -0,0 +1,4 @@ +parameter unit; +storage unit; +return unit; +code { DROP; PUSH bool True; LOOP {PUSH bool True}; UNIT; UNIT; PAIR } diff --git a/test/contracts/insertion_sort.tz b/test/contracts/insertion_sort.tz new file mode 100644 index 000000000..47c7014f4 --- /dev/null +++ b/test/contracts/insertion_sort.tz @@ -0,0 +1,27 @@ + +parameter (list int); +return (list int); +storage unit; +code { CAR; # Access list + # Insert procedure + LAMBDA (pair int (list int)) + (list int) + { DUP; CDR; DIP{CAR}; # Unpack accumulator and existing list + DIIP{NIL int}; PUSH bool True; # Setup loop + LOOP { IF_CONS { SWAP; + DIP{DUP; DIIP{DUP}; DIP{CMPLT}; SWAP}; # Duplicate numbers + SWAP; + # If less than + IF { DIP{SWAP; DIP{CONS}}; PUSH bool True} + # Otherwise + { SWAP; CONS; PUSH bool False}} + # Ending case + { NIL int; PUSH bool False}}; + SWAP; CONS; SWAP; # Finish lists + LAMBDA (pair int (list int)) + (list int) + {DUP; CAR; DIP{CDR}; CONS}; + REDUCE}; + NIL int; SWAP; DIP{SWAP}; # Accumulator for reverse onto + REDUCE; # Execute reverse onto + UNIT; SWAP; PAIR} # Calling convention diff --git a/test/contracts/int_publisher.tz b/test/contracts/int_publisher.tz new file mode 100644 index 000000000..db8da7c10 --- /dev/null +++ b/test/contracts/int_publisher.tz @@ -0,0 +1,21 @@ +# NONE if user wants to get the value +# SOME (signed hash of the string, string) +parameter (option (pair signature int)); +return int; +# The key used to update the contract +# The data +storage (pair key int); +code {DUP; DUP; CAR; + IF_NONE {PUSH tez "1.00"; # Fee pattern from July 26 + AMOUNT; CMPLE; IF {FAIL} {}; + # Provide the data + CDR; DIP {CDDR}} + {DUP; DIP{SWAP}; SWAP; CDAR; # Move key to the top + DIP {DUP; CAR; DIP {CDR; H}; PAIR}; # Arrange the new piece of data + CHECK_SIGNATURE; # Check to ensure the data is authentic + # Update data + IF {CDR; SWAP; DIP{DUP}; CDAR; PAIR} + # Revert the update. This could be replaced with FAIL + {DROP; DUP; CDR; DIP{CDDR}}}; + # Cleanup + SWAP; PAIR} diff --git a/test/contracts/king_of_tez.tz b/test/contracts/king_of_tez.tz new file mode 100644 index 000000000..899fff0cb --- /dev/null +++ b/test/contracts/king_of_tez.tz @@ -0,0 +1,18 @@ +parameter key_hash; +storage (pair timestamp (pair tez key_hash)); +return unit; +code { DUP; CDAR; + # If the time is more than 2 weeks, any amount makes you king + NOW; CMPGT; + # User becomes king of tez + IF { CAR; AMOUNT; PAIR; NOW; PUSH int 604800; ADD; PAIR } + # Check balance to see if user has paid enough to become the new king + { DUP; CDDAR; AMOUNT; CMPLT; + IF { FAIL } # user has not paid out + { CAR; DUP; + # New storage + DIP{ AMOUNT; PAIR; NOW; PUSH int 604800; ADD; PAIR }; + # Pay funds to old king + DEFAULT_ACCOUNT; AMOUNT; UNIT; TRANSFER_TOKENS; DROP }}; + # Cleanup + UNIT; PAIR }; diff --git a/test/contracts/list_of_transactions.tz b/test/contracts/list_of_transactions.tz new file mode 100644 index 000000000..1be3259e3 --- /dev/null +++ b/test/contracts/list_of_transactions.tz @@ -0,0 +1,9 @@ + +parameter unit; +storage (list (contract unit unit)); +return unit; +code { CDR; PUSH bool True; # Setup loop + LOOP {IF_CONS { PUSH tez "1.00"; UNIT; TRANSFER_TOKENS; # Make transfer + DROP; PUSH bool True} # Setup for next round of loop + { NIL (contract unit unit); PUSH bool False}}; # Data to satisfy types and end loop + UNIT; PAIR}; # Calling convention diff --git a/test/contracts/lockup.tz b/test/contracts/lockup.tz new file mode 100644 index 000000000..5b3f68516 --- /dev/null +++ b/test/contracts/lockup.tz @@ -0,0 +1,18 @@ +parameter unit; +storage (pair timestamp (pair tez (contract unit unit))); +return unit; +code { CDR; # Ignore the parameter + DUP; # Duplicate the storage + CAR; # Get the timestamp + NOW; # Push the current timestamp + CMPLT; # Compare to the current time + IF {FAIL} {}; # Fail if it is too soon + DUP; # Duplicate the storage value + # this must be on the bottom of the stack for us to call transfer tokens + CDR; # Ignore the timestamp, focussing in on the tranfser data + DUP; # Duplicate the transfer information + CAR; # Get the amount of the transfer on top of the stack + DIP{CDR}; # Put the contract underneath it + UNIT; # Put the contract's argument type on top of the stack + TRANSFER_TOKENS; # Make the transfer + PAIR} # Pair up to meet the calling convention diff --git a/test/contracts/min.tz b/test/contracts/min.tz new file mode 100644 index 000000000..5a7ac2643 --- /dev/null +++ b/test/contracts/min.tz @@ -0,0 +1,13 @@ + +parameter (pair int int); +return int; +storage unit; +code { CAR; # Ignore the storage + DUP; # Duplicate so we can get both the numbers passed as parameters + DUP; # Second dup so we can access the lesser number + CAR; DIP{CDR}; # Unpack the numbers on top of the stack + CMPLT; # Compare the two numbers, placing a boolean on top of the stack + IF {CAR} {CDR}; # Access the first number if the boolean was true + UNIT; # Push storage value + SWAP; # Correct order for calling convention pair + PAIR} # Pair the numbers satisfying the calling convention diff --git a/test/contracts/parameterizable_payments.tz b/test/contracts/parameterizable_payments.tz new file mode 100644 index 000000000..2d95dafe2 --- /dev/null +++ b/test/contracts/parameterizable_payments.tz @@ -0,0 +1,26 @@ +parameter (or (pair string (pair tez (contract unit unit))) nat); +return unit; +storage (pair (contract nat (pair nat bool)) (pair nat (map nat (pair string (pair tez (contract unit unit)))))); +code { DUP; DIP{CDR}; CAR; # Get the input while preserving the output + IF_LEFT { DIP{ DUP; CAR; SWAP; CDR; DUP; CAR; DIP{CDR}}; + SOME; SWAP; DUP; DIP{UPDATE}; # Add the element to the map + PUSH nat 1; ADD; PAIR; SWAP; # Add 1 to the index + PAIR; UNIT; PAIR} # Cleanup and finish + # Check our other contract to see if the transaction is allowed + { DIP{DUP; CAR}; PUSH tez "0.00"; SWAP; TRANSFER_TOKENS; + # Arrange the stack + DUP; CDR; + IF { CAR; DUP; DIIP{DUP; CDDR; DUP}; + DIP{ GET; # Get the value of the data + IF_NONE {FAIL} {}; # This should not happen + SWAP; + NONE (pair string (pair tez (contract unit unit)))}; + UPDATE; # Delete the element + SWAP; + # More stack arranging + DIP{ SWAP; DUP; CAR; DIP{CDR}}; + DIP{DIP{CAR; PAIR}; PAIR}; + DUP; CDAR; + DIP{CDDR}; UNIT; TRANSFER_TOKENS; # Make the transfer + PAIR} + { FAIL }}} diff --git a/test/contracts/parameterized_multisig.tz b/test/contracts/parameterized_multisig.tz new file mode 100644 index 000000000..22c7f94ac --- /dev/null +++ b/test/contracts/parameterized_multisig.tz @@ -0,0 +1,24 @@ +storage (pair (map nat (pair bool bool)) (pair key key)); +return bool; +parameter (or nat (pair signature nat)); +code { DUP; CAR; DIP{CDR}; # Stack rangling + IF_LEFT { DIP{DUP; CAR}; GET; # Get the value stored for that index + IF_NONE { PUSH bool False} # If not referenced, reject + { DUP; CAR; DIP{CDR}; AND}; + PAIR} + { DUP; CAR; DIP{CDR; DUP; H}; PAIR; SWAP; # Create the signature pair + DIP{ DIP{DUP; CDR; DIP{CAR}; DUP}; + SWAP; CAR; DIP{DUP}; CHECK_SIGNATURE }; # Check the first signature + SWAP; + # If the signature typechecked, get and update the first element of the pair + IF { DIP{DROP; SWAP; DUP}; DUP; + DIP{ GET; IF_NONE{PUSH (pair bool bool) (Pair False False)} {}; + CDR; PUSH bool True; PAIR; SOME }} + # Check the second signature + { DIP{DIP{DUP; CDR}; SWAP; CHECK_SIGNATURE}; SWAP; + IF { DUP; DIP{DIP{SWAP; DUP}; GET}; SWAP; + IF_NONE {PUSH (pair bool bool) (Pair False False)} {}; + CAR; PUSH bool True; SWAP; PAIR; SOME; SWAP} + {FAIL}}; + # Update the stored value and finish off + UPDATE; PAIR; PUSH bool False; PAIR}} diff --git a/test/contracts/publisher_payouts.tz b/test/contracts/publisher_payouts.tz new file mode 100644 index 000000000..15bca5d55 --- /dev/null +++ b/test/contracts/publisher_payouts.tz @@ -0,0 +1,17 @@ +parameter unit; +storage (option + (pair (pair (contract unit unit) (contract unit unit)) + (pair (pair timestamp (contract (option (pair signature int)) int)) + (pair tez int)))); +return unit; +code { CDR; IF_NONE {FAIL} {}; # Check if settlement has already ocurred + DUP; CDAAR; NOW; CMPLT; IF {FAIL} {}; # Check the timestamp + DUP; CDADR; DIP{SOME}; PUSH tez "1.01"; NONE (pair signature int); + TRANSFER_TOKENS; DIP{IF_NONE{FAIL} {}}; + DIP{DUP; CDDR; DUP; CDR}; CMPGT; + SWAP; + DIP{ IF {CAAR} {CADR}; + DIP{ NONE (pair (pair (contract unit unit) (contract unit unit)) + (pair (pair timestamp (contract (option (pair signature int)) int)) + (pair tez int)))}}; + CAR; UNIT; TRANSFER_TOKENS; PAIR} diff --git a/test/contracts/queue.tz b/test/contracts/queue.tz new file mode 100644 index 000000000..10a894fea --- /dev/null +++ b/test/contracts/queue.tz @@ -0,0 +1,24 @@ +parameter (option string); +storage (pair (pair nat nat) (map nat string)); +return (option string); +code { DUP; CAR; + # Retrieving an element + IF_NONE { CDR; DUP; CAR; DIP{CDR; DUP}; DUP; + CAR; SWAP; DIP{GET}; # Check if an element is available + SWAP; + # Put NONE on stack and finish + IF_NONE { NONE string; DIP{PAIR}; PAIR} + # Reoption the element and remove the entry from the map + { SOME; + DIP{ DUP; DIP{ CAR; DIP{ NONE string }; UPDATE }; + # Increment the counter and cleanup + DUP; CAR; PUSH nat 1; ADD; DIP{ CDR }; PAIR; PAIR}; + PAIR }} + # Arrange the stack + { DIP{DUP; CDAR; DIP{CDDR}; DUP}; SWAP; CAR; + # Add the element to the map + DIP{ SOME; SWAP; CDR; DUP; DIP{UPDATE}; + # Increment the second number + PUSH nat 1; ADD}; + # Cleanup and finish + PAIR; PAIR; NONE string; PAIR }} diff --git a/test/contracts/reduce_map.tz b/test/contracts/reduce_map.tz new file mode 100644 index 000000000..f112ff283 --- /dev/null +++ b/test/contracts/reduce_map.tz @@ -0,0 +1,22 @@ + +parameter (pair (lambda int int) (list int)); +return (list int); +storage unit; +code { DIP{NIL int}; + CAR; + DUP; + DIP{CAR; PAIR}; # Unpack data and setup accumulator + CDR; + LAMBDA (pair int (pair (lambda int int) (list int))) + (pair (lambda int int) (list int)) + # Apply the lambda and add the new element to the list + { DUP; CDAR; + DIP{ DUP; DIP{CDAR}; DUP; + CAR; DIP{CDDR; SWAP}; EXEC; CONS}; + PAIR}; + REDUCE; CDR; DIP{NIL int}; # First reduce + LAMBDA (pair int (list int)) + (list int) + {DUP; CAR; DIP{CDR}; CONS}; + REDUCE; # Correct list order + UNIT; SWAP; PAIR} # Calling convention diff --git a/test/contracts/reentrancy.tz b/test/contracts/reentrancy.tz new file mode 100644 index 000000000..f30f21ae5 --- /dev/null +++ b/test/contracts/reentrancy.tz @@ -0,0 +1,6 @@ +parameter unit; +storage (pair (contract unit unit) (contract unit unit)); +return unit; +code { CDR; DUP; CAR; PUSH tez "5.00"; UNIT; + TRANSFER_TOKENS; DROP; DUP; CDR; + PUSH tez "5.00"; UNIT; TRANSFER_TOKENS; PAIR }; diff --git a/test/contracts/spawn_identities.tz b/test/contracts/spawn_identities.tz new file mode 100644 index 000000000..48ef21d29 --- /dev/null +++ b/test/contracts/spawn_identities.tz @@ -0,0 +1,27 @@ +parameter nat; +return unit; +storage (list (contract string string)); +code { DUP; + CAR; # Get the number + DIP{CDR}; # Put the accumulator on the stack + PUSH bool True; # Push true so we have a do while loop + LOOP { DUP; PUSH nat 0; CMPEQ; # Check if the number is 0 + IF { PUSH bool False} # End the loop + { PUSH nat 1; SWAP; SUB; ABS; # Subtract 1. The ABS is to make it back into a nat + UNIT; # Storage type + LAMBDA (pair string unit) # Identity contract + (pair string unit) + {}; + PUSH tez "5.00"; # Strating balance + PUSH bool False; DUP; # Not spendable or delegatable + NONE key_hash; + # This is once again my key from the alphanet. + # I highly encourage you to send funds to it + # Will it help you? Will it help me? The answer is no, + # However, do it anyway + PUSH key_hash "tz1cxcwwnzENRdhe2Kb8ZdTrdNy4bFNyScx5"; + CREATE_CONTRACT; # Make the contract + SWAP; # Add to the list + DIP{CONS}; + PUSH bool True}}; # Continue the loop + DROP; UNIT; PAIR} # Calling convention diff --git a/test/contracts/strategy_proxy.tz b/test/contracts/strategy_proxy.tz new file mode 100644 index 000000000..f80c90078 --- /dev/null +++ b/test/contracts/strategy_proxy.tz @@ -0,0 +1,9 @@ +parameter nat; +storage (pair (option nat) (contract (or nat (pair signature nat)) bool)); +return (pair nat bool); +code { DUP; CAR; DIP{CDDR; DUP}; DUP; DIP{SOME; PAIR; SWAP}; # Store the nat in strorage + # Query our stored contract + LEFT (pair signature nat); DIP{PUSH tez "0.00"}; TRANSFER_TOKENS; + # Cleanup and finish + DIP{DUP; CAR}; DIP{IF_NONE {FAIL} {}}; SWAP; + PAIR; DIP{CDR; NONE nat; PAIR}; PAIR} diff --git a/test/contracts/subset.tz b/test/contracts/subset.tz new file mode 100644 index 000000000..6924c57fe --- /dev/null +++ b/test/contracts/subset.tz @@ -0,0 +1,18 @@ +parameter (pair (set string) (set string)); +return bool; +storage unit; +code { CAR; DUP; CDR; DIP{CAR}; # Unpack lists + PUSH bool True; + PAIR; SWAP; # Setup accumulator + LAMBDA (pair string (pair bool (set string))) + (pair bool (set string)) + { DUP; # Unpack accumulator and input + CAR; + DIP{ CDR; DUP; DUP; CDR; + DIP{CAR; DIP{CDR}}}; + MEM; # Check membership + AND; # Combine accumulator and input + PAIR}; + REDUCE; # Reduce + CAR; # Get the accumulator value + UNIT; SWAP; PAIR} # Calling convention diff --git a/test/contracts/swap_storage_input.tz b/test/contracts/swap_storage_input.tz new file mode 100644 index 000000000..a63a2179b --- /dev/null +++ b/test/contracts/swap_storage_input.tz @@ -0,0 +1,9 @@ + +parameter string; +return string; +storage string; # Note that all three values are of the same type +code { DUP; # In order to access both the storage and parameter, I need to duplicate the (pair parameter storage) + CAR; # Access the parameter + SWAP; # Exchange top and second element on the stack + CDR; # Get the storage in the pair + PAIR}; # Generate pair of elements diff --git a/test/contracts/swap_storage_input_dip.tz b/test/contracts/swap_storage_input_dip.tz new file mode 100644 index 000000000..5459623e1 --- /dev/null +++ b/test/contracts/swap_storage_input_dip.tz @@ -0,0 +1,8 @@ + +parameter string; +storage string; +return string; +code { DUP; # Duplicate the (pair parameter storage) + CDR; # Access the storage + DIP{CAR}; # Access the parameter, but leave the storage unchanged on top of the stack + PAIR} # Pair the elements, fulfilling the calling convention diff --git a/test/contracts/take_my_money.tz b/test/contracts/take_my_money.tz new file mode 100644 index 000000000..2b4109bc7 --- /dev/null +++ b/test/contracts/take_my_money.tz @@ -0,0 +1,9 @@ +parameter key_hash; +return unit; +storage unit; +code { CAR; DEFAULT_ACCOUNT; # Create an account for the recipient of the funds + DIP{UNIT}; # Push a value of the storage type below the contract + PUSH tez "1.00"; # The person can have a ęś© + UNIT; # Push the contract's argument type + TRANSFER_TOKENS; # Run the transfer + PAIR }; # Cleanup and put the return values diff --git a/test/contracts/two_vulnerabilities.tz b/test/contracts/two_vulnerabilities.tz new file mode 100644 index 000000000..96786e639 --- /dev/null +++ b/test/contracts/two_vulnerabilities.tz @@ -0,0 +1,7 @@ + +parameter unit; +storage (pair (contract unit unit) (contract unit unit)); +return unit; +code { CDR; DUP; CAR; PUSH tez "5.00"; UNIT; + TRANSFER_TOKENS; DROP; DUP; CDR; + PUSH tez "5.00"; UNIT; TRANSFER_TOKENS; PAIR }; diff --git a/test/test_contracts.sh b/test/test_contracts.sh index 9e89bce3d..51d0b78d8 100755 --- a/test/test_contracts.sh +++ b/test/test_contracts.sh @@ -26,6 +26,12 @@ ls $CONTRACT_PATH \ printf "All contracts are well typed\n\n" +# Assert all contracts typecheck +for contract in `ls $CONTRACT_PATH/*.tz`; do + printf "[Typechecking %s]\n" "$contract"; + ${client} typecheck program "$contract"; +done + # FORMAT: assert_output contract_file storage input expected_result assert_output $CONTRACT_PATH/ret_int.tz Unit Unit 300