From 976a03c52f14a5ec75292a7f48f7014179e5bbf1 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Thu, 1 Jun 2023 11:19:11 +0200 Subject: [PATCH 1/9] Proto/Apply: rename a few variables in apply_stake --- src/proto_alpha/lib_protocol/apply.ml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index b74ad032ac2e..252323630190 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -288,16 +288,17 @@ let apply_transaction_to_implicit ~ctxt ~sender ~amount ~pkh ~before_operation = in return (ctxt, result, []) -let apply_stake ~ctxt ~sender ~amount ~delegate ~before_operation = - let contract = Contract.Implicit delegate in +let apply_stake ~ctxt ~sender ~amount ~destination ~before_operation = + let contract = Contract.Implicit destination in (* Staking of zero is forbidden. *) error_when Tez.(amount = zero) (Empty_transaction contract) >>?= fun () -> error_unless - Signature.Public_key_hash.(sender = delegate) - (Invalid_staking_destination delegate) + Signature.Public_key_hash.(sender = destination) + (Invalid_staking_destination destination) >>?= fun () -> - Contract.is_delegate ctxt delegate >>=? fun is_delegate -> - error_unless is_delegate (Invalid_staking_destination delegate) >>?= fun () -> + Contract.is_delegate ctxt sender >>=? fun is_delegate -> + error_unless is_delegate (Invalid_staking_destination sender) >>?= fun () -> + let delegate = sender in Token.transfer ctxt (`Contract (Contract.Implicit sender)) @@ -805,7 +806,7 @@ let apply_manager_operation : ~ctxt ~sender:source ~amount - ~delegate:pkh + ~destination:pkh ~before_operation:ctxt_before_op | ("default" | "stake"), _ -> (* Only allow [Unit] parameter to implicit accounts' default and stake entrypoints. *) -- GitLab From 09ecb478e50aac371aa6f6c0dc9489bfbb2fde12 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Thu, 1 Jun 2023 11:32:34 +0200 Subject: [PATCH 2/9] Proto/Apply: more specific error for costaking disabled --- src/proto_alpha/lib_protocol/apply.ml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 252323630190..cffacf36a7ce 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -44,6 +44,7 @@ type error += | Invalid_transfer_to_sc_rollup | Invalid_sender of Destination.t | Invalid_staking_destination of public_key_hash + | Staking_for_nondelegate_while_costaking_disabled let () = register_error_kind @@ -235,7 +236,24 @@ let () = pkh) Data_encoding.(obj1 (req "destination" Contract.implicit_encoding)) (function Invalid_staking_destination pkh -> Some pkh | _ -> None) - (fun pkh -> Invalid_staking_destination pkh) + (fun pkh -> Invalid_staking_destination pkh) ; + let staking_for_nondelegate_while_costaking_disabled_description = + "As long as co-staking is not enabled, staking and unstaking operations \ + are only allowed from delegates." + in + register_error_kind + `Permanent + ~id:"operations.staking_for_nondelegate_while_costaking_disabled" + ~title:"Staking for a non-delegate while co-staking is disabled" + ~description:staking_for_nondelegate_while_costaking_disabled_description + ~pp:(fun ppf () -> + Format.pp_print_string + ppf + staking_for_nondelegate_while_costaking_disabled_description) + Data_encoding.unit + (function + | Staking_for_nondelegate_while_costaking_disabled -> Some () | _ -> None) + (fun () -> Staking_for_nondelegate_while_costaking_disabled) open Apply_results open Apply_operation_result @@ -297,7 +315,8 @@ let apply_stake ~ctxt ~sender ~amount ~destination ~before_operation = (Invalid_staking_destination destination) >>?= fun () -> Contract.is_delegate ctxt sender >>=? fun is_delegate -> - error_unless is_delegate (Invalid_staking_destination sender) >>?= fun () -> + error_unless is_delegate Staking_for_nondelegate_while_costaking_disabled + >>?= fun () -> let delegate = sender in Token.transfer ctxt -- GitLab From 63af34d3f1cdecbd0a9f5002635f5e146610c737 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Thu, 1 Jun 2023 11:36:35 +0200 Subject: [PATCH 3/9] Proto/Apply: more specific error for self-transactions --- src/proto_alpha/lib_protocol/apply.ml | 30 +++++++++++++-------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index cffacf36a7ce..bd686250a85e 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -43,7 +43,7 @@ type error += | Multiple_revelation | Invalid_transfer_to_sc_rollup | Invalid_sender of Destination.t - | Invalid_staking_destination of public_key_hash + | Invalid_self_transaction_destination | Staking_for_nondelegate_while_costaking_disabled let () = @@ -220,23 +220,21 @@ let () = Data_encoding.(obj1 (req "contract" Destination.encoding)) (function Invalid_sender c -> Some c | _ -> None) (fun c -> Invalid_sender c) ; + let invalid_self_transaction_destination_description = + "A pseudo-transaction destination must equal its sender." + in register_error_kind `Permanent - ~id:"operations.invalid_staking_destination" - ~title:"Invalid destination for a stake operation" - ~description: - "The transaction destination must be a registered delegate. Additionally \ - it must equal the operation source for now." - ~pp:(fun ppf pkh -> - Format.fprintf + ~id:"operations.invalid_self_transaction_destination" + ~title:"Invalid destination for a pseudo-transaction" + ~description:invalid_self_transaction_destination_description + ~pp:(fun ppf () -> + Format.pp_print_string ppf - "Invalid destination (%a) for this stake operation. Only registered \ - delegate are allowed." - Signature.Public_key_hash.pp - pkh) - Data_encoding.(obj1 (req "destination" Contract.implicit_encoding)) - (function Invalid_staking_destination pkh -> Some pkh | _ -> None) - (fun pkh -> Invalid_staking_destination pkh) ; + invalid_self_transaction_destination_description) + Data_encoding.unit + (function Invalid_self_transaction_destination -> Some () | _ -> None) + (fun () -> Invalid_self_transaction_destination) ; let staking_for_nondelegate_while_costaking_disabled_description = "As long as co-staking is not enabled, staking and unstaking operations \ are only allowed from delegates." @@ -312,7 +310,7 @@ let apply_stake ~ctxt ~sender ~amount ~destination ~before_operation = error_when Tez.(amount = zero) (Empty_transaction contract) >>?= fun () -> error_unless Signature.Public_key_hash.(sender = destination) - (Invalid_staking_destination destination) + Invalid_self_transaction_destination >>?= fun () -> Contract.is_delegate ctxt sender >>=? fun is_delegate -> error_unless is_delegate Staking_for_nondelegate_while_costaking_disabled -- GitLab From 34f96b6c2f101f170c03b1baec3cd965b4f61f0b Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Tue, 6 Jun 2023 16:54:55 +0200 Subject: [PATCH 4/9] Proto/Unstake_requests_storage: reuse types --- .../lib_protocol/unstake_requests_storage.ml | 14 ++++++++++---- .../lib_protocol/unstake_requests_storage.mli | 7 +++++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml index 7176f00912d0..31615fd4ad44 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml @@ -23,9 +23,12 @@ (* *) (*****************************************************************************) +type finalizable = + (Signature.Public_key_hash.t * Cycle_repr.t * Tez_repr.t) list + type prepared_finalize_unstake = { - finalizable : (Signature.Public_key_hash.t * Cycle_repr.t * Tez_repr.t) list; - unfinalizable : Signature.Public_key_hash.t * (Cycle_repr.t * Tez_repr.t) list; + finalizable : finalizable; + unfinalizable : Storage.Unstake_request.t; } let z100 = Z.of_int 100 @@ -77,7 +80,7 @@ let prepare_finalize_unstake ctxt contract = let slashing_history = Option.value slashing_history_opt ~default:[] in - let finalizable, unfinalizable = + let finalizable, unfinalizable_requests = List.partition_map (fun request -> let request_cycle, request_amount = request in @@ -93,5 +96,8 @@ let prepare_finalize_unstake ctxt contract = else Right request) requests in - let unfinalizable = (delegate, unfinalizable) in + let unfinalizable = + Storage.Unstake_request. + {delegate; requests = unfinalizable_requests} + in return_some {finalizable; unfinalizable}) diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.mli b/src/proto_alpha/lib_protocol/unstake_requests_storage.mli index 8bc35b435a59..050c17cadd2e 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.mli +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.mli @@ -28,9 +28,12 @@ This module is responsible for maintaining the {!Storage.Contract.Unstake_requests} table. *) +type finalizable = + (Signature.Public_key_hash.t * Cycle_repr.t * Tez_repr.t) list + type prepared_finalize_unstake = { - finalizable : (Signature.Public_key_hash.t * Cycle_repr.t * Tez_repr.t) list; - unfinalizable : Signature.Public_key_hash.t * (Cycle_repr.t * Tez_repr.t) list; + finalizable : finalizable; + unfinalizable : Storage.Unstake_request.t; } (** [prepare_finalize_unstake ctxt contract] preprocesses a [finalize_unstake] -- GitLab From 7f7888bf3c34851aeab9cee8069debee3158e947 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Tue, 6 Jun 2023 17:10:51 +0200 Subject: [PATCH 5/9] Proto/Unstake_requests_storage: prepare_finalize_unstake_and_save_remaining_unfinalizable_requests --- .../lib_protocol/unstake_requests_storage.ml | 12 ++++++++++++ .../lib_protocol/unstake_requests_storage.mli | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml index 31615fd4ad44..710aba989bb2 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.ml +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.ml @@ -101,3 +101,15 @@ let prepare_finalize_unstake ctxt contract = {delegate; requests = unfinalizable_requests} in return_some {finalizable; unfinalizable}) + +let prepare_finalize_unstake_and_save_remaining_unfinalizable_requests ctxt + contract = + let open Lwt_result_syntax in + let* prepared_opt = prepare_finalize_unstake ctxt contract in + match prepared_opt with + | None -> return (ctxt, []) + | Some {finalizable; unfinalizable} -> + let+ ctxt = + Storage.Contract.Unstake_requests.update ctxt contract unfinalizable + in + (ctxt, finalizable) diff --git a/src/proto_alpha/lib_protocol/unstake_requests_storage.mli b/src/proto_alpha/lib_protocol/unstake_requests_storage.mli index 050c17cadd2e..f32cbd55e020 100644 --- a/src/proto_alpha/lib_protocol/unstake_requests_storage.mli +++ b/src/proto_alpha/lib_protocol/unstake_requests_storage.mli @@ -48,3 +48,11 @@ val prepare_finalize_unstake : Raw_context.t -> Contract_repr.t -> prepared_finalize_unstake option tzresult Lwt.t + +(** [prepare_finalize_unstake_and_save_remaining_unfinalizable_requests ctxt contract] + calls [prepare_finalize_unstake], saves the remaining [unfinalizable] + requests and returns the [finalizable] ones. *) +val prepare_finalize_unstake_and_save_remaining_unfinalizable_requests : + Raw_context.t -> + Contract_repr.t -> + (Raw_context.t * finalizable) tzresult Lwt.t -- GitLab From 2dde837769241aba5a26cb8404ba3eb6bf30560e Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Fri, 2 Jun 2023 21:19:29 +0200 Subject: [PATCH 6/9] Proto/Alpha_context: expose Unstake_requests --- src/proto_alpha/lib_protocol/alpha_context.ml | 1 + src/proto_alpha/lib_protocol/alpha_context.mli | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 581a7f636b55..49952e0f6067 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -615,6 +615,7 @@ end module Token = Token module Cache = Cache_repr +module Unstake_requests = Unstake_requests_storage module Internal_for_tests = struct let to_raw x = x diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index f6cc8d67b7ca..b3e21f213771 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -4828,6 +4828,14 @@ module Token : sig (context * Receipt.balance_updates) tzresult Lwt.t end +(** This module re-exports definitions from {!Unstake_requests_storage}. *) +module Unstake_requests : sig + type finalizable = (public_key_hash * Cycle.t * Tez.t) list + + val prepare_finalize_unstake_and_save_remaining_unfinalizable_requests : + context -> Contract.t -> (context * finalizable) tzresult Lwt.t +end + (** This module re-exports definitions from {!Fees_storage}. *) module Fees : sig val record_paid_storage_space : -- GitLab From 2252d9e398cf7734485562ab42cab19cd035d8c1 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Fri, 2 Jun 2023 21:13:51 +0200 Subject: [PATCH 7/9] Proto: add module Staking --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 1 + src/proto_alpha/lib_protocol/dune | 4 ++++ src/proto_alpha/lib_protocol/staking.ml | 24 +++++++++++++++++++++ src/proto_alpha/lib_protocol/staking.mli | 24 +++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 src/proto_alpha/lib_protocol/staking.ml create mode 100644 src/proto_alpha/lib_protocol/staking.mli diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 8637a7aa5e93..5e6eb2542d29 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -235,6 +235,7 @@ "Dal_apply", "Zk_rollup_apply", + "Staking", "Baking", "Validate_errors", "Amendment", diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index e9af55b479c9..0286f1d3a3ee 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -240,6 +240,7 @@ Sc_rollup_operations Dal_apply Zk_rollup_apply + Staking Baking Validate_errors Amendment @@ -504,6 +505,7 @@ sc_rollup_operations.ml sc_rollup_operations.mli dal_apply.ml dal_apply.mli zk_rollup_apply.ml zk_rollup_apply.mli + staking.ml staking.mli baking.ml baking.mli validate_errors.ml validate_errors.mli amendment.ml amendment.mli @@ -769,6 +771,7 @@ sc_rollup_operations.ml sc_rollup_operations.mli dal_apply.ml dal_apply.mli zk_rollup_apply.ml zk_rollup_apply.mli + staking.ml staking.mli baking.ml baking.mli validate_errors.ml validate_errors.mli amendment.ml amendment.mli @@ -1018,6 +1021,7 @@ sc_rollup_operations.ml sc_rollup_operations.mli dal_apply.ml dal_apply.mli zk_rollup_apply.ml zk_rollup_apply.mli + staking.ml staking.mli baking.ml baking.mli validate_errors.ml validate_errors.mli amendment.ml amendment.mli diff --git a/src/proto_alpha/lib_protocol/staking.ml b/src/proto_alpha/lib_protocol/staking.ml new file mode 100644 index 000000000000..48fcc1a4b1b4 --- /dev/null +++ b/src/proto_alpha/lib_protocol/staking.ml @@ -0,0 +1,24 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) diff --git a/src/proto_alpha/lib_protocol/staking.mli b/src/proto_alpha/lib_protocol/staking.mli new file mode 100644 index 000000000000..48fcc1a4b1b4 --- /dev/null +++ b/src/proto_alpha/lib_protocol/staking.mli @@ -0,0 +1,24 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) -- GitLab From f72325f6db307fc10bc0a0bea56bf4ab662a14f8 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Fri, 2 Jun 2023 21:31:49 +0200 Subject: [PATCH 8/9] Proto/Staking: finalize_unstake --- src/proto_alpha/lib_protocol/staking.ml | 23 +++++++++++++++++++++++ src/proto_alpha/lib_protocol/staking.mli | 16 ++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/proto_alpha/lib_protocol/staking.ml b/src/proto_alpha/lib_protocol/staking.ml index 48fcc1a4b1b4..b87e9afe5609 100644 --- a/src/proto_alpha/lib_protocol/staking.ml +++ b/src/proto_alpha/lib_protocol/staking.ml @@ -22,3 +22,26 @@ (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) +open Alpha_context + +let finalize_unstake ctxt pkh = + let open Lwt_result_syntax in + let contract = Contract.Implicit pkh in + let* ctxt, finalizable = + Unstake_requests + .prepare_finalize_unstake_and_save_remaining_unfinalizable_requests + ctxt + contract + in + List.fold_left_es + (fun (ctxt, balance_updates) (delegate, cycle, amount) -> + let+ ctxt, new_balance_updates = + Token.transfer + ctxt + (`Unstaked_frozen_deposits (delegate, cycle)) + (`Contract contract) + amount + in + (ctxt, new_balance_updates @ balance_updates)) + (ctxt, []) + finalizable diff --git a/src/proto_alpha/lib_protocol/staking.mli b/src/proto_alpha/lib_protocol/staking.mli index 48fcc1a4b1b4..4be8b752f8e2 100644 --- a/src/proto_alpha/lib_protocol/staking.mli +++ b/src/proto_alpha/lib_protocol/staking.mli @@ -22,3 +22,19 @@ (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) + +open Alpha_context + +(** [finalize_unstake ctxt pkh] performs the finalization of all unstake + requests from [pkh] that can be finalized. + An unstake request can be finalized if it is old enough, specifically the + requested amount must not be at stake anymore and must not be slashable + anymore, i.e. after [preserved_cycles + max_slashing_period] after the + request. + Amounts are transferred from the [pkh]'s delegate (at request time) unstaked + frozen deposits to [pkh]'s spendable balance, minus slashing the requested + stake undergone in between. *) +val finalize_unstake : + context -> + public_key_hash -> + (context * Receipt.balance_updates) tzresult Lwt.t -- GitLab From 55bc95544526ae0c2b40eb3beb1c41471f969197 Mon Sep 17 00:00:00 2001 From: Mehdi Bouaziz Date: Thu, 1 Jun 2023 11:44:16 +0200 Subject: [PATCH 9/9] Proto/Apply: finalize_unstake pseudo-operation --- src/proto_alpha/lib_protocol/apply.ml | 57 +++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index bd686250a85e..e73bc5ddf7bb 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -45,6 +45,7 @@ type error += | Invalid_sender of Destination.t | Invalid_self_transaction_destination | Staking_for_nondelegate_while_costaking_disabled + | Invalid_nonzero_transaction_amount of Tez.t let () = register_error_kind @@ -251,7 +252,22 @@ let () = Data_encoding.unit (function | Staking_for_nondelegate_while_costaking_disabled -> Some () | _ -> None) - (fun () -> Staking_for_nondelegate_while_costaking_disabled) + (fun () -> Staking_for_nondelegate_while_costaking_disabled) ; + register_error_kind + `Permanent + ~id:"operations.invalid_nonzero_transaction_amount" + ~title:"Invalid non-zero transaction amount" + ~description:"A transaction expected a zero-amount but got non-zero." + ~pp:(fun ppf amount -> + Format.fprintf + ppf + "A transaction expected a zero-amount but got %a." + Tez.pp + amount) + Data_encoding.(obj1 (req "amount" Tez.encoding)) + (function + | Invalid_nonzero_transaction_amount amount -> Some amount | _ -> None) + (fun amount -> Invalid_nonzero_transaction_amount amount) open Apply_results open Apply_operation_result @@ -340,6 +356,33 @@ let apply_stake ~ctxt ~sender ~amount ~destination ~before_operation = in return (ctxt, result, []) +let apply_finalize_unstake ~ctxt ~sender ~amount ~destination ~before_operation + = + error_when Tez.(amount <> zero) (Invalid_nonzero_transaction_amount amount) + >>?= fun () -> + error_unless + Signature.Public_key_hash.(sender = destination) + Invalid_self_transaction_destination + >>?= fun () -> + let contract = Contract.Implicit sender in + Contract.allocated ctxt contract >>= fun already_allocated -> + Staking.finalize_unstake ctxt sender >>=? fun (ctxt, balance_updates) -> + let result = + Transaction_to_contract_result + { + storage = None; + lazy_storage_diff = None; + balance_updates; + ticket_receipt = []; + originated_contracts = []; + consumed_gas = Gas.consumed ~since:before_operation ~until:ctxt; + storage_size = Z.zero; + paid_storage_size_diff = Z.zero; + allocated_destination_contract = not already_allocated; + } + in + return (ctxt, result, []) + let transfer_from_any_address ctxt sender destination amount = match sender with | Destination.Contract sender -> @@ -825,8 +868,16 @@ let apply_manager_operation : ~amount ~destination:pkh ~before_operation:ctxt_before_op - | ("default" | "stake"), _ -> - (* Only allow [Unit] parameter to implicit accounts' default and stake entrypoints. *) + | "finalize_unstake", Prim (_, D_Unit, [], _) -> + apply_finalize_unstake + ~ctxt + ~sender:source + ~amount + ~destination:pkh + ~before_operation:ctxt_before_op + | ("default" | "stake" | "finalize_unstake"), _ -> + (* Only allow [Unit] parameter to implicit accounts' default, stake, + and finalize_unstake entrypoints. *) tzfail (Script_interpreter.Bad_contract_parameter source_contract) | _ -> tzfail (Script_tc_errors.No_such_entrypoint entrypoint)) >|=? fun (ctxt, res, ops) -> (ctxt, Transaction_result res, ops) -- GitLab