From 4ea2a6bfd8fbf3a77693ccc92fddb0f458d51f87 Mon Sep 17 00:00:00 2001 From: Arthur Guillon Date: Sun, 30 Jul 2023 20:05:15 +0200 Subject: [PATCH 1/2] More tests for B.Context.wait_for --- test/test_time.mligo | 69 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 7 deletions(-) diff --git a/test/test_time.mligo b/test/test_time.mligo index e4bb346..071e116 100644 --- a/test/test_time.mligo +++ b/test/test_time.mligo @@ -35,20 +35,35 @@ module Ping = struct failwith "come back later" end +module Exact = struct + type storage = timestamp + + [@entry] + let exact (_, last: unit * storage) : operation list * storage = + let now = Tezos.get_now () in + if last > (0: timestamp) && now <> last + 30 then + failwith "wrong time" + else + [], now +end + let (_, (alice, _, _)) = B.Context.init_default () -let originated level initial_time = +let ping_contract level initial_time = B.Contract.originate_module level "ping" (contract_of Ping) initial_time 0tez +let exact_contract level initial_time = + B.Contract.originate_module level "exact" (contract_of Exact) initial_time 0tez + let suite = B.Model.suite "Test suite for time-related operations" [ B.Model.case - "ping" - "succeeds when you call it after waiting for more than one minute" + "wait_for" + "waits for at least the expected time" (fun (level: B.Logger.level) -> - let contract = originated level (0: timestamp) in + let contract = ping_contract level (0: timestamp) in B.Result.reduce [ B.Context.call_as alice contract Ping; @@ -60,9 +75,9 @@ let suite = B.Model.case "ping" - "fails when you call it before waiting" + "does not wait for an arbitrary long time" (fun (level: B.Logger.level) -> - let contract = originated level (0: timestamp) in + let contract = ping_contract level (0: timestamp) in B.Result.reduce [ B.Context.call_as alice contract Ping; @@ -70,6 +85,46 @@ let suite = B.Expect.fail_with_message "come back later" (B.Context.call_as alice contract Ping); - ]) + ]); + + B.Model.case + "wait_for" + "waiting for the block time makes you miss 1 block, not more" + (fun (level: B.Logger.level) -> + let exact_contract = exact_contract level (0: timestamp) in + + (* We cannot just repeat the list [call_as; wait_for] because these + functions are impure *) + B.Result.reduce [ + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 15n; + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 15n; + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 15n; + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 15n; + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 15n; + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 15n; + B.Context.call_as alice exact_contract Exact; + ]); + + B.Model.case + "wait_for" + "waiting for less than one block time does not make you miss one block" + (fun (level: B.Logger.level) -> + let exact_contract = exact_contract level (0: timestamp) in + + (* We cannot just repeat the list [call_as; wait_for] because these + functions are impure *) + B.Result.reduce [ + B.Context.call_as alice exact_contract Exact; + B.Context.wait_for 1n; + B.Expect.fail_with_message + "wrong time" + (B.Context.call_as alice exact_contract Exact); + ]); ] From 74b4126b0bd9ba011a075ad72f669f68f2ebe3d9 Mon Sep 17 00:00:00 2001 From: Arthur Guillon Date: Wed, 20 Sep 2023 02:24:24 +0200 Subject: [PATCH 2/2] Something something ligo v1 --- examples/ticket_factory/src/common.mligo | 43 --------- examples/ticket_factory/src/mint_sc.mligo | 31 ++++--- examples/ticket_factory/src/oven_sc.mligo | 102 +++++++++++++--------- examples/ticket_factory/test/util.mligo | 24 ++--- 4 files changed, 89 insertions(+), 111 deletions(-) delete mode 100644 examples/ticket_factory/src/common.mligo diff --git a/examples/ticket_factory/src/common.mligo b/examples/ticket_factory/src/common.mligo deleted file mode 100644 index c261aae..0000000 --- a/examples/ticket_factory/src/common.mligo +++ /dev/null @@ -1,43 +0,0 @@ -(* MIT License - - Copyright (c) 2022 Marigold - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal in - the Software without restriction, including without limitation the rights to - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - the Software, and to permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. *) - -type oven_storage = { - stored_ticket : bytes ticket option -; qty_ticket : nat -; owner_address : address -; mint_address : address -} - -type mint_storage = { - fixed_payload : bytes -; minimal_amount : tez -} - -type oven_entrypoint = - | Oven_request_mint - | Oven_retreive_ticket of bytes ticket - | Oven_request_redeem - | Oven_retreive_tez - -type mint_entrypoint = - | Mint_process_mint of bytes ticket contract - | Mint_process_redeem of bytes ticket * unit contract diff --git a/examples/ticket_factory/src/mint_sc.mligo b/examples/ticket_factory/src/mint_sc.mligo index 6423492..5d4ab6a 100644 --- a/examples/ticket_factory/src/mint_sc.mligo +++ b/examples/ticket_factory/src/mint_sc.mligo @@ -20,10 +20,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) -#import "common.mligo" "Common" - -type entrypoint = Common.mint_entrypoint -type storage = Common.mint_storage +type storage = { + fixed_payload : bytes + ; minimal_amount : tez +} type applied = operation list * storage let tez_to_nat (xtz: tez) : nat = xtz / 1mutez @@ -56,13 +56,16 @@ let process_redeem let retribution = nat_to_tez qty in Tezos.transaction unit retribution callback -let main (action, storage: entrypoint * storage) : applied = - match action with - | Mint_process_mint callback -> - let quantity = Tezos.get_amount () in - let operation = process_mint storage callback quantity in - ([operation], storage) - | Mint_process_redeem (ticket, callback) -> - let self_address = Tezos.get_self_address () in - let operation = process_redeem storage self_address ticket callback in - ([operation], storage) +[@entry] +let mint_process_mint (callback: bytes ticket contract) (storage: storage): applied = + let quantity = Tezos.get_amount () in + let operation = process_mint storage callback quantity in + ([operation], storage) + +[@entry] +let mint_process_redeem + (ticket, callback: bytes ticket * unit contract) + (storage: storage): applied = + let self_address = Tezos.get_self_address () in + let operation = process_redeem storage self_address ticket callback in + ([operation], storage) diff --git a/examples/ticket_factory/src/oven_sc.mligo b/examples/ticket_factory/src/oven_sc.mligo index 4a3afaa..15aeb8a 100644 --- a/examples/ticket_factory/src/oven_sc.mligo +++ b/examples/ticket_factory/src/oven_sc.mligo @@ -20,24 +20,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *) -#import "common.mligo" "Common" +#import "mint_sc.mligo" "Mint" -type entrypoint = Common.oven_entrypoint -type storage = Common.oven_storage +type storage = { + stored_ticket : bytes ticket option + ; qty_ticket : nat + ; owner_address : address + ; mint_address : address +} type applied = operation list * storage let request_mint (mint_address: address) (qty: tez) : operation = if qty <= 0tez then failwith "oven_sc: amount should not null" else - let callback : bytes ticket contract = Tezos.self "%oven_retreive_ticket" in - let mint_sc : Common.mint_entrypoint contract = + let callback : bytes ticket contract = Tezos.self "%oven_retrieve_ticket" in + let mint_sc : (Mint parameter_of) contract = Tezos.get_contract_with_error mint_address "oven_sc: unable to find mint contract" in Tezos.transaction (Mint_process_mint callback) qty mint_sc -let retreive_ticket +let retrieve_ticket (counter: nat) (stored_ticket : bytes ticket option) (minted_ticket: bytes ticket) : bytes ticket option * nat = @@ -56,52 +60,66 @@ let request_redeem (mint_address: address) (stored_ticket : bytes ticket option) let (_, (_, qty)), ticket = Tezos.read_ticket ticket in if qty <= 0n then failwith "oven_sc: quantity is null" else - let callback : unit contract = Tezos.self "%oven_retreive_tez" in - let mint_sc : Common.mint_entrypoint contract = + let callback : unit contract = Tezos.self "%oven_retrieve_tez" in + let mint_sc : (Mint parameter_of) contract = Tezos.get_contract_with_error mint_address "oven_sc: unable to find mint contract" in Tezos.transaction (Mint_process_redeem (ticket, callback)) 0tez mint_sc -let retreive_tez (owner_address : address) (retribution: tez) : operation = +let retrieve_tez (owner_address : address) (retribution: tez) : operation = let beneficiary : unit contract = Tezos.get_contract_with_error owner_address "oven_sc: unable to find owner" in Tezos.transaction unit retribution beneficiary +[@entry] +let oven_request_mint + (_: unit) + ({owner_address; mint_address; stored_ticket; qty_ticket}: storage) : applied = + let _ = assert_with_error (Tezos.get_source () = owner_address) "oven_sc: not owner" in + let quantity = Tezos.get_amount () in + let operation = request_mint mint_address quantity in + ([operation], { + owner_address = owner_address + ; mint_address = mint_address + ; stored_ticket = stored_ticket + ; qty_ticket = qty_ticket} ) -let main (action, {owner_address; mint_address; stored_ticket; qty_ticket}: entrypoint * storage) : applied = - if Tezos.get_source () = owner_address then - let quantity = Tezos.get_amount () in - match action with - | Oven_request_mint -> - let operation = request_mint mint_address quantity in - ([operation], { - owner_address = owner_address - ; mint_address = mint_address - ; stored_ticket = stored_ticket - ; qty_ticket = qty_ticket} ) - | Oven_retreive_ticket minted_ticket -> - let (new_ticket, counter) = retreive_ticket qty_ticket stored_ticket minted_ticket in - ([], { - owner_address = owner_address - ; mint_address = mint_address - ; stored_ticket = new_ticket - ; qty_ticket = counter} ) - | Oven_request_redeem -> - let operation = request_redeem mint_address stored_ticket in - ([operation], { - owner_address = owner_address - ; mint_address = mint_address - ; stored_ticket = (None : bytes ticket option) - ; qty_ticket = 0n }) - | Oven_retreive_tez -> - let operation = retreive_tez owner_address quantity in - ([operation], { - owner_address = owner_address - ; mint_address = mint_address - ; stored_ticket = (None : bytes ticket option) - ; qty_ticket = 0n} ) +[@entry] +let oven_retrieve_ticket + (minted_ticket: bytes ticket) + ({owner_address; mint_address; stored_ticket; qty_ticket}: storage) : applied = + let _ = assert_with_error (Tezos.get_source () = owner_address) "oven_sc: not owner" in + let (new_ticket, counter) = retrieve_ticket qty_ticket stored_ticket minted_ticket in + ([], { + owner_address = owner_address + ; mint_address = mint_address + ; stored_ticket = new_ticket + ; qty_ticket = counter} ) - else failwith "oven_sc: not owner" +[@entry] +let oven_request_redeem + (_: unit) + ({owner_address; mint_address; stored_ticket; qty_ticket = _}: storage) : applied = + let _ = assert_with_error (Tezos.get_source () = owner_address) "oven_sc: not owner" in + let operation = request_redeem mint_address stored_ticket in + ([operation], { + owner_address = owner_address + ; mint_address = mint_address + ; stored_ticket = (None : bytes ticket option) + ; qty_ticket = 0n }) + +[@entry] +let oven_retrieve_tez + (_: unit) + ({owner_address; mint_address; stored_ticket = _; qty_ticket = _}: storage) : applied = + let _ = assert_with_error (Tezos.get_source () = owner_address) "oven_sc: not owner" in + let quantity = Tezos.get_amount () in + let operation = retrieve_tez owner_address quantity in + ([operation], { + owner_address = owner_address + ; mint_address = mint_address + ; stored_ticket = (None : bytes ticket option) + ; qty_ticket = 0n} ) diff --git a/examples/ticket_factory/test/util.mligo b/examples/ticket_factory/test/util.mligo index 7715426..89f0e8c 100644 --- a/examples/ticket_factory/test/util.mligo +++ b/examples/ticket_factory/test/util.mligo @@ -27,10 +27,10 @@ type originated = Breath.Contract.originated let originate_mint (level: Breath.Logger.level) (pl: bytes) (min_amount: tez) () = - Breath.Contract.originate_uncurried + Breath.Contract.originate_module level "mint_sc" - Mint.main + (contract_of Mint) { fixed_payload = pl; minimal_amount = min_amount } 0tez @@ -38,7 +38,7 @@ let originate_oven_with (level: Breath.Logger.level) (ticket: bytes ticket option) (actor: Breath.Context.actor) - (mint: (Mint.entrypoint, Mint.storage) originated) + (mint: (Mint parameter_of, Mint.storage) originated) () = let (fresh_ticket, counter) = match ticket with | None -> (None : bytes ticket option), 0n @@ -46,10 +46,10 @@ let originate_oven_with let (_, (_, qty)), fresh = Tezos.read_ticket t in (Some fresh, qty) in - Breath.Contract.originate_uncurried + Breath.Contract.originate_module level ("oven_sc_" ^ actor.name) - Oven.main + (contract_of Oven) { stored_ticket = fresh_ticket ; owner_address = actor.address ; mint_address = mint.originated_address @@ -60,25 +60,25 @@ let originate_oven_with_ticket (level: Breath.Logger.level) (ticket: bytes ticket) (actor: Breath.Context.actor) - (mint: (Mint.entrypoint, Mint.storage) originated) + (mint: (Mint parameter_of, Mint.storage) originated) () = originate_oven_with level (Some ticket) actor mint () let originate_oven (level: Breath.Logger.level) (actor: Breath.Context.actor) - (mint: (Mint.entrypoint, Mint.storage) originated) + (mint: (Mint parameter_of, Mint.storage) originated) () = originate_oven_with level (None: bytes ticket option) actor mint () -let request_mint (contract: (Oven.entrypoint, Oven.storage) originated) (qty: tez) () = +let request_mint (contract: (Oven parameter_of, Oven.storage) originated) (qty: tez) () = Breath.Contract.transfer_to contract Oven_request_mint qty -let request_redeem (contract: (Oven.entrypoint, Oven.storage) originated) () = +let request_redeem (contract: (Oven parameter_of, Oven.storage) originated) () = Breath.Contract.transfer_to contract Oven_request_redeem 0tez let expected_mint_state - (contract: (Mint.entrypoint, Mint.storage) originated) + (contract: (Mint parameter_of, Mint.storage) originated) (pl: bytes) (ma: tez) (current_balance: tez) : Breath.Result.result = @@ -90,9 +90,9 @@ let expected_mint_state Breath.Result.reduce [pl_expectation; ma_expectation; ba_expectation] let expected_oven_state - (contract : (Oven.entrypoint, Oven.storage) originated) + (contract : (Oven parameter_of, Oven.storage) originated) (actor : Breath.Context.actor) - (mint : (Mint.entrypoint, Mint.storage) originated) + (mint : (Mint parameter_of, Mint.storage) originated) (qty : nat) : Breath.Result.result = let { stored_ticket = _; owner_address; mint_address; qty_ticket} = Breath.Contract.storage_of contract