1use anyhow::Result;
2use nifty_asset::MAX_TX_SIZE;
3use retry::{delay::Exponential, retry};
4use solana_client::rpc_client::RpcClient;
5use solana_program::instruction::Instruction;
6use solana_sdk::{
7 pubkey::Pubkey,
8 signature::{Keypair, Signature},
9 signer::Signer,
10 transaction::Transaction,
11};
12
13#[macro_export]
14macro_rules! transaction {
15 ($signers:expr, $instructions:expr, $client:expr) => {
16 Transaction::new_signed_with_payer(
17 $instructions,
18 Some(&$signers[0].pubkey()),
19 $signers,
20 $client.get_latest_blockhash()?,
21 )
22 };
23}
24
25pub fn send_and_confirm_tx(
26 client: &RpcClient,
27 signers: &[&Keypair],
28 ixs: &[Instruction],
29) -> Result<Signature> {
30 let tx = transaction!(signers, ixs, client);
31
32 let signature = client.send_and_confirm_transaction(&tx)?;
33
34 Ok(signature)
35}
36
37pub fn send_and_confirm_tx_with_retries(
38 client: &RpcClient,
39 signers: &[&Keypair],
40 ixs: &[Instruction],
41) -> Result<Signature> {
42 let tx = transaction!(signers, ixs, client);
43
44 let res = retry(
46 Exponential::from_millis_with_factor(250, 2.0).take(3),
47 || client.send_and_confirm_transaction_with_spinner(&tx),
48 )?;
49
50 Ok(res)
51}
52
53pub fn pack_instructions<'a>(
54 num_signers: u32,
55 payer: &'a Pubkey,
56 ixs: &'a [Instruction],
57) -> Vec<Vec<Instruction>> {
58 let mut transactions: Vec<Vec<Instruction>> = vec![];
60 let mut tx_instructions: Vec<Instruction> = vec![];
62
63 let max_payload_size = MAX_TX_SIZE - std::mem::size_of::<Signature>() * num_signers as usize;
65
66 for ix in ixs {
67 tx_instructions.push(ix.clone());
68 let tx = Transaction::new_with_payer(tx_instructions.as_slice(), Some(payer));
69 let tx_len = bincode::serialize(&tx).unwrap().len();
70
71 if tx_len > max_payload_size {
72 let last_ix = tx_instructions.pop().unwrap();
73 transactions.push(tx_instructions.clone());
74 tx_instructions.clear();
75 tx_instructions.push(last_ix);
76 }
77 }
78 transactions.push(tx_instructions);
79
80 transactions
81}