poseidon_client/transactions/
message_builder.rs1use 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 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 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}