Raw File
delegate_services.ml
(*****************************************************************************)
(*                                                                           *)
(* Open Source License                                                       *)
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com>     *)
(* Copyright (c) 2020 Metastate AG <hello@metastate.dev>                     *)
(* Copyright (c) 2021 Nomadic Labs, <contact@nomadic-labs.com>               *)
(*                                                                           *)
(* 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.                                                 *)
(*                                                                           *)
(*****************************************************************************)

open Alpha_context

type error += Balance_rpc_non_delegate of public_key_hash

type error += (* `Temporary *) Not_registered of Signature.Public_key_hash.t

let () =
  register_error_kind
    `Temporary
    ~id:"delegate.not_registered"
    ~title:"Not a registered delegate"
    ~description:
      "The provided public key hash is not the address of a registered \
       delegate."
    ~pp:(fun ppf pkh ->
      Format.fprintf
        ppf
        "The provided public key hash (%a) is not the address of a registered \
         delegate. If you own this account and want to register it as a \
         delegate, use a delegation operation to delegate the account to \
         itself."
        Signature.Public_key_hash.pp
        pkh)
    Data_encoding.(obj1 (req "pkh" Signature.Public_key_hash.encoding))
    (function Not_registered pkh -> Some pkh | _ -> None)
    (fun pkh -> Not_registered pkh)

let () =
  register_error_kind
    `Temporary
    ~id:"delegate_service.balance_rpc_on_non_delegate"
    ~title:"Balance request for an unregistered delegate"
    ~description:"The account whose balance was requested is not a delegate."
    ~pp:(fun ppf pkh ->
      Format.fprintf
        ppf
        "The implicit account (%a) whose balance was requested is not a \
         registered delegate. To get the balance of this account you can use \
         the ../context/contracts/%a/balance RPC."
        Signature.Public_key_hash.pp
        pkh
        Signature.Public_key_hash.pp
        pkh)
    Data_encoding.(obj1 (req "pkh" Signature.Public_key_hash.encoding))
    (function Balance_rpc_non_delegate pkh -> Some pkh | _ -> None)
    (fun pkh -> Balance_rpc_non_delegate pkh)

type consensus_key = {
  consensus_key_pkh : Signature.Public_key_hash.t;
  consensus_key_pk : Signature.Public_key.t;
}

let consensus_key_encoding =
  let open Data_encoding in
  conv
    (fun {consensus_key_pkh; consensus_key_pk} ->
      (consensus_key_pkh, consensus_key_pk))
    (fun (consensus_key_pkh, consensus_key_pk) ->
      {consensus_key_pkh; consensus_key_pk})
    (obj2
       (req "pkh" Signature.Public_key_hash.encoding)
       (req "pk" Signature.Public_key.encoding))

type consensus_keys_info = {
  active : consensus_key;
  pendings : (Cycle.t * consensus_key) list;
}

let consensus_key_info_encoding =
  let open Data_encoding in
  conv
    (fun {active; pendings} -> (active, pendings))
    (fun (active, pendings) -> {active; pendings})
    (obj2
       (req "active" consensus_key_encoding)
       (dft
          "pendings"
          (list
             (merge_objs
                (obj1 (req "cycle" Cycle.encoding))
                consensus_key_encoding))
          []))

type info = {
  full_balance : Tez.t;
  current_frozen_deposits : Tez.t;
  frozen_deposits : Tez.t;
  staking_balance : Tez.t;
  delegated_contracts : Contract.t list;
  delegated_balance : Tez.t;
  deactivated : bool;
  grace_period : Cycle.t;
  voting_info : Vote.delegate_info;
  active_consensus_key : Signature.Public_key_hash.t;
  pending_consensus_keys : (Cycle.t * Signature.Public_key_hash.t) list;
}

let info_encoding =
  let open Data_encoding in
  conv
    (fun {
           full_balance;
           current_frozen_deposits;
           frozen_deposits;
           staking_balance;
           delegated_contracts;
           delegated_balance;
           deactivated;
           grace_period;
           voting_info;
           active_consensus_key;
           pending_consensus_keys;
         } ->
      ( ( full_balance,
          current_frozen_deposits,
          frozen_deposits,
          staking_balance,
          delegated_contracts,
          delegated_balance,
          deactivated,
          grace_period ),
        (voting_info, (active_consensus_key, pending_consensus_keys)) ))
    (fun ( ( full_balance,
             current_frozen_deposits,
             frozen_deposits,
             staking_balance,
             delegated_contracts,
             delegated_balance,
             deactivated,
             grace_period ),
           (voting_info, (active_consensus_key, pending_consensus_keys)) ) ->
      {
        full_balance;
        current_frozen_deposits;
        frozen_deposits;
        staking_balance;
        delegated_contracts;
        delegated_balance;
        deactivated;
        grace_period;
        voting_info;
        active_consensus_key;
        pending_consensus_keys;
      })
    (merge_objs
       (obj8
          (req "full_balance" Tez.encoding)
          (req "current_frozen_deposits" Tez.encoding)
          (req "frozen_deposits" Tez.encoding)
          (req "staking_balance" Tez.encoding)
          (req "delegated_contracts" (list Contract.encoding))
          (req "delegated_balance" Tez.encoding)
          (req "deactivated" bool)
          (req "grace_period" Cycle.encoding))
       (merge_objs
          Vote.delegate_info_encoding
          (obj2
             (req "active_consensus_key" Signature.Public_key_hash.encoding)
             (dft
                "pending_consensus_keys"
                (list
                   (obj2
                      (req "cycle" Cycle.encoding)
                      (req "pkh" Signature.Public_key_hash.encoding)))
                []))))

let participation_info_encoding =
  let open Data_encoding in
  conv
    (fun {
           Delegate.expected_cycle_activity;
           minimal_cycle_activity;
           missed_slots;
           missed_levels;
           remaining_allowed_missed_slots;
           expected_endorsing_rewards;
         } ->
      ( expected_cycle_activity,
        minimal_cycle_activity,
        missed_slots,
        missed_levels,
        remaining_allowed_missed_slots,
        expected_endorsing_rewards ))
    (fun ( expected_cycle_activity,
           minimal_cycle_activity,
           missed_slots,
           missed_levels,
           remaining_allowed_missed_slots,
           expected_endorsing_rewards ) ->
      {
        expected_cycle_activity;
        minimal_cycle_activity;
        missed_slots;
        missed_levels;
        remaining_allowed_missed_slots;
        expected_endorsing_rewards;
      })
    (obj6
       (req "expected_cycle_activity" int31)
       (req "minimal_cycle_activity" int31)
       (req "missed_slots" int31)
       (req "missed_levels" int31)
       (req "remaining_allowed_missed_slots" int31)
       (req "expected_endorsing_rewards" Tez.encoding))

type deposit_per_cycle = {cycle : Cycle.t; deposit : Tez.t}

let deposit_per_cycle_encoding : deposit_per_cycle Data_encoding.t =
  let open Data_encoding in
  conv
    (fun {cycle; deposit} -> (cycle, deposit))
    (fun (cycle, deposit) -> {cycle; deposit})
    (obj2 (req "cycle" Cycle.encoding) (req "deposit" Tez.encoding))

module S = struct
  let raw_path = RPC_path.(open_root / "context" / "delegates")

  open Data_encoding

  type list_query = {
    active : bool;
    inactive : bool;
    with_minimal_stake : bool;
    without_minimal_stake : bool;
  }

  let list_query : list_query RPC_query.t =
    let open RPC_query in
    query (fun active inactive with_minimal_stake without_minimal_stake ->
        {active; inactive; with_minimal_stake; without_minimal_stake})
    |+ flag "active" (fun t -> t.active)
    |+ flag "inactive" (fun t -> t.inactive)
    |+ flag "with_minimal_stake" (fun t -> t.with_minimal_stake)
    |+ flag "without_minimal_stake" (fun t -> t.without_minimal_stake)
    |> seal

  let list_delegate =
    RPC_service.get_service
      ~description:
        "Lists all registered delegates by default. The arguments `active`, \
         `inactive`, `with_minimal_stake`, and `without_minimal_stake` allow \
         to enumerate only the delegates that are active, inactive, have at \
         least a minimal stake to participate in consensus and in governance, \
         or do not have such a minimal stake, respectively. Note, setting \
         these arguments to false has no effect."
      ~query:list_query
      ~output:(list Signature.Public_key_hash.encoding)
      raw_path

  let path = RPC_path.(raw_path /: Signature.Public_key_hash.rpc_arg)

  let info =
    RPC_service.get_service
      ~description:"Everything about a delegate."
      ~query:RPC_query.empty
      ~output:info_encoding
      path

  let full_balance =
    RPC_service.get_service
      ~description:
        "Returns the full balance (in mutez) of a given delegate, including \
         the frozen deposits and the frozen bonds. It does not include its \
         delegated balance."
      ~query:RPC_query.empty
      ~output:Tez.encoding
      RPC_path.(path / "full_balance")

  let current_frozen_deposits =
    RPC_service.get_service
      ~description:
        "Returns the current amount of the frozen deposits (in mutez)."
      ~query:RPC_query.empty
      ~output:Tez.encoding
      RPC_path.(path / "current_frozen_deposits")

  let frozen_deposits =
    RPC_service.get_service
      ~description:
        "Returns the initial amount (that is, at the beginning of a cycle) of \
         the frozen deposits (in mutez). This amount is the same as the \
         current amount of the frozen deposits, unless the delegate has been \
         punished."
      ~query:RPC_query.empty
      ~output:Tez.encoding
      RPC_path.(path / "frozen_deposits")

  let unstaked_frozen_deposits =
    RPC_service.get_service
      ~description:
        "Returns, for each cycle, the sum of unstaked-but-frozen deposits for \
         this cycle. Cycles go from the last unslashable cycle to the current \
         cycle."
      ~query:RPC_query.empty
      ~output:(Data_encoding.list deposit_per_cycle_encoding)
      RPC_path.(path / "unstaked_frozen_deposits")

  let staking_balance =
    RPC_service.get_service
      ~description:
        "Returns the total amount of tokens (in mutez) delegated to a given \
         delegate. This includes the balances of all the contracts that \
         delegate to it, but also the balance of the delegate itself, its \
         frozen deposits, and its frozen bonds."
      ~query:RPC_query.empty
      ~output:Tez.encoding
      RPC_path.(path / "staking_balance")

  let delegated_contracts =
    RPC_service.get_service
      ~description:
        "Returns the list of contracts that delegate to a given delegate."
      ~query:RPC_query.empty
      ~output:(list Contract.encoding)
      RPC_path.(path / "delegated_contracts")

  let delegated_balance =
    RPC_service.get_service
      ~description:
        "Returns the sum (in mutez) of all balances of all the contracts that \
         delegate to a given delegate. This excludes the delegate's own \
         balance, its frozen deposits and its frozen bonds."
      ~query:RPC_query.empty
      ~output:Tez.encoding
      RPC_path.(path / "delegated_balance")

  let deactivated =
    RPC_service.get_service
      ~description:
        "Tells whether the delegate is currently tagged as deactivated or not."
      ~query:RPC_query.empty
      ~output:bool
      RPC_path.(path / "deactivated")

  let grace_period =
    RPC_service.get_service
      ~description:
        "Returns the cycle by the end of which the delegate might be \
         deactivated if she fails to execute any delegate action. A \
         deactivated delegate might be reactivated (without loosing any stake) \
         by simply re-registering as a delegate. For deactivated delegates, \
         this value contains the cycle at which they were deactivated."
      ~query:RPC_query.empty
      ~output:Cycle.encoding
      RPC_path.(path / "grace_period")

  let current_voting_power =
    RPC_service.get_service
      ~description:
        "The voting power of a given delegate, as computed from its current \
         stake."
      ~query:RPC_query.empty
      ~output:Data_encoding.int64
      RPC_path.(path / "current_voting_power")

  let voting_power =
    RPC_service.get_service
      ~description:"The voting power in the vote listings for a given delegate."
      ~query:RPC_query.empty
      ~output:Data_encoding.int64
      RPC_path.(path / "voting_power")

  let baking_power =
    RPC_service.get_service
      ~description:
        "The baking power for a given delegate from the selected stake \
         snapshot of the current cycle. This is the baking power which will be \
         used preserved_cycles after the current cycle to compute the baking \
         and endorsing rights."
      ~query:RPC_query.empty
      ~output:Data_encoding.int64
      RPC_path.(path / "baking_power")

  let current_baking_power =
    RPC_service.get_service
      ~description:
        "The baking power of a delegate, as computed from its current stake. \
         Contrary to the value returned by the baking_power endpoint, this \
         value is not used for computing baking rights but only reflects the \
         baking power that the delegate would have if a snapshot was taken at \
         the current block."
      ~query:RPC_query.empty
      ~output:Data_encoding.int64
      RPC_path.(path / "current_baking_power")

  let voting_info =
    RPC_service.get_service
      ~description:
        "Returns the delegate info (e.g. voting power) found in the listings \
         of the current voting period."
      ~query:RPC_query.empty
      ~output:Vote.delegate_info_encoding
      RPC_path.(path / "voting_info")

  let consensus_key =
    RPC_service.get_service
      ~description:
        "The active consensus key for a given delegate and the pending \
         consensus keys."
      ~query:RPC_query.empty
      ~output:consensus_key_info_encoding
      RPC_path.(path / "consensus_key")

  let participation =
    RPC_service.get_service
      ~description:
        "Returns cycle and level participation information. In particular this \
         indicates, in the field 'expected_cycle_activity', the number of \
         slots the delegate is expected to have in the cycle based on its \
         active stake. The field 'minimal_cycle_activity' indicates the \
         minimal endorsing slots in the cycle required to get endorsing \
         rewards. It is computed based on 'expected_cycle_activity. The fields \
         'missed_slots' and 'missed_levels' indicate the number of missed \
         endorsing slots and missed levels (for endorsing) in the cycle so \
         far. 'missed_slots' indicates the number of missed endorsing slots in \
         the cycle so far. The field 'remaining_allowed_missed_slots' \
         indicates the remaining amount of endorsing slots that can be missed \
         in the cycle before forfeiting the rewards. Finally, \
         'expected_endorsing_rewards' indicates the endorsing rewards that \
         will be distributed at the end of the cycle if activity at that point \
         will be greater than the minimal required; if the activity is already \
         known to be below the required minimum, then the rewards are zero."
      ~query:RPC_query.empty
      ~output:participation_info_encoding
      RPC_path.(path / "participation")
end

let check_delegate_registered ctxt pkh =
  Delegate.registered ctxt pkh >>= function
  | true -> return_unit
  | false -> tzfail (Not_registered pkh)

let register () =
  let open Services_registration in
  register0 ~chunked:true S.list_delegate (fun ctxt q () ->
      Delegate.list ctxt >>= fun delegates ->
      (match q with
      | {active = true; inactive = false; _} ->
          List.filter_es
            (fun pkh -> Delegate.deactivated ctxt pkh >|=? not)
            delegates
      | {active = false; inactive = true; _} ->
          List.filter_es (fun pkh -> Delegate.deactivated ctxt pkh) delegates
      | {active = false; inactive = false; _}
      (* This case is counter-intuitive, but it represents the default behavior, when no arguments are given *)
      | {active = true; inactive = true; _} ->
          return delegates)
      >>=? fun delegates ->
      let minimal_stake = Constants.minimal_stake ctxt in
      match q with
      | {with_minimal_stake = true; without_minimal_stake = false; _} ->
          List.filter_es
            (fun pkh ->
              Delegate.staking_balance ctxt pkh >|=? fun staking_balance ->
              Tez.(staking_balance >= minimal_stake))
            delegates
      | {with_minimal_stake = false; without_minimal_stake = true; _} ->
          List.filter_es
            (fun pkh ->
              Delegate.staking_balance ctxt pkh >|=? fun staking_balance ->
              Tez.(staking_balance < minimal_stake))
            delegates
      | {with_minimal_stake = true; without_minimal_stake = true; _}
      | {with_minimal_stake = false; without_minimal_stake = false; _} ->
          return delegates) ;
  register1 ~chunked:false S.info (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.For_RPC.full_balance ctxt pkh >>=? fun full_balance ->
      Delegate.frozen_deposits ctxt pkh >>=? fun frozen_deposits ->
      Delegate.staking_balance ctxt pkh >>=? fun staking_balance ->
      Delegate.delegated_contracts ctxt pkh >>= fun delegated_contracts ->
      Delegate.For_RPC.delegated_balance ctxt pkh >>=? fun delegated_balance ->
      Delegate.deactivated ctxt pkh >>=? fun deactivated ->
      Delegate.last_cycle_before_deactivation ctxt pkh >>=? fun grace_period ->
      Vote.get_delegate_info ctxt pkh >>=? fun voting_info ->
      Delegate.Consensus_key.active_pubkey ctxt pkh >>=? fun consensus_key ->
      Delegate.Consensus_key.pending_updates ctxt pkh >|=? fun pendings ->
      let pending_consensus_keys =
        List.map (fun (cycle, pkh, _) -> (cycle, pkh)) pendings
      in
      {
        full_balance;
        current_frozen_deposits = frozen_deposits.current_amount;
        frozen_deposits = frozen_deposits.initial_amount;
        staking_balance;
        delegated_contracts;
        delegated_balance;
        deactivated;
        grace_period;
        voting_info;
        active_consensus_key = consensus_key.consensus_pkh;
        pending_consensus_keys;
      }) ;
  register1 ~chunked:false S.full_balance (fun ctxt pkh () () ->
      trace (Balance_rpc_non_delegate pkh) (check_delegate_registered ctxt pkh)
      >>=? fun () -> Delegate.For_RPC.full_balance ctxt pkh) ;
  register1 ~chunked:false S.current_frozen_deposits (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.frozen_deposits ctxt pkh >>=? fun deposits ->
      return deposits.current_amount) ;
  register1 ~chunked:false S.frozen_deposits (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.frozen_deposits ctxt pkh >>=? fun deposits ->
      return deposits.initial_amount) ;
  register1 ~chunked:false S.unstaked_frozen_deposits (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      let ctxt_cycle = (Alpha_context.Level.current ctxt).cycle in
      let csts = (Constants.all ctxt).parametric in
      let last_unslashable_cycle =
        Option.value ~default:Cycle.root
        @@ Cycle.sub
             ctxt_cycle
             (csts.preserved_cycles + csts.max_slashing_period)
      in
      let cycles = Cycle.(last_unslashable_cycle ---> ctxt_cycle) in
      List.map_es
        (fun cycle ->
          Unstaked_frozen_deposits.balance ctxt pkh cycle >>=? fun deposit ->
          return (cycle, deposit))
        cycles
      >>=? fun requests ->
      Alpha_context.Unstake_requests.For_RPC
      .apply_slash_to_unstaked_unfinalizable
        ctxt
        ~delegate:pkh
        ~requests
      >>=? List.map_es (fun (cycle, deposit) -> return {cycle; deposit})) ;
  register1 ~chunked:false S.staking_balance (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.staking_balance ctxt pkh) ;
  register1 ~chunked:true S.delegated_contracts (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.delegated_contracts ctxt pkh >|= ok) ;
  register1 ~chunked:false S.delegated_balance (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.For_RPC.delegated_balance ctxt pkh) ;
  register1 ~chunked:false S.deactivated (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.deactivated ctxt pkh) ;
  register1 ~chunked:false S.grace_period (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.last_cycle_before_deactivation ctxt pkh) ;
  register1 ~chunked:false S.current_voting_power (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Vote.get_current_voting_power_free ctxt pkh) ;
  register1 ~chunked:false S.voting_power (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Vote.get_voting_power_free ctxt pkh) ;
  register1 ~chunked:false S.baking_power (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      let cycle = (Level.current ctxt).cycle in
      Stake_distribution.For_RPC.delegate_baking_power_for_cycle ctxt cycle pkh) ;
  register1 ~chunked:false S.current_baking_power (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Stake_distribution.For_RPC.delegate_current_baking_power ctxt pkh) ;
  register1 ~chunked:false S.voting_info (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Vote.get_delegate_info ctxt pkh) ;
  register1 ~chunked:false S.consensus_key (fun ctxt pkh () () ->
      Delegate.Consensus_key.active_pubkey ctxt pkh
      >>=? fun {
                 consensus_pk = consensus_key_pk;
                 consensus_pkh = consensus_key_pkh;
                 _;
               } ->
      Delegate.Consensus_key.pending_updates ctxt pkh >>=? fun pendings ->
      let pendings =
        List.map
          (fun (cycle, consensus_key_pkh, consensus_key_pk) ->
            (cycle, {consensus_key_pk; consensus_key_pkh}))
          pendings
      in
      return {active = {consensus_key_pk; consensus_key_pkh}; pendings}) ;
  register1 ~chunked:false S.participation (fun ctxt pkh () () ->
      check_delegate_registered ctxt pkh >>=? fun () ->
      Delegate.participation_info ctxt pkh)

let list ctxt block ?(active = true) ?(inactive = false)
    ?(with_minimal_stake = true) ?(without_minimal_stake = false) () =
  RPC_context.make_call0
    S.list_delegate
    ctxt
    block
    {active; inactive; with_minimal_stake; without_minimal_stake}
    ()

let info ctxt block pkh = RPC_context.make_call1 S.info ctxt block pkh () ()

let full_balance ctxt block pkh =
  RPC_context.make_call1 S.full_balance ctxt block pkh () ()

let current_frozen_deposits ctxt block pkh =
  RPC_context.make_call1 S.current_frozen_deposits ctxt block pkh () ()

let frozen_deposits ctxt block pkh =
  RPC_context.make_call1 S.frozen_deposits ctxt block pkh () ()

let unstaked_frozen_deposits ctxt block pkh =
  RPC_context.make_call1 S.unstaked_frozen_deposits ctxt block pkh () ()

let staking_balance ctxt block pkh =
  RPC_context.make_call1 S.staking_balance ctxt block pkh () ()

let delegated_contracts ctxt block pkh =
  RPC_context.make_call1 S.delegated_contracts ctxt block pkh () ()

let delegated_balance ctxt block pkh =
  RPC_context.make_call1 S.delegated_balance ctxt block pkh () ()

let deactivated ctxt block pkh =
  RPC_context.make_call1 S.deactivated ctxt block pkh () ()

let grace_period ctxt block pkh =
  RPC_context.make_call1 S.grace_period ctxt block pkh () ()

let voting_power ctxt block pkh =
  RPC_context.make_call1 S.voting_power ctxt block pkh () ()

let current_voting_power ctxt block pkh =
  RPC_context.make_call1 S.current_voting_power ctxt block pkh () ()

let baking_power ctxt block pkh =
  RPC_context.make_call1 S.baking_power ctxt block pkh () ()

let current_baking_power ctxt block pkh =
  RPC_context.make_call1 S.current_baking_power ctxt block pkh () ()

let voting_info ctxt block pkh =
  RPC_context.make_call1 S.voting_info ctxt block pkh () ()

let consensus_key ctxt block pkh =
  RPC_context.make_call1 S.consensus_key ctxt block pkh () ()

let participation ctxt block pkh =
  RPC_context.make_call1 S.participation ctxt block pkh () ()
back to top