123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- use {
- clap::{builder::BoolishValueParser, crate_description, crate_name, crate_version, Arg, Command}, solana_clap_v3_utils::{
- input_parsers::{
- parse_url_or_moniker,
- signer::{SignerSource, SignerSourceParserBuilder},
- },
- input_validators::normalize_to_url_if_moniker,
- keypair::signer_from_path,
- }, solana_client::nonblocking::rpc_client::RpcClient, solana_remote_wallet::remote_wallet::RemoteWalletManager, solana_sdk::{
- commitment_config::CommitmentConfig,
- message::Message,
- pubkey::Pubkey,
- signature::{Signature, Signer},
- transaction::Transaction,
- }, spl_tlv_account_resolution::{account::ExtraAccountMeta, seeds::Seed, state::ExtraAccountMetaList}, spl_transfer_hook_interface::instruction::ExecuteInstruction, std::{error::Error, process::exit, rc::Rc, sync::Arc}
- };
- struct Config {
- commitment_config: CommitmentConfig,
- payer: Arc<dyn Signer>,
- json_rpc_url: String,
- verbose: bool,
- }
- pub fn get_extra_account_metas_with_source_wallet_block() -> Vec<ExtraAccountMeta> {
- vec![
- // [5] wallet_block for source token account wallet
- ExtraAccountMeta::new_with_seeds(
- &[
- Seed::Literal {
- bytes: b"wallet_block".to_vec(),
- },
- Seed::AccountData {
- account_index: 0,
- data_index: 32,
- length: 32,
- },
- ],
- false,
- false,
- ).unwrap(),
- ]
- }
- pub fn get_extra_account_metas_with_both_wallet_blocks() -> Vec<ExtraAccountMeta> {
- vec![
- // [5] wallet_block for source token account wallet
- ExtraAccountMeta::new_with_seeds(
- &[
- Seed::Literal {
- bytes: b"wallet_block".to_vec(),
- },
- Seed::AccountData {
- account_index: 0,
- data_index: 32,
- length: 32,
- },
- ],
- false,
- false,
- ).unwrap(),
- // [6] wallet_block for destination token account wallet
- ExtraAccountMeta::new_with_seeds(
- &[
- Seed::Literal {
- bytes: b"wallet_block".to_vec(),
- },
- Seed::AccountData {
- account_index: 2,
- data_index: 32,
- length: 32,
- },
- ],
- false,
- false,
- ).unwrap(),
- ]
- }
- fn create_empty_extra_metas() -> Vec<u8> {
- let size = ExtraAccountMetaList::size_of(0).unwrap();
- let metas: Vec<ExtraAccountMeta> = vec![];
- let mut data = vec![0; size];
- ExtraAccountMetaList::init::<ExecuteInstruction>(&mut data, &metas).unwrap();
- data
- }
- fn create_extra_metas_with_source_wallet_block() -> Vec<u8> {
- let metas: Vec<ExtraAccountMeta> = get_extra_account_metas_with_source_wallet_block();
- let size = ExtraAccountMetaList::size_of(metas.len()).unwrap();
- let mut data = vec![0; size];
- ExtraAccountMetaList::init::<ExecuteInstruction>(&mut data, &metas).unwrap();
- data
- }
- fn create_extra_metas_with_both_wallet_blocks() -> Vec<u8> {
- let metas: Vec<ExtraAccountMeta> = get_extra_account_metas_with_both_wallet_blocks();
- let size = ExtraAccountMetaList::size_of(metas.len()).unwrap();
- let mut data = vec![0; size];
- ExtraAccountMetaList::init::<ExecuteInstruction>(&mut data, &metas).unwrap();
- data
- }
- fn get_extra_metas_account_data() {
- let data_empty = create_empty_extra_metas();
- let data_source_wallet_block = create_extra_metas_with_source_wallet_block();
- let data_both_wallet_blocks = create_extra_metas_with_both_wallet_blocks();
- println!("data empty: {:?}", data_empty);
- println!("data source wallet block: {:?}", data_source_wallet_block);
- println!("data both wallet blocks: {:?}", data_both_wallet_blocks);
- }
- async fn get_config(rpc_client: &Arc<RpcClient>) {
- let config = block_list_client::accounts::Config::find_pda().0;
- let data = rpc_client.get_account_data(&config).await.unwrap();
- println!("config: {:?}", data);
- let config = block_list_client::accounts::Config::from_bytes(&data).unwrap();
- println!("config: {:?}", config);
- }
- async fn get_extra_metas(rpc_client: &Arc<RpcClient>, mint_address: &Pubkey) {
- let extra_metas = block_list_client::accounts::ExtraMetas::find_pda(mint_address).0;
- let data = rpc_client.get_account_data(&extra_metas).await.unwrap();
- println!("extra_metas: {:?}", data);
- }
- async fn process_setup_extra_metas(
- rpc_client: &Arc<RpcClient>,
- payer: &Arc<dyn Signer>,
- mint_address: &Pubkey,
- check_both_wallets: bool,
- ) -> Result<Signature, Box<dyn Error>> {
- let ix = block_list_client::instructions::SetupExtraMetasBuilder::new()
- .authority(payer.pubkey())
- .config(block_list_client::accounts::Config::find_pda().0)
- .mint(*mint_address)
- .extra_metas(block_list_client::accounts::ExtraMetas::find_pda(mint_address).0)
- .check_both_wallets(check_both_wallets)
- .instruction();
- let mut transaction = Transaction::new_unsigned(Message::new(&[ix], Some(&payer.pubkey())));
-
- let blockhash = rpc_client
- .get_latest_blockhash()
- .await
- .map_err(|err| format!("error: unable to get latest blockhash: {}", err))?;
- transaction
- .try_sign(&[payer], blockhash)
- .map_err(|err| format!("error: failed to sign transaction: {}", err))?;
- let signature = rpc_client
- .send_and_confirm_transaction_with_spinner(&transaction)
- .await
- .map_err(|err| format!("error: send transaction: {}", err))?;
- Ok(signature)
- }
- async fn process_init(
- rpc_client: &Arc<RpcClient>,
- payer: &Arc<dyn Signer>,
- ) -> Result<Signature, Box<dyn Error>> {
- let ix = block_list_client::instructions::InitBuilder::new()
- .authority(payer.pubkey())
- .config(block_list_client::accounts::Config::find_pda().0)
- .instruction();
- let mut transaction = Transaction::new_unsigned(Message::new(&[ix], Some(&payer.pubkey())));
-
- let blockhash = rpc_client
- .get_latest_blockhash()
- .await
- .map_err(|err| format!("error: unable to get latest blockhash: {}", err))?;
- transaction
- .try_sign(&[payer], blockhash)
- .map_err(|err| format!("error: failed to sign transaction: {}", err))?;
- let signature = rpc_client
- .send_and_confirm_transaction_with_spinner(&transaction)
- .await
- .map_err(|err| format!("error: send transaction: {}", err))?;
- Ok(signature)
- }
- async fn process_block_wallet(
- rpc_client: &Arc<RpcClient>,
- payer: &Arc<dyn Signer>,
- wallet_address: &Pubkey,
- ) -> Result<Signature, Box<dyn Error>> {
-
- let ix = block_list_client::instructions::BlockWalletBuilder::new()
- .authority(payer.pubkey())
- .config(block_list_client::accounts::Config::find_pda().0)
- .wallet(*wallet_address)
- .wallet_block(block_list_client::accounts::WalletBlock::find_pda(wallet_address).0)
- .instruction();
- let mut transaction = Transaction::new_unsigned(Message::new(&[ix], Some(&payer.pubkey())));
-
- let blockhash = rpc_client
- .get_latest_blockhash()
- .await
- .map_err(|err| format!("error: unable to get latest blockhash: {}", err))?;
- transaction
- .try_sign(&[payer], blockhash)
- .map_err(|err| format!("error: failed to sign transaction: {}", err))?;
- let signature = rpc_client
- .send_and_confirm_transaction_with_spinner(&transaction)
- .await
- .map_err(|err| format!("error: send transaction: {}", err))?;
- Ok(signature)
- }
- async fn process_unblock_wallet(
- rpc_client: &Arc<RpcClient>,
- payer: &Arc<dyn Signer>,
- wallet_address: &Pubkey,
- ) -> Result<Signature, Box<dyn Error>> {
- let ix = block_list_client::instructions::UnblockWalletBuilder::new()
- .authority(payer.pubkey())
- .config(block_list_client::accounts::Config::find_pda().0)
- .wallet_block(block_list_client::accounts::WalletBlock::find_pda(wallet_address).0)
- .instruction();
- let mut transaction = Transaction::new_unsigned(Message::new(&[ix], Some(&payer.pubkey())));
-
- let blockhash = rpc_client
- .get_latest_blockhash()
- .await
- .map_err(|err| format!("error: unable to get latest blockhash: {}", err))?;
- transaction
- .try_sign(&[payer], blockhash)
- .map_err(|err| format!("error: failed to sign transaction: {}", err))?;
- let signature = rpc_client
- .send_and_confirm_transaction_with_spinner(&transaction)
- .await
- .map_err(|err| format!("error: send transaction: {}", err))?;
- Ok(signature)
- }
- #[tokio::main]
- async fn main() -> Result<(), Box<dyn Error>> {
- let app_matches = Command::new(crate_name!())
- .about(crate_description!())
- .version(crate_version!())
- .subcommand_required(true)
- .arg_required_else_help(true)
- .arg({
- let arg = Arg::new("config_file")
- .short('C')
- .long("config")
- .value_name("PATH")
- .takes_value(true)
- .global(true)
- .help("Configuration file to use");
- if let Some(ref config_file) = *solana_cli_config::CONFIG_FILE {
- arg.default_value(config_file)
- } else {
- arg
- }
- })
- .arg(
- Arg::new("payer")
- .long("payer")
- .value_name("KEYPAIR")
- .value_parser(SignerSourceParserBuilder::default().allow_all().build())
- .takes_value(true)
- .global(true)
- .help("Filepath or URL to a keypair [default: client keypair]"),
- )
- .arg(
- Arg::new("verbose")
- .long("verbose")
- .short('v')
- .takes_value(false)
- .global(true)
- .help("Show additional information"),
- )
- .arg(
- Arg::new("json_rpc_url")
- .short('u')
- .long("url")
- .value_name("URL")
- .takes_value(true)
- .global(true)
- .value_parser(parse_url_or_moniker)
- .help("JSON RPC URL for the cluster [default: value from configuration file]"),
- )
- .subcommand(
- Command::new("init").about("Initializes the blocklist")
- )
- .subcommand(
- Command::new("block-wallet").about("Blocks a wallet")
- .arg(
- Arg::new("wallet_address")
- .value_name("WALLET_ADDRESS")
- .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build())
- .takes_value(true)
- .index(1)
- .help("Specify the wallet address to block"),
- )
- )
- .subcommand(
- Command::new("unblock-wallet").about("Unblocks a wallet")
- .arg(
- Arg::new("wallet_address")
- .value_name("WALLET_ADDRESS")
- .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build())
- .takes_value(true)
- .index(1)
- .help("Specify the wallet address to unblock"),
- )
- )
- .subcommand(
- Command::new("get-extra-metas-account-data").about("Gets the extra metas account data")
- )
- .subcommand(
- Command::new("get-config").about("Gets the config account data")
- )
- .subcommand(
- Command::new("get-extra-metas").about("Gets the extra metas account data")
- .arg(
- Arg::new("mint_address")
- .value_name("MINT_ADDRESS")
- .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build())
- .takes_value(true)
- .index(1)
- .help("Specify the mint address"),
- )
- )
- .subcommand(
- Command::new("setup-extra-metas").about("Setup the extra metas account")
- .arg(
- Arg::new("mint_address")
- .value_name("MINT_ADDRESS")
- .value_parser(SignerSourceParserBuilder::default().allow_pubkey().build())
- .takes_value(true)
- .index(1)
- .help("Specify the mint address"),
- )
- .arg(
- Arg::new("check-both-wallets")
- .long("check-both-wallets")
- .short('b')
- .help("Specify if both wallets should be checked"),
- )
- )
- .get_matches();
- let (command, matches) = app_matches.subcommand().unwrap();
- let mut wallet_manager: Option<Rc<RemoteWalletManager>> = None;
- let config = {
- let cli_config = if let Some(config_file) = matches.try_get_one::<String>("config_file")? {
- solana_cli_config::Config::load(config_file).unwrap_or_default()
- } else {
- solana_cli_config::Config::default()
- };
- let payer = if let Ok(Some((signer, _))) =
- SignerSource::try_get_signer(matches, "payer", &mut wallet_manager)
- {
- Box::new(signer)
- } else {
- signer_from_path(
- matches,
- &cli_config.keypair_path,
- "payer",
- &mut wallet_manager,
- )?
- };
- let json_rpc_url = normalize_to_url_if_moniker(
- matches
- .get_one::<String>("json_rpc_url")
- .unwrap_or(&cli_config.json_rpc_url),
- );
- Config {
- commitment_config: CommitmentConfig::confirmed(),
- payer: Arc::from(payer),
- json_rpc_url,
- verbose: matches.try_contains_id("verbose")?,
- }
- };
- solana_logger::setup_with_default("solana=info");
- if config.verbose {
- println!("JSON RPC URL: {}", config.json_rpc_url);
- }
- let rpc_client = Arc::new(RpcClient::new_with_commitment(
- config.json_rpc_url.clone(),
- config.commitment_config,
- ));
- match (command, matches) {
- ("init", _arg_matches) => {
- let response = process_init(
- &rpc_client,
- &config.payer,
- )
- .await
- .unwrap_or_else(|err| {
- eprintln!("error: init: {}", err);
- exit(1);
- });
- println!("{}", response);
- }
- ("block-wallet", arg_matches) => {
- let wallet_address =
- SignerSource::try_get_pubkey(arg_matches, "wallet_address", &mut wallet_manager)
- .unwrap()
- .unwrap();
- let response = process_block_wallet(
- &rpc_client,
- &config.payer,
- &wallet_address,
- )
- .await
- .unwrap_or_else(|err| {
- eprintln!("error: init: {}", err);
- exit(1);
- });
- println!("{}", response);
- }
- ("unblock-wallet", arg_matches) => {
- let wallet_address =
- SignerSource::try_get_pubkey(arg_matches, "wallet_address", &mut wallet_manager)
- .unwrap()
- .unwrap();
- let response = process_unblock_wallet(
- &rpc_client,
- &config.payer,
- &wallet_address,
- )
- .await
- .unwrap_or_else(|err| {
- eprintln!("error: init: {}", err);
- exit(1);
- });
- println!("{}", response);
- }
- ("get-extra-metas-account-data", _arg_matches) => {
- get_extra_metas_account_data();
- }
- ("get-config", _arg_matches) => {
- get_config(&rpc_client).await;
- }
- ("get-extra-metas", arg_matches) => {
- let mint_address =
- SignerSource::try_get_pubkey(arg_matches, "mint_address", &mut wallet_manager)
- .unwrap()
- .unwrap();
- get_extra_metas(&rpc_client, &mint_address).await;
- }
- ("setup-extra-metas", arg_matches) => {
- let mint_address =
- SignerSource::try_get_pubkey(arg_matches, "mint_address", &mut wallet_manager)
- .unwrap()
- .unwrap();
- let check_both_wallets = arg_matches.contains_id("check-both-wallets");
- let response = process_setup_extra_metas(
- &rpc_client,
- &config.payer,
- &mint_address,
- check_both_wallets,
- )
- .await
- .unwrap_or_else(|err| {
- eprintln!("error: setup_extra_metas: {}", err);
- exit(1);
- });
- println!("{}", response);
- }
- _ => unreachable!(),
- };
- Ok(())
- }
-
|