spl-token-cli 5.5.0

SPL-Token Command-line Utility
Documentation
#![allow(clippy::arithmetic_side_effects)]
use {
    crate::{
        clap_app::Error,
        output::{CliTokenAccount, CliTokenAccounts},
    },
    serde::{Deserialize, Serialize},
    solana_account_decoder::{parse_token::TokenAccountType, UiAccountData},
    solana_client::rpc_response::RpcKeyedAccount,
    solana_sdk::pubkey::Pubkey,
    spl_associated_token_account_interface::address::get_associated_token_address_with_program_id,
    std::{
        collections::{btree_map::Entry, BTreeMap},
        str::FromStr,
    },
};

#[derive(Serialize, Deserialize)]
pub(crate) struct UnsupportedAccount {
    pub address: String,
    pub err: String,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub(crate) enum AccountFilter {
    Delegated,
    ExternallyCloseable,
    All,
}

pub(crate) fn sort_and_parse_token_accounts(
    owner: &Pubkey,
    accounts: Vec<RpcKeyedAccount>,
    explicit_token: bool,
    account_filter: AccountFilter,
) -> Result<CliTokenAccounts, Error> {
    let mut cli_accounts: BTreeMap<(Pubkey, Pubkey), Vec<CliTokenAccount>> = BTreeMap::new();
    let mut unsupported_accounts = vec![];
    let mut max_len_balance = 0;
    let mut aux_count = 0;

    for keyed_account in accounts {
        let address_str = keyed_account.pubkey;
        let address = Pubkey::from_str(&address_str)?;
        let program_id = Pubkey::from_str(&keyed_account.account.owner)?;

        if let UiAccountData::Json(parsed_account) = keyed_account.account.data {
            match serde_json::from_value(parsed_account.parsed) {
                Ok(TokenAccountType::Account(ui_token_account)) => {
                    let mint = Pubkey::from_str(&ui_token_account.mint)?;
                    let btree_key = (program_id, mint);
                    let is_associated =
                        get_associated_token_address_with_program_id(owner, &mint, &program_id)
                            == address;

                    match account_filter {
                        AccountFilter::Delegated if ui_token_account.delegate.is_none() => continue,
                        AccountFilter::ExternallyCloseable
                            if ui_token_account.close_authority.is_none() =>
                        {
                            continue
                        }
                        _ => (),
                    }

                    if !is_associated {
                        aux_count += 1;
                    }

                    max_len_balance = max_len_balance.max(
                        ui_token_account
                            .token_amount
                            .real_number_string_trimmed()
                            .len(),
                    );

                    let cli_account = CliTokenAccount {
                        address: address_str,
                        program_id: program_id.to_string(),
                        account: ui_token_account,
                        is_associated,
                        has_permanent_delegate: false,
                    };

                    let entry = cli_accounts.entry(btree_key);
                    match entry {
                        Entry::Occupied(_) => {
                            entry.and_modify(|e| {
                                if is_associated {
                                    e.insert(0, cli_account)
                                } else {
                                    e.push(cli_account)
                                }
                            });
                        }
                        Entry::Vacant(_) => {
                            entry.or_insert_with(|| vec![cli_account]);
                        }
                    }
                }
                Ok(_) => unsupported_accounts.push(UnsupportedAccount {
                    address: address_str,
                    err: "Not a token account".to_string(),
                }),
                Err(err) => unsupported_accounts.push(UnsupportedAccount {
                    address: address_str,
                    err: format!("Account parse failure: {}", err),
                }),
            }
        }
    }

    Ok(CliTokenAccounts {
        accounts: cli_accounts.into_values().collect(),
        unsupported_accounts,
        max_len_balance,
        aux_len: if aux_count > 0 {
            format!("  (Aux-{}*)", aux_count).chars().count() + 1
        } else {
            0
        },
        explicit_token,
    })
}