// file: kb-onchain-transport/src/standard_http_economics.rs // version: 2 //! Configurable standard inflation, supply and stake-economics HTTP requests. /// Inflation governor parameters. #[derive(Clone, Copy, Debug, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcInflationGovernor { /// Initial inflation rate. pub initial: f64, /// Terminal inflation rate. pub terminal: f64, /// Annual taper rate. pub taper: f64, /// Foundation allocation rate. pub foundation: f64, /// Foundation allocation term in years. pub foundation_term: f64, } /// Inflation rates for the current epoch. #[derive(Clone, Copy, Debug, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcInflationRate { /// Total inflation rate. pub total: f64, /// Validator inflation rate. pub validator: f64, /// Foundation inflation rate. pub foundation: f64, /// Epoch represented by the rates. pub epoch: u64, } /// Inflation reward credited to one requested address. #[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcInflationReward { /// Reward epoch. pub epoch: u64, /// First effective slot of the rewarded epoch. pub effective_slot: u64, /// Reward amount in lamports. pub amount: u64, /// Account balance after the reward. pub post_balance: u64, /// Legacy vote commission percentage when applicable. pub commission: std::option::Option, /// Vote commission in basis points when exposed by the node. #[serde(default, skip_serializing_if = "std::option::Option::is_none")] pub commission_bps: std::option::Option, } /// Current lamport supply breakdown. #[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcSupply { /// Total lamport supply. pub total: u64, /// Circulating lamport supply. pub circulating: u64, /// Non-circulating lamport supply. pub non_circulating: u64, /// Non-circulating account list when requested. #[serde(default)] pub non_circulating_accounts: std::vec::Vec, } /// Optional commitment accepted by `getInflationGovernor`. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcInflationGovernorConfig { /// Optional commitment level. #[serde(skip_serializing_if = "std::option::Option::is_none")] pub commitment: std::option::Option, } /// Epoch and contextual options accepted by `getInflationReward`. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcEpochConfig { /// Optional reward epoch. #[serde(skip_serializing_if = "std::option::Option::is_none")] pub epoch: std::option::Option, /// Optional commitment level. #[serde(skip_serializing_if = "std::option::Option::is_none")] pub commitment: std::option::Option, /// Optional minimum context slot. #[serde(skip_serializing_if = "std::option::Option::is_none")] pub min_context_slot: std::option::Option, } /// Options accepted by `getSupply`. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct RpcSupplyConfig { /// Optional commitment level. #[serde(skip_serializing_if = "std::option::Option::is_none")] pub commitment: std::option::Option, /// Optional omission of the potentially large non-circulating account list. #[serde(skip_serializing_if = "std::option::Option::is_none")] pub exclude_non_circulating_accounts_list: std::option::Option, } /// Typed `getInflationGovernor` request. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct GetInflationGovernorRequest { /// Optional commitment configuration. pub config: std::option::Option, } impl crate::StandardHttpRequest for crate::GetInflationGovernorRequest { type Response = crate::RpcInflationGovernor; const METHOD: &'static str = "getInflationGovernor"; fn params(&self) -> kb_core::Result> { if let std::option::Option::Some(config) = &self.config { let value = match crate::serialize_parameter(Self::METHOD, config) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; return std::result::Result::Ok(std::vec![value]); } return std::result::Result::Ok(std::vec::Vec::new()); } } /// Typed `getInflationRate` request. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct GetInflationRateRequest; impl crate::StandardHttpRequest for crate::GetInflationRateRequest { type Response = crate::RpcInflationRate; const METHOD: &'static str = "getInflationRate"; fn params(&self) -> kb_core::Result> { return std::result::Result::Ok(std::vec::Vec::new()); } } /// Typed `getInflationReward` request. #[derive(Clone, Debug, Eq, PartialEq)] pub struct GetInflationRewardRequest { /// Account public keys whose rewards are requested, in response order. pub addresses: std::vec::Vec, /// Optional epoch, commitment and minimum-context options. pub config: std::option::Option, } impl crate::StandardHttpRequest for crate::GetInflationRewardRequest { type Response = std::vec::Vec>; const METHOD: &'static str = "getInflationReward"; fn params(&self) -> kb_core::Result> { let validation_result = crate::validate_pubkey_list(&self.addresses, "getInflationReward address", usize::MAX); if let std::result::Result::Err(error) = validation_result { return std::result::Result::Err(error); } let addresses = match crate::serialize_parameter(Self::METHOD, &self.addresses) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let mut params = std::vec![addresses]; if let std::option::Option::Some(config) = &self.config { let value = match crate::serialize_parameter(Self::METHOD, config) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; params.push(value); } return std::result::Result::Ok(params); } } /// Typed `getStakeMinimumDelegation` request. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct GetStakeMinimumDelegationRequest { /// Optional commitment and minimum-context options. pub config: std::option::Option, } impl crate::StandardHttpRequest for crate::GetStakeMinimumDelegationRequest { type Response = crate::RpcResponse; const METHOD: &'static str = "getStakeMinimumDelegation"; fn params(&self) -> kb_core::Result> { if let std::option::Option::Some(config) = &self.config { let value = match crate::serialize_parameter(Self::METHOD, config) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; return std::result::Result::Ok(std::vec![value]); } return std::result::Result::Ok(std::vec::Vec::new()); } } /// Typed `getSupply` request. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct GetSupplyRequest { /// Optional commitment and non-circulating-list options. pub config: std::option::Option, } impl crate::StandardHttpRequest for crate::GetSupplyRequest { type Response = crate::RpcResponse; const METHOD: &'static str = "getSupply"; fn params(&self) -> kb_core::Result> { if let std::option::Option::Some(config) = &self.config { let value = match crate::serialize_parameter(Self::METHOD, config) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return std::result::Result::Err(error), }; return std::result::Result::Ok(std::vec![value]); } return std::result::Result::Ok(std::vec::Vec::new()); } } #[cfg(test)] mod tests { fn pubkey(seed: u8) -> std::string::String { return bs58::encode([seed; 32]).into_string(); } #[test] fn supply_distinguishes_omitted_and_explicit_false_option() { let omitted = crate::GetSupplyRequest { config: std::option::Option::Some(crate::RpcSupplyConfig { commitment: std::option::Option::Some(crate::RpcCommitmentLevel::Finalized), exclude_non_circulating_accounts_list: std::option::Option::None, }), }; let explicit = crate::GetSupplyRequest { config: std::option::Option::Some(crate::RpcSupplyConfig { commitment: std::option::Option::Some(crate::RpcCommitmentLevel::Finalized), exclude_non_circulating_accounts_list: std::option::Option::Some(false), }), }; let omitted_params = match crate::StandardHttpRequest::params(&omitted) { std::result::Result::Ok(params) => params, std::result::Result::Err(error) => panic!("params failed: {error}"), }; let explicit_params = match crate::StandardHttpRequest::params(&explicit) { std::result::Result::Ok(params) => params, std::result::Result::Err(error) => panic!("params failed: {error}"), }; assert!(omitted_params[0].get("excludeNonCirculatingAccountsList").is_none()); assert_eq!( explicit_params[0]["excludeNonCirculatingAccountsList"], serde_json::Value::Bool(false) ); } #[test] fn inflation_reward_preserves_epoch_commitment_and_minimum_context() { let request = crate::GetInflationRewardRequest { addresses: std::vec![pubkey(1), pubkey(2)], config: std::option::Option::Some(crate::RpcEpochConfig { epoch: std::option::Option::Some(44), commitment: std::option::Option::Some(crate::RpcCommitmentLevel::Confirmed), min_context_slot: std::option::Option::Some(99), }), }; let params = match crate::StandardHttpRequest::params(&request) { std::result::Result::Ok(params) => params, std::result::Result::Err(error) => panic!("params failed: {error}"), }; assert_eq!(params[1]["epoch"], serde_json::Value::from(44_u64)); assert_eq!(params[1]["commitment"], serde_json::Value::String("confirmed".to_string())); assert_eq!(params[1]["minContextSlot"], serde_json::Value::from(99_u64)); let reward = match serde_json::from_value::(serde_json::json!({ "epoch": 44, "effectiveSlot": 100, "amount": 200, "postBalance": 300, "commission": 5, "commissionBps": 575 })) { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => panic!("inflation reward parsing failed: {error}"), }; assert_eq!(reward.commission, std::option::Option::Some(5)); assert_eq!(reward.commission_bps, std::option::Option::Some(575)); let empty = crate::GetInflationRewardRequest { addresses: std::vec::Vec::new(), config: std::option::Option::None, }; let empty_params = match crate::StandardHttpRequest::params(&empty) { std::result::Result::Ok(params) => params, std::result::Result::Err(error) => panic!("empty params failed: {error}"), }; assert_eq!(empty_params, std::vec![serde_json::json!([])]); } }