poseidon_client/transactions/
message_builder.rs

1use crate::{AccountMeta, Instruction, PublicKey};
2use core::fmt;
3
4#[derive(Clone)]
5pub struct MessageBuilder {
6    pub(crate) instructions: Vec<Instruction>,
7    pub(crate) program_ids: Vec<AccountMeta>,
8    pub(crate) signed_keys: Vec<PublicKey>,
9    pub(crate) unsigned_keys: Vec<PublicKey>,
10    pub(crate) num_readonly_signed_accounts: u8,
11    pub(crate) num_readonly_unsigned_accounts: u8,
12    pub(crate) payer: Option<PublicKey>,
13}
14
15impl Default for MessageBuilder {
16    fn default() -> Self {
17        MessageBuilder::new()
18    }
19}
20
21impl MessageBuilder {
22    pub fn new() -> Self {
23        MessageBuilder {
24            instructions: Vec::default(),
25            program_ids: Vec::default(),
26            signed_keys: Vec::default(),
27            unsigned_keys: Vec::default(),
28            num_readonly_signed_accounts: u8::default(),
29            num_readonly_unsigned_accounts: u8::default(),
30            payer: Option::default(),
31        }
32    }
33
34    pub fn add_instruction(&mut self, instruction: Instruction) -> &mut Self {
35        self.instructions.push(instruction);
36
37        self
38    }
39
40    pub fn add_payer(&mut self, payer: PublicKey) -> &mut Self {
41        self.payer = Some(payer);
42
43        self
44    }
45
46    pub fn build(&mut self) -> &mut Self {
47        self.instructions.iter().for_each(|instruction| {
48            self.program_ids.push(AccountMeta {
49                pubkey: instruction.program_id,
50                is_signer: false,
51                is_writable: false,
52            });
53        });
54
55        let mut instruction_account_metas: Vec<_> = self
56            .instructions
57            .iter()
58            .flat_map(|ix| ix.accounts.iter())
59            .collect();
60
61        instruction_account_metas.extend(&self.program_ids);
62
63        // Make signers first
64        instruction_account_metas.sort_by(|x, y| {
65            y.is_signer
66                .cmp(&x.is_signer)
67                .then(y.is_writable.cmp(&x.is_writable))
68        });
69
70        let payer_account_meta;
71        if let Some(payer) = self.payer {
72            payer_account_meta = AccountMeta {
73                pubkey: payer,
74                is_signer: true,
75                is_writable: true,
76            };
77
78            instruction_account_metas.insert(0, &payer_account_meta);
79        }
80
81        let mut unique_account_metas: Vec<AccountMeta> = Vec::default();
82        for account_meta in instruction_account_metas {
83            // Promote to writable if a later AccountMeta requires it
84            if let Some(x) = unique_account_metas
85                .iter_mut()
86                .find(|x| x.pubkey == account_meta.pubkey)
87            {
88                x.is_writable |= account_meta.is_writable;
89                continue;
90            }
91            unique_account_metas.push(account_meta.clone());
92        }
93
94        unique_account_metas.iter().for_each(|account_meta| {
95            if account_meta.is_signer {
96                self.signed_keys.push(account_meta.pubkey);
97                if !account_meta.is_writable {
98                    self.num_readonly_signed_accounts += 1;
99                }
100            } else {
101                self.unsigned_keys.push(account_meta.pubkey);
102                if !account_meta.is_writable {
103                    self.num_readonly_unsigned_accounts += 1;
104                }
105            }
106        });
107
108        self
109    }
110}
111
112impl fmt::Debug for MessageBuilder {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        let signed_keys = self
115            .signed_keys
116            .iter()
117            .map(|public_key| bs58::encode(&public_key).into_string())
118            .collect::<Vec<String>>();
119
120        let unsigned_keys = self
121            .unsigned_keys
122            .iter()
123            .map(|public_key| bs58::encode(&public_key).into_string())
124            .collect::<Vec<String>>();
125
126        f.debug_struct("MessageBuilder")
127            .field("instructions", &self.instructions)
128            .field("program_ids", &self.program_ids)
129            .field("signed_keys", &signed_keys)
130            .field("unsigned_keys", &unsigned_keys)
131            .field(
132                "num_readonly_signed_accounts",
133                &self.num_readonly_signed_accounts,
134            )
135            .field(
136                "num_readonly_unsigned_accounts",
137                &self.num_readonly_unsigned_accounts,
138            )
139            .field(
140                "payer",
141                &match self.payer {
142                    Some(payer) => Some(bs58::encode(payer).into_string()),
143                    None => None,
144                },
145            )
146            .finish()
147    }
148}