use anchor_lang::prelude::*;
use anchor_spl::{token::TokenAccount, token_interface};
use crate::{states::TokenMapAccess, utils::pubkey::optional_address, CoreError};
use super::{swap::HasSwapParams, TokenRecord, TokensWithFeed};
#[zero_copy]
#[cfg_attr(feature = "debug", derive(Debug))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TokenAndAccount {
token: Pubkey,
account: Pubkey,
}
impl TokenAndAccount {
pub fn init(&mut self, account: &Account<TokenAccount>) {
self.token = account.mint;
self.account = account.key();
}
pub fn init_with_interface(
&mut self,
account: &InterfaceAccount<token_interface::TokenAccount>,
) {
self.token = account.mint;
self.account = account.key();
}
pub fn token(&self) -> Option<Pubkey> {
optional_address(&self.token).copied()
}
pub fn account(&self) -> Option<Pubkey> {
optional_address(&self.account).copied()
}
pub fn token_and_account(&self) -> Option<(Pubkey, Pubkey)> {
let token = self.token()?;
let account = self.account()?;
Some((token, account))
}
}
pub struct TokensCollector {
tokens: Vec<Pubkey>,
}
impl TokensCollector {
pub fn new(action: Option<&impl HasSwapParams>, extra_capacity: usize) -> Self {
let mut tokens;
match action {
Some(action) => {
let swap = action.swap();
tokens = Vec::with_capacity(swap.num_tokens() + extra_capacity);
tokens.extend_from_slice(swap.tokens());
}
None => tokens = Vec::with_capacity(extra_capacity),
}
Self { tokens }
}
pub fn insert_token(&mut self, token: &Pubkey) -> bool {
match self.tokens.binary_search(token) {
Ok(_) => false,
Err(idx) => {
self.tokens.insert(idx, *token);
true
}
}
}
pub fn into_vec(mut self, token_map: &impl TokenMapAccess) -> Result<Vec<Pubkey>> {
token_map.sort_tokens_by_provider(&mut self.tokens)?;
Ok(self.tokens)
}
pub fn to_feeds(&self, token_map: &impl TokenMapAccess) -> Result<TokensWithFeed> {
let records = self
.tokens
.iter()
.map(|token| {
let config = token_map
.get(token)
.ok_or_else(|| error!(CoreError::UnknownToken))?;
TokenRecord::from_config(*token, config)
})
.collect::<Result<Vec<_>>>()?;
TokensWithFeed::try_from_records(records)
}
}