kora_lib/transaction/
versioned_message.rs1use solana_message::VersionedMessage;
2
3use crate::error::KoraError;
4use base64::{engine::general_purpose::STANDARD, Engine as _};
5
6pub trait VersionedMessageExt {
7 fn encode_b64_message(&self) -> Result<String, KoraError>;
8}
9
10impl VersionedMessageExt for VersionedMessage {
11 fn encode_b64_message(&self) -> Result<String, KoraError> {
12 let serialized = self.serialize();
13 Ok(STANDARD.encode(serialized))
14 }
15}
16
17#[cfg(test)]
18mod tests {
19 use super::*;
20 use solana_message::{compiled_instruction::CompiledInstruction, v0, Message};
21 use solana_sdk::{
22 hash::Hash,
23 instruction::{AccountMeta, Instruction},
24 pubkey::Pubkey,
25 signature::Keypair,
26 signer::Signer as _,
27 };
28
29 #[test]
30 fn test_encode_b64_message_legacy() {
31 let keypair = Keypair::new();
32 let program_id = Pubkey::new_unique();
33 let instruction = Instruction::new_with_bytes(
34 program_id,
35 &[1, 2, 3, 4, 5],
36 vec![AccountMeta::new(keypair.pubkey(), true)],
37 );
38
39 let message =
40 VersionedMessage::Legacy(Message::new(&[instruction], Some(&keypair.pubkey())));
41
42 let encoded = message.encode_b64_message().unwrap();
43
44 let decoded_bytes = STANDARD.decode(&encoded).unwrap();
46 assert!(!decoded_bytes.is_empty());
47
48 let original_bytes = message.serialize();
50 assert_eq!(decoded_bytes, original_bytes);
51 }
52
53 #[test]
54 fn test_encode_b64_message_v0() {
55 let keypair = Keypair::new();
56 let program_id = Pubkey::new_unique();
57 let recipient = Pubkey::new_unique();
58
59 let v0_message = v0::Message {
60 header: solana_message::MessageHeader {
61 num_required_signatures: 1,
62 num_readonly_signed_accounts: 0,
63 num_readonly_unsigned_accounts: 2,
64 },
65 account_keys: vec![keypair.pubkey(), recipient, program_id],
66 recent_blockhash: Hash::new_unique(),
67 instructions: vec![CompiledInstruction {
68 program_id_index: 2,
69 accounts: vec![0, 1],
70 data: vec![1, 2, 3],
71 }],
72 address_table_lookups: vec![],
73 };
74
75 let message = VersionedMessage::V0(v0_message);
76
77 let encoded = message.encode_b64_message().unwrap();
78
79 let decoded_bytes = STANDARD.decode(&encoded).unwrap();
81 assert!(!decoded_bytes.is_empty());
82
83 let original_bytes = message.serialize();
85 assert_eq!(decoded_bytes, original_bytes);
86 }
87
88 #[test]
89 fn test_encode_b64_message_v0_with_lookup_tables() {
90 let keypair = Keypair::new();
91 let program_id = Pubkey::new_unique();
92 let lookup_table_account = Pubkey::new_unique();
93
94 let v0_message = v0::Message {
95 header: solana_message::MessageHeader {
96 num_required_signatures: 1,
97 num_readonly_signed_accounts: 0,
98 num_readonly_unsigned_accounts: 1,
99 },
100 account_keys: vec![keypair.pubkey(), program_id],
101 recent_blockhash: Hash::new_unique(),
102 instructions: vec![CompiledInstruction {
103 program_id_index: 1,
104 accounts: vec![0, 2], data: vec![42, 0, 1, 2],
106 }],
107 address_table_lookups: vec![solana_message::v0::MessageAddressTableLookup {
108 account_key: lookup_table_account,
109 writable_indexes: vec![0],
110 readonly_indexes: vec![],
111 }],
112 };
113
114 let message = VersionedMessage::V0(v0_message);
115
116 let encoded = message.encode_b64_message().unwrap();
117
118 let decoded_bytes = STANDARD.decode(&encoded).unwrap();
120 assert!(!decoded_bytes.is_empty());
121
122 let original_bytes = message.serialize();
124 assert_eq!(decoded_bytes, original_bytes);
125
126 match message {
128 VersionedMessage::V0(v0_msg) => {
129 assert_eq!(v0_msg.address_table_lookups.len(), 1);
130 assert_eq!(v0_msg.address_table_lookups[0].account_key, lookup_table_account);
131 assert_eq!(v0_msg.address_table_lookups[0].writable_indexes, vec![0]);
132 assert_eq!(v0_msg.address_table_lookups[0].readonly_indexes.len(), 0);
133 }
134 _ => panic!("Expected V0 message"),
135 }
136 }
137}