use std::ops::Deref;
use gmsol_programs::gmsol_store::client::{accounts, args};
use gmsol_solana_utils::transaction_builder::TransactionBuilder;
use gmsol_utils::{oracle::PriceProviderKind, token_config::UpdateTokenConfigParams};
use solana_sdk::{pubkey::Pubkey, signer::Signer, system_program};
use crate::{serde::StringPubkey, utils::Value};
pub trait TokenConfigOps<C> {
fn initialize_token_map<'a>(
&'a self,
store: &Pubkey,
token_map: &'a dyn Signer,
) -> (TransactionBuilder<'a, C>, Pubkey);
#[allow(clippy::too_many_arguments)]
fn insert_token_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
name: &str,
token: &Pubkey,
builder: UpdateTokenConfigParams,
enable: bool,
new: bool,
) -> TransactionBuilder<C>;
#[allow(clippy::too_many_arguments)]
fn insert_synthetic_token_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
name: &str,
token: &Pubkey,
decimals: u8,
builder: UpdateTokenConfigParams,
enable: bool,
new: bool,
) -> TransactionBuilder<C>;
fn toggle_token_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
enable: bool,
) -> TransactionBuilder<C>;
fn toggle_token_price_adjustment(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
enable: bool,
) -> TransactionBuilder<C>;
fn set_expected_provider(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
provider: PriceProviderKind,
) -> TransactionBuilder<C>;
fn update_feed_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
provider: PriceProviderKind,
update: UpdateFeedConfig,
) -> crate::Result<TransactionBuilder<C>>;
}
impl<C: Deref<Target = impl Signer> + Clone> TokenConfigOps<C> for crate::Client<C> {
fn initialize_token_map<'a>(
&'a self,
store: &Pubkey,
token_map: &'a dyn Signer,
) -> (TransactionBuilder<'a, C>, Pubkey) {
let builder = self
.store_transaction()
.anchor_accounts(accounts::InitializeTokenMap {
payer: self.payer(),
store: *store,
token_map: token_map.pubkey(),
system_program: system_program::ID,
})
.anchor_args(args::InitializeTokenMap {})
.signer(token_map);
(builder, token_map.pubkey())
}
fn insert_token_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
name: &str,
token: &Pubkey,
builder: UpdateTokenConfigParams,
enable: bool,
new: bool,
) -> TransactionBuilder<C> {
let authority = self.payer();
self.store_transaction()
.anchor_accounts(accounts::PushToTokenMap {
authority,
store: *store,
token_map: *token_map,
token: *token,
system_program: system_program::ID,
})
.anchor_args(args::PushToTokenMap {
name: name.to_owned(),
builder: builder.into(),
enable,
new,
})
}
fn insert_synthetic_token_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
name: &str,
token: &Pubkey,
decimals: u8,
builder: UpdateTokenConfigParams,
enable: bool,
new: bool,
) -> TransactionBuilder<C> {
let authority = self.payer();
self.store_transaction()
.anchor_accounts(accounts::PushToTokenMapSynthetic {
authority,
store: *store,
token_map: *token_map,
system_program: system_program::ID,
})
.anchor_args(args::PushToTokenMapSynthetic {
name: name.to_owned(),
token: *token,
token_decimals: decimals,
builder: builder.into(),
enable,
new,
})
}
fn toggle_token_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
enable: bool,
) -> TransactionBuilder<C> {
let authority = self.payer();
self.store_transaction()
.anchor_accounts(accounts::ToggleTokenConfig {
authority,
store: *store,
token_map: *token_map,
})
.anchor_args(args::ToggleTokenConfig {
token: *token,
enable,
})
}
fn toggle_token_price_adjustment(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
enable: bool,
) -> TransactionBuilder<C> {
let authority = self.payer();
self.store_transaction()
.anchor_accounts(accounts::ToggleTokenPriceAdjustment {
authority,
store: *store,
token_map: *token_map,
})
.anchor_args(args::ToggleTokenPriceAdjustment {
token: *token,
enable,
})
}
fn set_expected_provider(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
provider: PriceProviderKind,
) -> TransactionBuilder<C> {
let authority = self.payer();
self.store_transaction()
.anchor_accounts(accounts::SetExpectedProvider {
authority,
store: *store,
token_map: *token_map,
})
.anchor_args(args::SetExpectedProvider {
token: *token,
provider: provider as u8,
})
}
fn update_feed_config(
&self,
store: &Pubkey,
token_map: &Pubkey,
token: &Pubkey,
provider: PriceProviderKind,
update: UpdateFeedConfig,
) -> crate::Result<TransactionBuilder<C>> {
let authority = self.payer();
let txn = self
.store_transaction()
.anchor_accounts(accounts::SetFeedConfigV2 {
authority,
store: *store,
token_map: *token_map,
})
.anchor_args(args::SetFeedConfigV2 {
token: *token,
provider: provider.into(),
feed: update.feed_id.map(|k| k.0),
timestamp_adjustment: update.timestamp_adjustment,
max_deviation_factor: update
.max_deviation_factor
.map(|f| f.to_u128())
.transpose()?,
});
Ok(txn)
}
}
#[derive(typed_builder::TypedBuilder)]
#[cfg_attr(serde, derive(serde::Serialize, serde::Deserialize))]
pub struct UpdateFeedConfig {
#[builder(default)]
#[cfg_attr(serde, serde(default))]
pub feed_id: Option<StringPubkey>,
#[builder(default)]
#[cfg_attr(serde, serde(default))]
pub timestamp_adjustment: Option<u32>,
#[builder(default)]
#[cfg_attr(serde, serde(default))]
pub max_deviation_factor: Option<Value>,
}