592 lines
22 KiB
Rust
592 lines
22 KiB
Rust
// file: crates/ksp-onchain-transport-lib/src/rpc_economics.rs
|
|
// version: 6
|
|
|
|
/// 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,
|
|
});
|
|
}
|
|
}
|
|
|
|
impl crate::HttpTransportPool {
|
|
/// Executes typed `getInflationGovernor` and returns the runtime-provided schedule values unchanged.
|
|
pub async fn get_inflation_governor(
|
|
&self,
|
|
role: &crate::HttpRoleName,
|
|
config: std::option::Option<&crate::SolanaCommitmentConfig>,
|
|
) -> ksp_core_lib::Result<crate::SolanaInflationGovernor> {
|
|
let mut params = std::vec::Vec::new();
|
|
push_economics_commitment_config(&mut params, config);
|
|
let value = self.execute_economics_rpc("getInflationGovernor", role, params).await;
|
|
return match value {
|
|
std::result::Result::Ok(value) => crate::SolanaInflationGovernor::decode_wire("getInflationGovernor", value),
|
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
|
};
|
|
}
|
|
|
|
/// Executes typed `getInflationRate` without locally recalculating the inflation schedule.
|
|
pub async fn get_inflation_rate(&self, role: &crate::HttpRoleName) -> ksp_core_lib::Result<crate::SolanaInflationRate> {
|
|
let value = self.execute_economics_rpc("getInflationRate", role, std::vec::Vec::new()).await;
|
|
return match value {
|
|
std::result::Result::Ok(value) => crate::SolanaInflationRate::decode_wire("getInflationRate", value),
|
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
|
};
|
|
}
|
|
|
|
/// Executes typed `getInflationReward`, preserving input order, positional nulls and runtime commission extensions.
|
|
pub async fn get_inflation_reward(
|
|
&self,
|
|
role: &crate::HttpRoleName,
|
|
addresses: &[ksp_core_lib::Pubkey],
|
|
config: std::option::Option<&crate::SolanaInflationRewardConfig>,
|
|
) -> ksp_core_lib::Result<std::vec::Vec<std::option::Option<crate::SolanaInflationReward>>> {
|
|
if let std::option::Option::Some(config) = config
|
|
&& config.commitment() == std::option::Option::Some(crate::SolanaCommitment::Processed)
|
|
{
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(
|
|
crate::ERROR_CODE_INVALID_RPC_PARAMETERS,
|
|
"getInflationReward commitment must be confirmed or finalized when explicitly provided",
|
|
)
|
|
.with_context("rpc_method", "getInflationReward")
|
|
.with_context("commitment", "processed"),
|
|
);
|
|
}
|
|
let address_values = addresses.iter().map(|address| return serde_json::Value::String(address.to_string())).collect::<std::vec::Vec<_>>();
|
|
let mut params = std::vec![serde_json::Value::Array(address_values)];
|
|
if let std::option::Option::Some(config) = config
|
|
&& !config.is_empty()
|
|
{
|
|
params.push((*config).to_json_value());
|
|
}
|
|
let value = self.execute_economics_rpc("getInflationReward", role, params).await;
|
|
let value = match value {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return decode_inflation_rewards("getInflationReward", value, addresses.len());
|
|
}
|
|
|
|
/// Executes typed `getStakeMinimumDelegation` and preserves the contextual runtime value in lamports.
|
|
pub async fn get_stake_minimum_delegation(
|
|
&self,
|
|
role: &crate::HttpRoleName,
|
|
config: std::option::Option<&crate::SolanaContextConfig>,
|
|
) -> ksp_core_lib::Result<crate::SolanaRpcResponse<u64>> {
|
|
let mut params = std::vec::Vec::new();
|
|
push_economics_context_config(&mut params, config);
|
|
let value = self.execute_economics_rpc("getStakeMinimumDelegation", role, params).await;
|
|
let value = match value {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return decode_economics_u64_response("getStakeMinimumDelegation", value);
|
|
}
|
|
|
|
/// Executes typed `getSupply`, preserving the explicit account-list exclusion flag and contextual totals.
|
|
pub async fn get_supply(
|
|
&self,
|
|
role: &crate::HttpRoleName,
|
|
config: std::option::Option<&crate::SolanaSupplyConfig>,
|
|
) -> ksp_core_lib::Result<crate::SolanaRpcResponse<crate::SolanaSupply>> {
|
|
let mut params = std::vec::Vec::new();
|
|
if let std::option::Option::Some(config) = config
|
|
&& !config.is_empty()
|
|
{
|
|
params.push((*config).to_json_value());
|
|
}
|
|
let value = self.execute_economics_rpc("getSupply", role, params).await;
|
|
let value = match value {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return decode_supply_response("getSupply", value);
|
|
}
|
|
|
|
async fn execute_economics_rpc(
|
|
&self,
|
|
method_name: &'static str,
|
|
role: &crate::HttpRoleName,
|
|
params: std::vec::Vec<serde_json::Value>,
|
|
) -> ksp_core_lib::Result<serde_json::Value> {
|
|
let descriptor = economics_descriptor(method_name);
|
|
let descriptor = match descriptor {
|
|
std::result::Result::Ok(descriptor) => descriptor,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return self.execute_standard_rpc(role, descriptor, params).await;
|
|
}
|
|
}
|
|
|
|
#[derive(serde::Deserialize)]
|
|
struct WireEconomicsRpcResponse<T> {
|
|
context: serde_json::Value,
|
|
value: T,
|
|
}
|
|
|
|
#[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>,
|
|
}
|
|
|
|
fn push_economics_commitment_config(params: &mut std::vec::Vec<serde_json::Value>, config: std::option::Option<&crate::SolanaCommitmentConfig>) {
|
|
if let std::option::Option::Some(config) = config
|
|
&& config.commitment().is_some()
|
|
{
|
|
params.push((*config).to_json_value());
|
|
}
|
|
return;
|
|
}
|
|
|
|
fn push_economics_context_config(params: &mut std::vec::Vec<serde_json::Value>, config: std::option::Option<&crate::SolanaContextConfig>) {
|
|
if let std::option::Option::Some(config) = config
|
|
&& (config.commitment().is_some() || config.min_context_slot().is_some())
|
|
{
|
|
params.push((*config).to_json_value());
|
|
}
|
|
return;
|
|
}
|
|
|
|
fn decode_inflation_rewards(
|
|
method: &str,
|
|
value: serde_json::Value,
|
|
expected_count: usize,
|
|
) -> ksp_core_lib::Result<std::vec::Vec<std::option::Option<crate::SolanaInflationReward>>> {
|
|
let decoded = crate::decode_wire_json::<std::vec::Vec<std::option::Option<serde_json::Value>>>(method, value);
|
|
let values = match decoded {
|
|
std::result::Result::Ok(values) => values,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
if values.len() != expected_count {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_RESPONSE, "getInflationReward result count does not match the requested address count")
|
|
.with_context("rpc_method", method)
|
|
.with_context("expected_count", expected_count.to_string())
|
|
.with_context("actual_count", values.len().to_string()),
|
|
);
|
|
}
|
|
let mut rewards = std::vec::Vec::with_capacity(values.len());
|
|
for value in values {
|
|
match value {
|
|
std::option::Option::Some(value) => {
|
|
let reward = crate::SolanaInflationReward::decode_wire(method, value);
|
|
match reward {
|
|
std::result::Result::Ok(reward) => rewards.push(std::option::Option::Some(reward)),
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
}
|
|
},
|
|
std::option::Option::None => rewards.push(std::option::Option::None),
|
|
}
|
|
}
|
|
return std::result::Result::Ok(rewards);
|
|
}
|
|
|
|
fn decode_economics_u64_response(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<crate::SolanaRpcResponse<u64>> {
|
|
let decoded = crate::decode_wire_json::<WireEconomicsRpcResponse<u64>>(method, value);
|
|
let wire = match decoded {
|
|
std::result::Result::Ok(wire) => wire,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let context = crate::SolanaRpcContext::decode_wire(method, wire.context);
|
|
return match context {
|
|
std::result::Result::Ok(context) => std::result::Result::Ok(crate::SolanaRpcResponse::new(context, wire.value)),
|
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
|
};
|
|
}
|
|
|
|
fn decode_supply_response(method: &str, value: serde_json::Value) -> ksp_core_lib::Result<crate::SolanaRpcResponse<crate::SolanaSupply>> {
|
|
let decoded = crate::decode_wire_json::<WireEconomicsRpcResponse<serde_json::Value>>(method, value);
|
|
let wire = match decoded {
|
|
std::result::Result::Ok(wire) => wire,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let context = crate::SolanaRpcContext::decode_wire(method, wire.context);
|
|
let context = match context {
|
|
std::result::Result::Ok(context) => context,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let supply = crate::SolanaSupply::decode_wire(method, wire.value);
|
|
return match supply {
|
|
std::result::Result::Ok(supply) => std::result::Result::Ok(crate::SolanaRpcResponse::new(context, supply)),
|
|
std::result::Result::Err(error) => std::result::Result::Err(error),
|
|
};
|
|
}
|
|
|
|
fn economics_descriptor(method: &str) -> ksp_core_lib::Result<&'static crate::HttpRpcMethodDescriptor> {
|
|
let descriptor = crate::find_http_rpc_method(method);
|
|
return match descriptor {
|
|
std::option::Option::Some(descriptor)
|
|
if descriptor.category() == crate::HttpRpcCategory::Economics && descriptor.coverage_release() == crate::HttpRpcCoverageRelease::V0_2_4 =>
|
|
{
|
|
std::result::Result::Ok(descriptor)
|
|
},
|
|
_ => std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_RESPONSE, "typed Economics descriptor is missing from the audited 0.2.4 registry")
|
|
.with_context("rpc_method", method),
|
|
),
|
|
};
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "../unit_tests/rpc_economics.rs"]
|
|
mod tests;
|