From 6eefc5c488e79a874139e2c78598936ea0a1c65d Mon Sep 17 00:00:00 2001 From: Samuel Vanderwaal Date: Sat, 20 Apr 2024 11:01:56 -0800 Subject: [PATCH 1/2] add priority fees to all commands --- src/args.rs | 33 +++++++++++- src/commands/approve.rs | 19 +++++-- src/commands/burn.rs | 15 +++++- src/commands/create.rs | 15 +++++- src/commands/lock.rs | 15 +++++- src/commands/mint.rs | 20 +++++++- src/commands/mint_batch.rs | 23 +++++++-- src/commands/mod.rs | 6 ++- src/commands/revoke.rs | 19 +++++-- src/commands/transfer.rs | 15 +++++- src/commands/unlock.rs | 15 +++++- src/main.rs | 38 ++++++++++++-- src/transaction.rs | 101 +++++++++++++++++++++++++++++++++++-- 13 files changed, 306 insertions(+), 28 deletions(-) diff --git a/src/args.rs b/src/args.rs index 1cc2ee5..fdd0108 100644 --- a/src/args.rs +++ b/src/args.rs @@ -3,6 +3,8 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; use solana_program::pubkey::Pubkey; +use crate::transaction::Priority; + #[derive(Parser)] #[clap(author, version, about)] pub struct Args { @@ -27,9 +29,17 @@ pub enum Commands { /// The recipient to receive reclaimed rent. Defaults to the signer. recipient: Option, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Create an asset with extension data. - Mint { asset_file_path: PathBuf }, + Mint { + asset_file_path: PathBuf, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, + }, /// Create a batch of assets with extension data. MintBatch { asset_files_dir: PathBuf, @@ -37,6 +47,9 @@ pub enum Commands { /// Delay in ms between transactions. #[arg(long, default_value = "100")] delay: u64, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Create a basic asset with no extensions. Create { @@ -55,6 +68,9 @@ pub enum Commands { /// Owner of the created asset, defaults to authority pubkey. #[arg(short, long)] owner: Option, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Get an asset account's data and decode it. Decode { @@ -82,6 +98,9 @@ pub enum Commands { /// Specify each one separately: --role burn --role lock --role transfer #[arg(short = 'R', long)] role: Vec, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Lock an asset, preventing any actions to be performed on it. Lock { @@ -90,6 +109,9 @@ pub enum Commands { /// Path to the signer keypair file. Defaults to the config keypair. signer_keypair_path: Option, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Revoke a delegate from an asset. Revoke { @@ -104,6 +126,9 @@ pub enum Commands { /// Revoke all roles from the delegate and clear it. #[arg(long)] all: bool, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Transfer an asset to a new owner. Transfer { @@ -112,6 +137,9 @@ pub enum Commands { /// The recipient of the asset. recipient: Pubkey, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, /// Unlock an asset, allowing actions to be performed on it. Unlock { @@ -120,5 +148,8 @@ pub enum Commands { /// Path to the signer keypair file. Defaults to the config keypair. signer_keypair_path: Option, + + #[arg(short = 'P', long, default_value = "low")] + priority: Priority, }, } diff --git a/src/commands/approve.rs b/src/commands/approve.rs index d0298a2..1f40227 100644 --- a/src/commands/approve.rs +++ b/src/commands/approve.rs @@ -11,6 +11,7 @@ pub struct ApproveArgs { pub asset: Pubkey, pub delegate: Pubkey, pub role: Vec, + pub priority: Priority, } pub fn handle_approve(args: ApproveArgs) -> Result<()> { @@ -33,7 +34,7 @@ pub fn handle_approve(args: ApproveArgs) -> Result<()> { }) .collect(); - let args = ApproveInstructionArgs { + let ix_args = ApproveInstructionArgs { delegate_input: DelegateInput::Some { roles }, }; @@ -42,9 +43,21 @@ pub fn handle_approve(args: ApproveArgs) -> Result<()> { owner, delegate, } - .instruction(args); + .instruction(ix_args); - let sig = send_and_confirm_tx(&config.client, &[&owner_sk], &[ix])?; + let signers = vec![&owner_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Setting {delegate} as a delegate on asset {asset} in tx: {sig}"); diff --git a/src/commands/burn.rs b/src/commands/burn.rs index f1a2bf8..4d508a3 100644 --- a/src/commands/burn.rs +++ b/src/commands/burn.rs @@ -5,6 +5,7 @@ pub struct BurnArgs { pub rpc_url: Option, pub asset: Pubkey, pub recipient: Option, + pub priority: Priority, } pub fn handle_burn(args: BurnArgs) -> Result<()> { @@ -26,7 +27,19 @@ pub fn handle_burn(args: BurnArgs) -> Result<()> { } .instruction(); - let sig = send_and_confirm_tx(&config.client, &[&signer_sk], &[ix])?; + let signers = vec![&signer_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Burned asset {asset} in tx: {sig}"); diff --git a/src/commands/create.rs b/src/commands/create.rs index 97abd30..9579358 100644 --- a/src/commands/create.rs +++ b/src/commands/create.rs @@ -7,6 +7,7 @@ pub struct CreateArgs { pub asset_keypair_path: Option, pub immutable: bool, pub owner: Option, + pub priority: Priority, } pub fn handle_create(args: CreateArgs) -> Result<()> { @@ -41,7 +42,19 @@ pub fn handle_create(args: CreateArgs) -> Result<()> { } .instruction(ix_args); - let sig = send_and_confirm_tx(&config.client, &[&authority_sk, &asset_sk], &[ix])?; + let signers = vec![&authority_sk, &asset_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Asset {asset} created in tx: {sig}"); diff --git a/src/commands/lock.rs b/src/commands/lock.rs index 519f98b..5bc42d6 100644 --- a/src/commands/lock.rs +++ b/src/commands/lock.rs @@ -7,6 +7,7 @@ pub struct LockArgs { pub rpc_url: Option, pub asset: Pubkey, pub signer_keypair_path: Option, + pub priority: Priority, } pub fn handle_lock(args: LockArgs) -> Result<()> { @@ -27,7 +28,19 @@ pub fn handle_lock(args: LockArgs) -> Result<()> { let ix = Lock { asset, signer }.instruction(); - let sig = send_and_confirm_tx(&config.client, &[&payer_sk, &signer_sk], &[ix])?; + let signers = vec![&payer_sk, &signer_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Locking asset {asset} in tx: {sig}"); diff --git a/src/commands/mint.rs b/src/commands/mint.rs index 64d2726..7dec2ef 100644 --- a/src/commands/mint.rs +++ b/src/commands/mint.rs @@ -1,4 +1,6 @@ -use crate::transaction::pack_instructions; +use solana_sdk::compute_budget::ComputeBudgetInstruction; + +use crate::transaction::{get_compute_units, get_priority_fee, pack_instructions, Priority}; use super::*; @@ -6,6 +8,7 @@ pub struct MintArgs { pub keypair_path: Option, pub rpc_url: Option, pub asset_file_path: PathBuf, + pub priority: Priority, } pub async fn handle_mint(args: MintArgs) -> Result<()> { @@ -43,6 +46,8 @@ pub async fn handle_mint(args: MintArgs) -> Result<()> { }) .collect::>(); + let micro_lamports = get_priority_fee(&args.priority); + let instructions = mint(MintIxArgs { accounts, asset_args, @@ -51,9 +56,20 @@ pub async fn handle_mint(args: MintArgs) -> Result<()> { let packed_instructions = pack_instructions(2, &authority_sk.pubkey(), &instructions); + let signers = vec![&authority_sk, &asset_sk]; + // Instructions are packed to max data length sizes, so we only put one in each tx. for instructions in packed_instructions { - let sig = send_and_confirm_tx(&config.client, &[&authority_sk, &asset_sk], &instructions)?; + let compute_units = + get_compute_units(&config.client, &instructions, &signers)?.unwrap_or(200_000); + + let mut final_instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ]; + final_instructions.extend(instructions); + + let sig = send_and_confirm_tx(&config.client, &signers, &final_instructions)?; println!("sig: {}", sig); } diff --git a/src/commands/mint_batch.rs b/src/commands/mint_batch.rs index 80b4573..38036e3 100644 --- a/src/commands/mint_batch.rs +++ b/src/commands/mint_batch.rs @@ -12,6 +12,7 @@ pub struct MintBatchArgs { pub rpc_url: Option, pub asset_files_dir: PathBuf, pub delay: u64, + pub priority: Priority, } pub struct AssetStruct { @@ -133,6 +134,8 @@ pub async fn handle_mint_batch(args: MintBatchArgs) -> Result<()> { .unwrap() .progress_chars("=>-"); + let micro_lamports = get_priority_fee(&args.priority); + for (i, asset_instructions) in instructions.into_iter().enumerate() { let client = client.clone(); let authority_sk = authority_sk.clone(); @@ -146,19 +149,31 @@ pub async fn handle_mint_batch(args: MintBatchArgs) -> Result<()> { // to create the asset and set its extension data. futures.push(tokio::spawn(async move { // Pack all the instructions for minting this asset into as few transactions as possible. - let packed_transactions = + let packed_instructions = pack_instructions(2, &authority_sk.pubkey(), &asset_instructions); // Create a progress bar for each asset w/ the number of transactions to send. - let pb = mp_clone.add(ProgressBar::new(packed_transactions.len() as u64)); + let pb = mp_clone.add(ProgressBar::new(packed_instructions.len() as u64)); pb.set_style(sty_clone.clone()); let asset_sk = &asset_keys.lock().await[i]; let asset_address = &asset_sk.pubkey(); pb.set_message(format!("sending transactions for asset {asset_address}")); - for transaction in packed_transactions { - let res = send_and_confirm_tx(&client, &[&authority_sk, &asset_sk], &transaction); + let signers = vec![&authority_sk, asset_sk]; + + for instructions in packed_instructions { + let compute_units = get_compute_units(&client, &instructions, &signers) + .unwrap_or(Some(200_000)) + .unwrap_or(200_000); + + let mut final_instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ]; + final_instructions.extend(instructions); + + let res = send_and_confirm_tx(&client, &signers, &final_instructions); pb.inc(1); match res { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index d45d077..60449c5 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -22,7 +22,10 @@ pub use transfer::*; pub use unlock::*; // Internal lib -pub use crate::{setup::CliConfig, transaction::send_and_confirm_tx}; +pub use crate::{ + setup::CliConfig, + transaction::{get_compute_units, get_priority_fee, send_and_confirm_tx, Priority}, +}; // Standard lib pub use std::{fs::File, path::PathBuf}; @@ -40,6 +43,7 @@ pub use { serde::{Deserialize, Serialize}, solana_program::system_program, solana_sdk::{ + compute_budget::ComputeBudgetInstruction, pubkey::Pubkey, signature::{read_keypair_file, Keypair}, signer::Signer, diff --git a/src/commands/revoke.rs b/src/commands/revoke.rs index ae7d0bc..c7f17fb 100644 --- a/src/commands/revoke.rs +++ b/src/commands/revoke.rs @@ -11,6 +11,7 @@ pub struct RevokeArgs { pub asset: Pubkey, pub role: Vec, pub all: bool, + pub priority: Priority, } pub fn handle_revoke(args: RevokeArgs) -> Result<()> { @@ -31,7 +32,7 @@ pub fn handle_revoke(args: RevokeArgs) -> Result<()> { }) .collect(); - let args = RevokeInstructionArgs { + let ix_args = RevokeInstructionArgs { delegate_input: if args.all { DelegateInput::All } else { @@ -39,9 +40,21 @@ pub fn handle_revoke(args: RevokeArgs) -> Result<()> { }, }; - let ix = Revoke { asset, signer }.instruction(args); + let ix = Revoke { asset, signer }.instruction(ix_args); - let sig = send_and_confirm_tx(&config.client, &[&signer_sk], &[ix])?; + let signers = vec![&signer_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Revoking the delegate on asset {asset} in tx: {sig}"); diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index 8294b93..9cc3c72 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -7,6 +7,7 @@ pub struct TransferArgs { pub rpc_url: Option, pub asset: Pubkey, pub recipient: Pubkey, + pub priority: Priority, } pub fn handle_transfer(args: TransferArgs) -> Result<()> { @@ -26,7 +27,19 @@ pub fn handle_transfer(args: TransferArgs) -> Result<()> { } .instruction(); - let sig = send_and_confirm_tx(&config.client, &[&signer_sk], &[ix])?; + let signers = vec![&signer_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Transferring asset {asset} to {recipient} in tx: {sig}"); diff --git a/src/commands/unlock.rs b/src/commands/unlock.rs index fedc3ce..f53288f 100644 --- a/src/commands/unlock.rs +++ b/src/commands/unlock.rs @@ -7,6 +7,7 @@ pub struct UnlockArgs { pub rpc_url: Option, pub asset: Pubkey, pub signer_keypair_path: Option, + pub priority: Priority, } pub fn handle_unlock(args: UnlockArgs) -> Result<()> { @@ -27,7 +28,19 @@ pub fn handle_unlock(args: UnlockArgs) -> Result<()> { let ix = Unlock { asset, signer }.instruction(); - let sig = send_and_confirm_tx(&config.client, &[&payer_sk, &signer_sk], &[ix])?; + let signers = vec![&payer_sk, &signer_sk]; + + let micro_lamports = get_priority_fee(&args.priority); + let compute_units = + get_compute_units(&config.client, &[ix.clone()], &signers)?.unwrap_or(200_000); + + let instructions = vec![ + ComputeBudgetInstruction::set_compute_unit_limit(compute_units as u32), + ComputeBudgetInstruction::set_compute_unit_price(micro_lamports), + ix, + ]; + + let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; println!("Unlocking asset {asset} in tx: {sig}"); diff --git a/src/main.rs b/src/main.rs index 4de875e..90f91c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,17 +16,23 @@ async fn main() -> Result<()> { let rpc_url = args.rpc_url.clone(); match args.command { - Commands::Burn { asset, recipient } => handle_burn(BurnArgs { + Commands::Burn { + asset, + recipient, + priority, + } => handle_burn(BurnArgs { keypair_path, rpc_url, asset, recipient, + priority, }), Commands::Create { name, asset_keypair_path, immutable, owner, + priority, } => handle_create(CreateArgs { keypair_path, rpc_url, @@ -34,6 +40,7 @@ async fn main() -> Result<()> { asset_keypair_path, immutable, owner, + priority, }), Commands::Decode { asset, field, raw } => handle_decode(DecodeArgs { rpc_url, @@ -45,63 +52,86 @@ async fn main() -> Result<()> { asset, delegate, role, + priority, } => handle_approve(ApproveArgs { keypair_path, rpc_url, asset, delegate, role, + priority, }), Commands::Lock { asset, signer_keypair_path, + priority, } => handle_lock(LockArgs { keypair_path, rpc_url, asset, signer_keypair_path, + priority, }), - Commands::Mint { asset_file_path } => { + Commands::Mint { + asset_file_path, + priority, + } => { handle_mint(MintArgs { keypair_path, rpc_url, asset_file_path, + priority, }) .await } Commands::MintBatch { asset_files_dir, delay, + priority, } => { handle_mint_batch(MintBatchArgs { keypair_path, rpc_url, asset_files_dir, delay, + priority, }) .await } - Commands::Revoke { asset, role, all } => handle_revoke(RevokeArgs { + Commands::Revoke { + asset, + role, + all, + priority, + } => handle_revoke(RevokeArgs { keypair_path, rpc_url, asset, role, all, + priority, }), - Commands::Transfer { asset, recipient } => handle_transfer(TransferArgs { + Commands::Transfer { + asset, + recipient, + priority, + } => handle_transfer(TransferArgs { keypair_path, rpc_url, asset, recipient, + priority, }), Commands::Unlock { asset, signer_keypair_path, + priority, } => handle_unlock(UnlockArgs { keypair_path, rpc_url, asset, signer_keypair_path, + priority, }), } } diff --git a/src/transaction.rs b/src/transaction.rs index edfdb3c..3a7d99e 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -1,18 +1,72 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; use nifty_asset::MAX_TX_SIZE; use retry::{delay::Exponential, retry}; -use solana_client::rpc_client::RpcClient; +use solana_client::{rpc_client::RpcClient, rpc_config::RpcSimulateTransactionConfig}; use solana_program::instruction::Instruction; use solana_sdk::{ + commitment_config::CommitmentConfig, + hash::Hash, pubkey::Pubkey, signature::{Keypair, Signature}, signer::Signer, transaction::Transaction, }; +use std::{ + fmt::{self, Display, Formatter}, + str::FromStr, +}; + +#[derive(Debug, Default, Clone, Eq, PartialEq)] +pub enum Priority { + None, + #[default] + Low, + Medium, + High, + Max, +} + +impl FromStr for Priority { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "none" => Ok(Self::None), + "low" => Ok(Self::Low), + "medium" => Ok(Self::Medium), + "high" => Ok(Self::High), + "max" => Ok(Self::Max), + _ => Err(anyhow!("Invalid priority".to_string())), + } + } +} + +impl Display for Priority { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::None => write!(f, "None"), + Self::Low => write!(f, "Low"), + Self::Medium => write!(f, "Medium"), + Self::High => write!(f, "High"), + Self::Max => write!(f, "Max"), + } + } +} + +pub fn get_priority_fee(priority: &Priority) -> u64 { + match priority { + Priority::None => 1_000, + Priority::Low => 50_000, + Priority::Medium => 200_000, + Priority::High => 1_000_000, + Priority::Max => 2_000_000, + } +} + #[macro_export] macro_rules! transaction { - ($signers:expr, $instructions:expr, $client:expr) => { + ($client:expr, $signers:expr, $instructions:expr) => { Transaction::new_signed_with_payer( $instructions, Some(&$signers[0].pubkey()), @@ -27,7 +81,7 @@ pub fn send_and_confirm_tx( signers: &[&Keypair], ixs: &[Instruction], ) -> Result { - let tx = transaction!(signers, ixs, client); + let tx = transaction!(client, signers, ixs); let signature = client.send_and_confirm_transaction(&tx)?; @@ -39,7 +93,7 @@ pub fn send_and_confirm_tx_with_retries( signers: &[&Keypair], ixs: &[Instruction], ) -> Result { - let tx = transaction!(signers, ixs, client); + let tx = transaction!(client, signers, ixs); // Send tx with retries. let res = retry( @@ -79,3 +133,40 @@ pub fn pack_instructions<'a>( transactions } + +pub fn get_compute_units( + client: &RpcClient, + ixs: &[Instruction], + signers: &[&Keypair], +) -> Result> { + let config = RpcSimulateTransactionConfig { + sig_verify: false, + replace_recent_blockhash: true, + commitment: Some(CommitmentConfig::confirmed()), + ..Default::default() + }; + + let tx = Transaction::new_signed_with_payer( + ixs, + Some(&signers[0].pubkey()), + signers, + Hash::new(Pubkey::default().as_ref()), // dummy value + ); + + // This doesn't return an error if the simulation fails + let sim_result = client.simulate_transaction_with_config(&tx, config)?; + + // it sets the error Option on the value in the Ok variant, so we check here + // and return the error manually. + if let Some(err) = sim_result.value.err { + return Err(err.into()); + } + + // Otherwise, we can get the compute units from the simulation result + let units = sim_result + .value + .units_consumed + .map(|units| (units as f64 * 1.20) as u64); + + Ok(units) +} From b38c64c6b44967c3e9308b055571dec2e229b493 Mon Sep 17 00:00:00 2001 From: Samuel Vanderwaal Date: Sat, 20 Apr 2024 11:24:36 -0800 Subject: [PATCH 2/2] add spinners for non-batch commands --- src/commands/approve.rs | 2 +- src/commands/burn.rs | 2 +- src/commands/create.rs | 2 +- src/commands/lock.rs | 2 +- src/commands/mint.rs | 2 +- src/commands/mint_batch.rs | 1 + src/commands/mod.rs | 5 ++++- src/commands/revoke.rs | 2 +- src/commands/transfer.rs | 2 +- src/commands/unlock.rs | 2 +- src/transaction.rs | 12 ++++++++++++ 11 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/commands/approve.rs b/src/commands/approve.rs index 1f40227..505f147 100644 --- a/src/commands/approve.rs +++ b/src/commands/approve.rs @@ -57,7 +57,7 @@ pub fn handle_approve(args: ApproveArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Setting {delegate} as a delegate on asset {asset} in tx: {sig}"); diff --git a/src/commands/burn.rs b/src/commands/burn.rs index 4d508a3..a28f064 100644 --- a/src/commands/burn.rs +++ b/src/commands/burn.rs @@ -39,7 +39,7 @@ pub fn handle_burn(args: BurnArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Burned asset {asset} in tx: {sig}"); diff --git a/src/commands/create.rs b/src/commands/create.rs index 9579358..3170fb8 100644 --- a/src/commands/create.rs +++ b/src/commands/create.rs @@ -54,7 +54,7 @@ pub fn handle_create(args: CreateArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Asset {asset} created in tx: {sig}"); diff --git a/src/commands/lock.rs b/src/commands/lock.rs index 5bc42d6..e06e683 100644 --- a/src/commands/lock.rs +++ b/src/commands/lock.rs @@ -40,7 +40,7 @@ pub fn handle_lock(args: LockArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Locking asset {asset} in tx: {sig}"); diff --git a/src/commands/mint.rs b/src/commands/mint.rs index 7dec2ef..05ff6b8 100644 --- a/src/commands/mint.rs +++ b/src/commands/mint.rs @@ -69,7 +69,7 @@ pub async fn handle_mint(args: MintArgs) -> Result<()> { ]; final_instructions.extend(instructions); - let sig = send_and_confirm_tx(&config.client, &signers, &final_instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &final_instructions)?; println!("sig: {}", sig); } diff --git a/src/commands/mint_batch.rs b/src/commands/mint_batch.rs index 38036e3..cd0c0c4 100644 --- a/src/commands/mint_batch.rs +++ b/src/commands/mint_batch.rs @@ -174,6 +174,7 @@ pub async fn handle_mint_batch(args: MintBatchArgs) -> Result<()> { final_instructions.extend(instructions); let res = send_and_confirm_tx(&client, &signers, &final_instructions); + pb.inc(1); match res { diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 60449c5..85b7bb7 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -24,7 +24,10 @@ pub use unlock::*; // Internal lib pub use crate::{ setup::CliConfig, - transaction::{get_compute_units, get_priority_fee, send_and_confirm_tx, Priority}, + transaction::{ + get_compute_units, get_priority_fee, send_and_confirm_tx, send_and_confirm_tx_with_spinner, + Priority, + }, }; // Standard lib diff --git a/src/commands/revoke.rs b/src/commands/revoke.rs index c7f17fb..d4d75d5 100644 --- a/src/commands/revoke.rs +++ b/src/commands/revoke.rs @@ -54,7 +54,7 @@ pub fn handle_revoke(args: RevokeArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Revoking the delegate on asset {asset} in tx: {sig}"); diff --git a/src/commands/transfer.rs b/src/commands/transfer.rs index 9cc3c72..330d942 100644 --- a/src/commands/transfer.rs +++ b/src/commands/transfer.rs @@ -39,7 +39,7 @@ pub fn handle_transfer(args: TransferArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Transferring asset {asset} to {recipient} in tx: {sig}"); diff --git a/src/commands/unlock.rs b/src/commands/unlock.rs index f53288f..728143d 100644 --- a/src/commands/unlock.rs +++ b/src/commands/unlock.rs @@ -40,7 +40,7 @@ pub fn handle_unlock(args: UnlockArgs) -> Result<()> { ix, ]; - let sig = send_and_confirm_tx(&config.client, &signers, &instructions)?; + let sig = send_and_confirm_tx_with_spinner(&config.client, &signers, &instructions)?; println!("Unlocking asset {asset} in tx: {sig}"); diff --git a/src/transaction.rs b/src/transaction.rs index 3a7d99e..9472725 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -88,6 +88,18 @@ pub fn send_and_confirm_tx( Ok(signature) } +pub fn send_and_confirm_tx_with_spinner( + client: &RpcClient, + signers: &[&Keypair], + ixs: &[Instruction], +) -> Result { + let tx = transaction!(client, signers, ixs); + + let signature = client.send_and_confirm_transaction_with_spinner(&tx)?; + + Ok(signature) +} + pub fn send_and_confirm_tx_with_retries( client: &RpcClient, signers: &[&Keypair],