diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 6fcfd1635a1c349e0f0b419aeaf9c2c2a33acc35..f1944074c462629e3d1f8eda2e3e865af6b3b035 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -4914,8 +4914,12 @@ end module Staking_pseudotokens : sig type t + val zero : t + val min : t -> t -> t + val ( = ) : t -> t -> bool + val frozen_deposits_pseudotokens_for_tez_amount : context -> public_key_hash -> Tez.t -> t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/staking.ml b/src/proto_alpha/lib_protocol/staking.ml index 11d901fa0ed2da96e78478aa681ba9771137f614..b3cc7e1a0bbe35d36f14732cccc4de02060cc50c 100644 --- a/src/proto_alpha/lib_protocol/staking.ml +++ b/src/proto_alpha/lib_protocol/staking.ml @@ -143,47 +143,59 @@ let stake ctxt ~sender ~delegate amount = in return (ctxt, stake_balance_updates @ finalize_balance_updates) +let record_request_unstake ctxt ~sender_contract ~delegate requested_amount = + let open Lwt_result_syntax in + if Tez.(requested_amount = zero) then return (ctxt, []) + else + let* requested_pseudotokens = + Staking_pseudotokens.frozen_deposits_pseudotokens_for_tez_amount + ctxt + delegate + requested_amount + in + let* available_pseudotokens = + Staking_pseudotokens.costaking_pseudotokens_balance ctxt sender_contract + in + let pseudotokens_to_unstake = + Staking_pseudotokens.min requested_pseudotokens available_pseudotokens + in + if Staking_pseudotokens.(pseudotokens_to_unstake = zero) then + return (ctxt, []) + else + let* ctxt, tez_to_unstake = + Staking_pseudotokens.debit_frozen_deposits_pseudotokens + ctxt + delegate + pseudotokens_to_unstake + in + let* ctxt = + Staking_pseudotokens.debit_costaking_pseudotokens + ctxt + sender_contract + pseudotokens_to_unstake + in + let current_cycle = (Level.current ctxt).cycle in + let* ctxt, balance_updates = + Token.transfer + ctxt + (`Frozen_deposits delegate) + (`Unstaked_frozen_deposits (delegate, current_cycle)) + tez_to_unstake + in + let+ ctxt = + Unstake_requests.add + ctxt + ~contract:sender_contract + ~delegate + current_cycle + tez_to_unstake + in + (ctxt, balance_updates) + let request_unstake ctxt ~sender_contract ~delegate requested_amount = let open Lwt_result_syntax in let* ctxt, finalize_balance_updates = finalize_unstake ctxt sender_contract in - let* requested_pseudotokens = - Staking_pseudotokens.frozen_deposits_pseudotokens_for_tez_amount - ctxt - delegate - requested_amount - in - let* available_pseudotokens = - Staking_pseudotokens.costaking_pseudotokens_balance ctxt sender_contract - in - let pseudotokens_to_unstake = - Staking_pseudotokens.min requested_pseudotokens available_pseudotokens - in - let* ctxt, tez_to_unstake = - Staking_pseudotokens.debit_frozen_deposits_pseudotokens - ctxt - delegate - pseudotokens_to_unstake - in - let* ctxt = - Staking_pseudotokens.debit_costaking_pseudotokens - ctxt - sender_contract - pseudotokens_to_unstake - in - let current_cycle = (Level.current ctxt).cycle in - let* ctxt, unstake_balance_updates = - Token.transfer - ctxt - (`Frozen_deposits delegate) - (`Unstaked_frozen_deposits (delegate, current_cycle)) - tez_to_unstake - in - let+ ctxt = - Unstake_requests.add - ctxt - ~contract:sender_contract - ~delegate - current_cycle - tez_to_unstake + let+ ctxt, unstake_balance_updates = + record_request_unstake ctxt ~sender_contract ~delegate requested_amount in (ctxt, unstake_balance_updates @ finalize_balance_updates) diff --git a/src/proto_alpha/lib_protocol/staking_pseudotokens_storage.ml b/src/proto_alpha/lib_protocol/staking_pseudotokens_storage.ml index 7439e943ce1abbd33657812ae50f12464980e9c0..20ecf2b6804357421dd759aa4184d6241e7a4025 100644 --- a/src/proto_alpha/lib_protocol/staking_pseudotokens_storage.ml +++ b/src/proto_alpha/lib_protocol/staking_pseudotokens_storage.ml @@ -93,21 +93,27 @@ let pseudotokens_of ~frozen_deposits_pseudotokens ~frozen_deposits_tez let tez_of ~frozen_deposits_pseudotokens ~frozen_deposits_tez ~pseudotoken_amount = - let frozen_deposits_tez_z = - Z.of_int64 (Tez_repr.to_mutez frozen_deposits_tez) - in - let frozen_deposits_pseudotokens_z = - Z.of_int64 (Staking_pseudotoken_repr.to_int64 frozen_deposits_pseudotokens) - in - let pseudotoken_amount_z = - Z.of_int64 (Staking_pseudotoken_repr.to_int64 pseudotoken_amount) - in - let res_z = - Z.div - (Z.mul frozen_deposits_tez_z pseudotoken_amount_z) - frozen_deposits_pseudotokens_z - in - Tez_repr.of_mutez_exn (Z.to_int64 res_z) + if Staking_pseudotoken_repr.(frozen_deposits_pseudotokens = zero) then ( + (* When there are no frozen deposits, starts with 1 mutez = 1 pseudotoken. *) + assert (Tez_repr.(frozen_deposits_tez = zero)) ; + Tez_repr.of_mutez_exn (Staking_pseudotoken_repr.to_int64 pseudotoken_amount)) + else + let frozen_deposits_tez_z = + Z.of_int64 (Tez_repr.to_mutez frozen_deposits_tez) + in + let frozen_deposits_pseudotokens_z = + Z.of_int64 + (Staking_pseudotoken_repr.to_int64 frozen_deposits_pseudotokens) + in + let pseudotoken_amount_z = + Z.of_int64 (Staking_pseudotoken_repr.to_int64 pseudotoken_amount) + in + let res_z = + Z.div + (Z.mul frozen_deposits_tez_z pseudotoken_amount_z) + frozen_deposits_pseudotokens_z + in + Tez_repr.of_mutez_exn (Z.to_int64 res_z) let frozen_deposits_pseudotokens_for_tez_amount ctxt delegate tez_amount = let open Lwt_result_syntax in @@ -115,10 +121,19 @@ let frozen_deposits_pseudotokens_for_tez_amount ctxt delegate tez_amount = let* {current_amount = frozen_deposits_tez; initial_amount = _} = Frozen_deposits_storage.get ctxt contract in - let+ frozen_deposits_pseudotokens = - Storage.Contract.Frozen_deposits_pseudotokens.get ctxt contract - in - pseudotokens_of ~frozen_deposits_pseudotokens ~frozen_deposits_tez ~tez_amount + if Tez_repr.(frozen_deposits_tez = zero) then + (* [Frozen_deposits_pseudotokens] may not be initialized when there are no + frozen deposits tez. This may happen when a new delegate is registered. *) + return + Staking_pseudotoken_repr.(of_int64_exn (Tez_repr.to_mutez tez_amount)) + else + let+ frozen_deposits_pseudotokens = + Storage.Contract.Frozen_deposits_pseudotokens.get ctxt contract + in + pseudotokens_of + ~frozen_deposits_pseudotokens + ~frozen_deposits_tez + ~tez_amount let update_frozen_deposits_pseudotokens ~f ctxt delegate = let open Lwt_result_syntax in @@ -142,38 +157,44 @@ let update_frozen_deposits_pseudotokens ~f ctxt delegate = let credit_frozen_deposits_pseudotokens_for_tez_amount ctxt delegate tez_amount = - let f ~frozen_deposits_pseudotokens ~frozen_deposits_tez = - let open Result_syntax in - let pseudotokens_to_add = - pseudotokens_of - ~frozen_deposits_pseudotokens - ~frozen_deposits_tez - ~tez_amount - in - let+ new_pseudotokens_balance = - Staking_pseudotoken_repr.( - pseudotokens_to_add +? frozen_deposits_pseudotokens) + if Tez_repr.(tez_amount = zero) then + return (ctxt, Staking_pseudotoken_repr.zero) + else + let f ~frozen_deposits_pseudotokens ~frozen_deposits_tez = + let open Result_syntax in + let pseudotokens_to_add = + pseudotokens_of + ~frozen_deposits_pseudotokens + ~frozen_deposits_tez + ~tez_amount + in + let+ new_pseudotokens_balance = + Staking_pseudotoken_repr.( + pseudotokens_to_add +? frozen_deposits_pseudotokens) + in + (new_pseudotokens_balance, pseudotokens_to_add) in - (new_pseudotokens_balance, pseudotokens_to_add) - in - update_frozen_deposits_pseudotokens ~f ctxt delegate + update_frozen_deposits_pseudotokens ~f ctxt delegate let debit_frozen_deposits_pseudotokens ctxt delegate pseudotoken_amount = - let f ~frozen_deposits_pseudotokens ~frozen_deposits_tez = - let open Result_syntax in - let+ new_pseudotokens_balance = - Staking_pseudotoken_repr.( - frozen_deposits_pseudotokens -? pseudotoken_amount) - in - let tez_amount = - tez_of - ~frozen_deposits_pseudotokens - ~frozen_deposits_tez - ~pseudotoken_amount + if Staking_pseudotoken_repr.(pseudotoken_amount = zero) then + return (ctxt, Tez_repr.zero) + else + let f ~frozen_deposits_pseudotokens ~frozen_deposits_tez = + let open Result_syntax in + let+ new_pseudotokens_balance = + Staking_pseudotoken_repr.( + frozen_deposits_pseudotokens -? pseudotoken_amount) + in + let tez_amount = + tez_of + ~frozen_deposits_pseudotokens + ~frozen_deposits_tez + ~pseudotoken_amount + in + (new_pseudotokens_balance, tez_amount) in - (new_pseudotokens_balance, tez_amount) - in - update_frozen_deposits_pseudotokens ~f ctxt delegate + update_frozen_deposits_pseudotokens ~f ctxt delegate let costaking_pseudotokens_balance ctxt contract = let open Lwt_result_syntax in