yellowstone_shield_cli/command/
mod.rs1pub mod identity;
2pub mod policy;
3
4use anyhow::Result;
5use log::info;
6use solana_client::client_error::ClientError;
7use solana_client::nonblocking::rpc_client::RpcClient;
8use solana_commitment_config::CommitmentConfig;
9use solana_instruction::Instruction;
10use solana_keypair::Keypair;
11use solana_pubkey::Pubkey;
12use solana_signer::Signer;
13use spl_token_metadata_interface::state::TokenMetadata;
14use yellowstone_shield_client::TransactionBuilder;
15
16use crate::policy::PolicyVersion;
17
18pub struct CommandContext {
19 pub client: RpcClient,
20 pub keypair: Keypair,
21}
22
23pub struct SolanaAccount<T>(pub Pubkey, pub Option<T>);
24pub struct CommandComplete(
25 pub SolanaAccount<TokenMetadata>,
26 pub SolanaAccount<PolicyVersion>,
27);
28
29pub type RunResult = Result<CommandComplete>;
30
31#[async_trait::async_trait]
32pub trait RunCommand {
33 async fn run(&mut self, context: CommandContext) -> RunResult;
34}
35
36async fn send_batched_tx<T, F>(
37 client: &RpcClient,
38 keypair: &Keypair,
39 items: &[T],
40 chunk_size: usize,
41 mut instruction_builder: F,
42) -> Result<(), ClientError>
43where
44 T: Clone,
45 F: FnMut(&T) -> Instruction,
46{
47 for batch in items.chunks(chunk_size) {
48 let instructions: Vec<_> = batch.iter().map(&mut instruction_builder).collect();
49
50 if instructions.is_empty() {
51 continue;
52 }
53
54 let last_blockhash = client.get_latest_blockhash().await?;
55
56 let tx = TransactionBuilder::build()
57 .instructions(instructions)
58 .signer(keypair)
59 .payer(&keypair.pubkey())
60 .recent_blockhash(last_blockhash)
61 .transaction();
62
63 let signature = client
64 .send_and_confirm_transaction_with_spinner_and_commitment(
65 &tx,
66 CommitmentConfig::confirmed(),
67 )
68 .await?;
69
70 info!("Transaction signature: {}", signature);
71 }
72
73 Ok(())
74}