v0.2.4-pre.002
This commit is contained in:
377
crates/ksp-onchain-transport-lib/src/rpc_economics.rs
Normal file
377
crates/ksp-onchain-transport-lib/src/rpc_economics.rs
Normal file
@@ -0,0 +1,377 @@
|
||||
// file: crates/ksp-onchain-transport-lib/src/rpc_economics.rs
|
||||
// version: 1
|
||||
|
||||
/// Inflation-governor values returned by `getInflationGovernor`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct SolanaInflationGovernor {
|
||||
initial: f64,
|
||||
terminal: f64,
|
||||
taper: f64,
|
||||
foundation: f64,
|
||||
foundation_term: f64,
|
||||
}
|
||||
|
||||
impl SolanaInflationGovernor {
|
||||
/// Returns the initial inflation rate.
|
||||
#[must_use]
|
||||
pub const fn initial(&self) -> f64 {
|
||||
return self.initial;
|
||||
}
|
||||
|
||||
/// Returns the terminal inflation rate.
|
||||
#[must_use]
|
||||
pub const fn terminal(&self) -> f64 {
|
||||
return self.terminal;
|
||||
}
|
||||
|
||||
/// Returns the taper/disinflation parameter reported by the runtime.
|
||||
#[must_use]
|
||||
pub const fn taper(&self) -> f64 {
|
||||
return self.taper;
|
||||
}
|
||||
|
||||
/// Returns the foundation allocation rate.
|
||||
#[must_use]
|
||||
pub const fn foundation(&self) -> f64 {
|
||||
return self.foundation;
|
||||
}
|
||||
|
||||
/// Returns the foundation allocation term.
|
||||
#[must_use]
|
||||
pub const fn foundation_term(&self) -> f64 {
|
||||
return self.foundation_term;
|
||||
}
|
||||
|
||||
/// Decodes an inflation-governor result from its Solana JSON wire shape.
|
||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
let decoded = crate::decode_wire_json::<WireInflationGovernor>(method, value);
|
||||
return match decoded {
|
||||
std::result::Result::Ok(wire) => std::result::Result::Ok(Self {
|
||||
initial: wire.initial,
|
||||
terminal: wire.terminal,
|
||||
taper: wire.taper,
|
||||
foundation: wire.foundation,
|
||||
foundation_term: wire.foundation_term,
|
||||
}),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Current inflation-rate values returned by `getInflationRate`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct SolanaInflationRate {
|
||||
total: f64,
|
||||
validator: f64,
|
||||
foundation: f64,
|
||||
epoch: u64,
|
||||
}
|
||||
|
||||
impl SolanaInflationRate {
|
||||
/// Returns the total inflation rate.
|
||||
#[must_use]
|
||||
pub const fn total(&self) -> f64 {
|
||||
return self.total;
|
||||
}
|
||||
|
||||
/// Returns the validator inflation rate.
|
||||
#[must_use]
|
||||
pub const fn validator(&self) -> f64 {
|
||||
return self.validator;
|
||||
}
|
||||
|
||||
/// Returns the foundation inflation rate.
|
||||
#[must_use]
|
||||
pub const fn foundation(&self) -> f64 {
|
||||
return self.foundation;
|
||||
}
|
||||
|
||||
/// Returns the epoch associated with the rate.
|
||||
#[must_use]
|
||||
pub const fn epoch(&self) -> u64 {
|
||||
return self.epoch;
|
||||
}
|
||||
|
||||
/// Decodes an inflation-rate result from its Solana JSON wire shape.
|
||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
let decoded = crate::decode_wire_json::<WireInflationRate>(method, value);
|
||||
return match decoded {
|
||||
std::result::Result::Ok(wire) => {
|
||||
std::result::Result::Ok(Self { total: wire.total, validator: wire.validator, foundation: wire.foundation, epoch: wire.epoch })
|
||||
},
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Optional epoch/context configuration accepted by `getInflationReward`.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct SolanaInflationRewardConfig {
|
||||
epoch: std::option::Option<u64>,
|
||||
commitment: std::option::Option<crate::SolanaCommitment>,
|
||||
min_context_slot: std::option::Option<u64>,
|
||||
}
|
||||
|
||||
impl SolanaInflationRewardConfig {
|
||||
/// Creates an inflation-reward configuration.
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
epoch: std::option::Option<u64>,
|
||||
commitment: std::option::Option<crate::SolanaCommitment>,
|
||||
min_context_slot: std::option::Option<u64>,
|
||||
) -> Self {
|
||||
return Self { epoch, commitment, min_context_slot };
|
||||
}
|
||||
|
||||
/// Returns the optional target epoch.
|
||||
#[must_use]
|
||||
pub const fn epoch(&self) -> std::option::Option<u64> {
|
||||
return self.epoch;
|
||||
}
|
||||
|
||||
/// Returns the optional commitment level.
|
||||
#[must_use]
|
||||
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> {
|
||||
return self.commitment;
|
||||
}
|
||||
|
||||
/// Returns the optional minimum context slot.
|
||||
#[must_use]
|
||||
pub const fn min_context_slot(&self) -> std::option::Option<u64> {
|
||||
return self.min_context_slot;
|
||||
}
|
||||
|
||||
/// Returns whether this config would serialize to an empty object.
|
||||
pub(crate) const fn is_empty(&self) -> bool {
|
||||
return self.epoch.is_none() && self.commitment.is_none() && self.min_context_slot.is_none();
|
||||
}
|
||||
|
||||
/// Serializes this config to the exact Solana JSON-RPC object.
|
||||
#[must_use]
|
||||
pub(crate) fn to_json_value(self) -> serde_json::Value {
|
||||
let mut object = serde_json::Map::new();
|
||||
if let std::option::Option::Some(epoch) = self.epoch {
|
||||
object.insert("epoch".to_owned(), serde_json::Value::Number(epoch.into()));
|
||||
}
|
||||
if let std::option::Option::Some(commitment) = self.commitment {
|
||||
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
|
||||
}
|
||||
if let std::option::Option::Some(min_context_slot) = self.min_context_slot {
|
||||
object.insert("minContextSlot".to_owned(), serde_json::Value::Number(min_context_slot.into()));
|
||||
}
|
||||
return serde_json::Value::Object(object);
|
||||
}
|
||||
}
|
||||
|
||||
/// One non-null positional reward returned by `getInflationReward`.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SolanaInflationReward {
|
||||
epoch: u64,
|
||||
effective_slot: u64,
|
||||
amount: u64,
|
||||
post_balance: u64,
|
||||
commission: std::option::Option<u8>,
|
||||
commission_bps: crate::SolanaWireField<u16>,
|
||||
}
|
||||
|
||||
impl SolanaInflationReward {
|
||||
/// Returns the rewarded epoch.
|
||||
#[must_use]
|
||||
pub const fn epoch(&self) -> u64 {
|
||||
return self.epoch;
|
||||
}
|
||||
|
||||
/// Returns the slot at which the reward became effective.
|
||||
#[must_use]
|
||||
pub const fn effective_slot(&self) -> u64 {
|
||||
return self.effective_slot;
|
||||
}
|
||||
|
||||
/// Returns the reward amount in lamports.
|
||||
#[must_use]
|
||||
pub const fn amount(&self) -> u64 {
|
||||
return self.amount;
|
||||
}
|
||||
|
||||
/// Returns the post-reward account balance in lamports.
|
||||
#[must_use]
|
||||
pub const fn post_balance(&self) -> u64 {
|
||||
return self.post_balance;
|
||||
}
|
||||
|
||||
/// Returns the nullable legacy/effective commission percentage.
|
||||
#[must_use]
|
||||
pub const fn commission(&self) -> std::option::Option<u8> {
|
||||
return self.commission;
|
||||
}
|
||||
|
||||
/// Returns the basis-point commission while preserving omitted/null/present wire states.
|
||||
#[must_use]
|
||||
pub const fn commission_bps(&self) -> &crate::SolanaWireField<u16> {
|
||||
return &self.commission_bps;
|
||||
}
|
||||
|
||||
/// Decodes one non-null inflation reward from its Solana JSON wire shape.
|
||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
let decoded = crate::decode_wire_json::<WireInflationReward>(method, value);
|
||||
return match decoded {
|
||||
std::result::Result::Ok(wire) => std::result::Result::Ok(Self {
|
||||
epoch: wire.epoch,
|
||||
effective_slot: wire.effective_slot,
|
||||
amount: wire.amount,
|
||||
post_balance: wire.post_balance,
|
||||
commission: wire.commission,
|
||||
commission_bps: wire.commission_bps,
|
||||
}),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Optional configuration accepted by `getSupply`.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct SolanaSupplyConfig {
|
||||
commitment: std::option::Option<crate::SolanaCommitment>,
|
||||
exclude_non_circulating_accounts_list: std::option::Option<bool>,
|
||||
}
|
||||
|
||||
impl SolanaSupplyConfig {
|
||||
/// Creates a supply configuration.
|
||||
#[must_use]
|
||||
pub const fn new(commitment: std::option::Option<crate::SolanaCommitment>, exclude_non_circulating_accounts_list: std::option::Option<bool>) -> Self {
|
||||
return Self { commitment, exclude_non_circulating_accounts_list };
|
||||
}
|
||||
|
||||
/// Returns the optional commitment level.
|
||||
#[must_use]
|
||||
pub const fn commitment(&self) -> std::option::Option<crate::SolanaCommitment> {
|
||||
return self.commitment;
|
||||
}
|
||||
|
||||
/// Returns whether the request explicitly controls omission of the non-circulating account list.
|
||||
#[must_use]
|
||||
pub const fn exclude_non_circulating_accounts_list(&self) -> std::option::Option<bool> {
|
||||
return self.exclude_non_circulating_accounts_list;
|
||||
}
|
||||
|
||||
/// Returns whether this config would serialize to an empty object.
|
||||
pub(crate) const fn is_empty(&self) -> bool {
|
||||
return self.commitment.is_none() && self.exclude_non_circulating_accounts_list.is_none();
|
||||
}
|
||||
|
||||
/// Serializes this config to the exact Solana JSON-RPC object.
|
||||
#[must_use]
|
||||
pub(crate) fn to_json_value(self) -> serde_json::Value {
|
||||
let mut object = serde_json::Map::new();
|
||||
if let std::option::Option::Some(commitment) = self.commitment {
|
||||
object.insert("commitment".to_owned(), serde_json::Value::String(commitment.as_str().to_owned()));
|
||||
}
|
||||
if let std::option::Option::Some(exclude) = self.exclude_non_circulating_accounts_list {
|
||||
object.insert("excludeNonCirculatingAccountsList".to_owned(), serde_json::Value::Bool(exclude));
|
||||
}
|
||||
return serde_json::Value::Object(object);
|
||||
}
|
||||
}
|
||||
|
||||
/// Supply totals returned inside the contextual `getSupply` response.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct SolanaSupply {
|
||||
total: u64,
|
||||
circulating: u64,
|
||||
non_circulating: u64,
|
||||
non_circulating_accounts: std::vec::Vec<ksp_core_lib::Pubkey>,
|
||||
}
|
||||
|
||||
impl SolanaSupply {
|
||||
/// Returns the total supply in lamports.
|
||||
#[must_use]
|
||||
pub const fn total(&self) -> u64 {
|
||||
return self.total;
|
||||
}
|
||||
|
||||
/// Returns the circulating supply in lamports.
|
||||
#[must_use]
|
||||
pub const fn circulating(&self) -> u64 {
|
||||
return self.circulating;
|
||||
}
|
||||
|
||||
/// Returns the non-circulating supply in lamports.
|
||||
#[must_use]
|
||||
pub const fn non_circulating(&self) -> u64 {
|
||||
return self.non_circulating;
|
||||
}
|
||||
|
||||
/// Returns the ordered non-circulating account list supplied by the runtime.
|
||||
#[must_use]
|
||||
pub fn non_circulating_accounts(&self) -> &[ksp_core_lib::Pubkey] {
|
||||
return self.non_circulating_accounts.as_slice();
|
||||
}
|
||||
|
||||
/// Decodes a supply result from its Solana JSON wire shape.
|
||||
pub(crate) fn decode_wire(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<Self> {
|
||||
let decoded = crate::decode_wire_json::<WireSupply>(method, value);
|
||||
let wire = match decoded {
|
||||
std::result::Result::Ok(wire) => wire,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let mut accounts = std::vec::Vec::with_capacity(wire.non_circulating_accounts.len());
|
||||
for account in wire.non_circulating_accounts {
|
||||
let parsed = crate::parse_wire_pubkey(method, "nonCirculatingAccounts", account.as_str());
|
||||
match parsed {
|
||||
std::result::Result::Ok(pubkey) => accounts.push(pubkey),
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
}
|
||||
}
|
||||
return std::result::Result::Ok(Self {
|
||||
total: wire.total,
|
||||
circulating: wire.circulating,
|
||||
non_circulating: wire.non_circulating,
|
||||
non_circulating_accounts: accounts,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WireInflationGovernor {
|
||||
initial: f64,
|
||||
terminal: f64,
|
||||
taper: f64,
|
||||
foundation: f64,
|
||||
foundation_term: f64,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WireInflationRate {
|
||||
total: f64,
|
||||
validator: f64,
|
||||
foundation: f64,
|
||||
epoch: u64,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WireInflationReward {
|
||||
epoch: u64,
|
||||
effective_slot: u64,
|
||||
amount: u64,
|
||||
post_balance: u64,
|
||||
#[serde(default)]
|
||||
commission: std::option::Option<u8>,
|
||||
#[serde(default)]
|
||||
commission_bps: crate::SolanaWireField<u16>,
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct WireSupply {
|
||||
total: u64,
|
||||
circulating: u64,
|
||||
non_circulating: u64,
|
||||
non_circulating_accounts: std::vec::Vec<std::string::String>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/rpc_economics.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user