diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_services.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_services.ml index c9733dc503cdf74c1c0ba183a3c4b02589b40981..9ea2d75c5261f66d6d91ae827af3791b144135ff 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_services.ml +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_services.ml @@ -26,9 +26,17 @@ open Alpha_context module S = struct + open Data_encoding + + let q_encoding = + conv + (fun Q.{num; den} -> (num, den)) + (fun (num, den) -> Q.make num den) + (obj2 (req "numerator" n) (req "denominator" n)) + let context_path = RPC_path.(open_root / "context") - let _path = RPC_path.(context_path / "inflation") + let path = RPC_path.(context_path / "inflation") let total_supply = RPC_service.get_service @@ -43,18 +51,95 @@ module S = struct ~query:RPC_query.empty ~output:Tez.encoding RPC_path.(context_path / "total_frozen_stake") + + let current_yearly_rate = + RPC_service.get_service + ~description: + "Returns the current expected maximum yearly inflation rate (in %)" + ~query:RPC_query.empty + ~output:(string Plain) + RPC_path.(path / "current_yearly_rate") + + let current_yearly_rate_exact = + RPC_service.get_service + ~description: + "Returns the current expected maximum yearly inflation rate (exact \ + quotient)" + ~query:RPC_query.empty + ~output:q_encoding + RPC_path.(path / "current_yearly_rate_exact") + + let current_rewards_per_minute = + RPC_service.get_service + ~description: + "Returns the current expected maximum rewards per minute (in mutez)" + ~query:RPC_query.empty + ~output:Tez.encoding + RPC_path.(path / "rewards_per_minute") end +let q_to_float_string q = + let offset = 1000 in + let unit = Z.div q.Q.num q.den in + let q = Q.(sub q (unit /// Z.one)) in + let q = Q.(mul q (offset // 1)) in + let dec = Z.div q.num q.den in + let padded_dec_string = Format.asprintf "%03d" (Z.to_int dec) in + Format.asprintf "%a.%s" Z.pp_print unit padded_dec_string + +let current_rewards_per_minute ctxt = + let open Lwt_result_syntax in + let base_total_rewards_per_minute = + (Constants.reward_weights ctxt).base_total_rewards_per_minute + in + let q_base_total_rewards_per_minute = + Tez.to_mutez base_total_rewards_per_minute |> Q.of_int64 + in + let cycle = (Level.current ctxt).cycle in + let* f = Delegate.Rewards.For_RPC.get_reward_coeff ctxt ~cycle in + let f = Q.mul f q_base_total_rewards_per_minute (* rewards per minute *) in + return f + +(* Does the reverse operations of [compute_coeff] in [adaptive_inflation_storage.ml] *) +let current_yearly_rate_value ~formatter ctxt = + let open Lwt_result_syntax in + let q_min_per_year = Q.of_int 525600 in + let* total_supply = Contract.get_total_supply ctxt in + let q_total_supply = Tez.to_mutez total_supply |> Q.of_int64 in + let* f = current_rewards_per_minute ctxt in + let f = Q.div f q_total_supply (* inflation per minute *) in + let f = Q.mul f q_min_per_year (* inflation per year *) in + (* transform into a string *) + let f = Q.(mul f (100 // 1)) in + return (formatter f) + let register () = let open Services_registration in + let open Lwt_result_syntax in register0 ~chunked:false S.total_supply (fun ctxt () () -> Contract.get_total_supply ctxt) ; register0 ~chunked:false S.total_frozen_stake (fun ctxt () () -> let cycle = (Level.current ctxt).cycle in - Stake_distribution.get_total_frozen_stake ctxt cycle) + Stake_distribution.get_total_frozen_stake ctxt cycle) ; + register0 ~chunked:false S.current_yearly_rate (fun ctxt () () -> + current_yearly_rate_value ~formatter:q_to_float_string ctxt) ; + register0 ~chunked:false S.current_yearly_rate_exact (fun ctxt () () -> + current_yearly_rate_value ~formatter:(fun x -> x) ctxt) ; + register0 ~chunked:false S.current_rewards_per_minute (fun ctxt () () -> + let* f = current_rewards_per_minute ctxt in + return (Tez.of_mutez_exn (Q.to_int64 f))) let total_supply ctxt block = RPC_context.make_call0 S.total_supply ctxt block () () let total_frozen_stake ctxt block = RPC_context.make_call0 S.total_frozen_stake ctxt block () () + +let current_yearly_rate ctxt block = + RPC_context.make_call0 S.current_yearly_rate ctxt block () () + +let current_yearly_rate_exact ctxt block = + RPC_context.make_call0 S.current_yearly_rate_exact ctxt block () () + +let current_rewards_per_minute ctxt block = + RPC_context.make_call0 S.current_rewards_per_minute ctxt block () () diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_services.mli b/src/proto_alpha/lib_protocol/adaptive_inflation_services.mli index d22b4b717032e30a8100aa38633adf6af000e239..651aa92f8c3153df141eedb3038c19943598a07b 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_services.mli +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_services.mli @@ -30,4 +30,13 @@ val total_supply : 'a #RPC_context.simple -> 'a -> Tez.t shell_tzresult Lwt.t val total_frozen_stake : 'a #RPC_context.simple -> 'a -> Tez.t shell_tzresult Lwt.t +val current_yearly_rate : + 'a #RPC_context.simple -> 'a -> string shell_tzresult Lwt.t + +val current_yearly_rate_exact : + 'a #RPC_context.simple -> 'a -> Q.t shell_tzresult Lwt.t + +val current_rewards_per_minute : + 'a #RPC_context.simple -> 'a -> Tez.t shell_tzresult Lwt.t + val register : unit -> unit diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml index a72ad9b43ddc53a9ca1aa9702185ebf101edba88..25682b3f9b894e8d7b8597627669ab2011ed890a 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml @@ -204,3 +204,7 @@ let load_reward_coeff ctxt = let init_ema ctxt = Storage.Adaptive_inflation.Launch_ema.init ctxt 0L let activate ctxt ~cycle = Storage.Adaptive_inflation.Activation.init ctxt cycle + +module For_RPC = struct + let get_reward_coeff = get_reward_coeff +end diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli index 898da8efcd3440dc40557bcf5ddbb2e22b1c317b..f49be6ce69b2b1a171d13ba0e25c62e973225bc9 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli @@ -54,3 +54,16 @@ val init_ema : Raw_context.t -> Raw_context.t tzresult Lwt.t voted to be activated (yet). *) val activate : Raw_context.t -> cycle:Cycle_repr.t -> Raw_context.t tzresult Lwt.t + +module For_RPC : sig + (** [get_reward_coeff ctxt cycle] reads the reward coeff for the given cycle + from the storage. + Returns [Q.one] if the given cycle is not between [current_cycle] and + [current_cycle + preserved_cycles]. + If adaptive inflation has not been activated, or has been activated and the + given cycle is less than [preserved_cycles] after the activation cycle, + then this function returns [Q.one]. + Used only for RPCs. To get the actual rewards, use [Delegate_rewards]. *) + val get_reward_coeff : + Raw_context.t -> cycle:Cycle_repr.t -> Q.t tzresult Lwt.t +end diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index 8559ab1bb052396a00d3c71266b167864bf6b034..04b75aef3703658fea484ccdfc9d20be2c2f84b3 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -499,7 +499,11 @@ module Delegate = struct let deactivated = Delegate_activation_storage.is_inactive module Consensus_key = Delegate_consensus_key - module Rewards = Delegate_rewards + + module Rewards = struct + include Delegate_rewards + module For_RPC = Adaptive_inflation_storage.For_RPC + end end module Stake_distribution = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 60f475e1bb24c0ec7d05915306753588021eb7f4..b8e035e4db64f33851601b6e0560c2783c651fcf 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2249,6 +2249,19 @@ module Delegate : sig val reward_from_constants : ?coeff:Q.t -> Constants.Parametric.t -> reward_kind:reward_kind -> Tez.t end + + module For_RPC : sig + (** [get_reward_coeff ctxt cycle] reads the reward coeff for the given cycle + from the storage. + Returns [Q.one] if the given cycle is not between [current_cycle] and + [current_cycle + preserved_cycles]. + If adaptive inflation has not been activated, or has been activated and the + given cycle is less than [preserved_cycles] after the activation cycle, + then this function returns [Q.one]. + Used only for RPCs. To get the actual rewards, use the reward functions + defined above. *) + val get_reward_coeff : t -> cycle:Cycle.t -> Q.t tzresult Lwt.t + end end end