Skip to main content

gmsol_sdk/utils/
instruction_serialization.rs

1use std::borrow::Cow;
2
3use base64::{engine::general_purpose::STANDARD, Engine};
4use solana_sdk::instruction::Instruction;
5use solana_sdk::pubkey::Pubkey;
6
7/// Instruction serialziation format.
8#[derive(Debug, Default, Clone, Copy)]
9#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
12pub enum InstructionSerialization {
13    /// Base58 (Squads).
14    Base58,
15    #[default]
16    /// Base64.
17    Base64,
18    /// Base58 (Legacy).
19    Base58Legacy,
20}
21
22/// Serialize an instruction.
23pub fn serialize_instruction(
24    ix: &Instruction,
25    format: InstructionSerialization,
26    payer: Option<&Pubkey>,
27) -> crate::Result<String> {
28    use solana_sdk::message::legacy::Message;
29
30    let message = match format {
31        InstructionSerialization::Base58
32        | InstructionSerialization::Base64
33        | InstructionSerialization::Base58Legacy => {
34            let message = Message::new(&[ix.clone()], payer);
35            match format {
36                InstructionSerialization::Base58 | InstructionSerialization::Base58Legacy => {
37                    bs58::encode(message.serialize()).into_string()
38                }
39                InstructionSerialization::Base64 => STANDARD.encode(message.serialize()),
40            }
41        }
42    };
43
44    Ok(message)
45}
46
47/// Serialize message.
48pub fn serialize_message(
49    message: &solana_sdk::message::VersionedMessage,
50    format: InstructionSerialization,
51) -> crate::Result<String> {
52    let message = match format {
53        InstructionSerialization::Base58 => bs58::encode(message.serialize()).into_string(),
54        InstructionSerialization::Base64 => STANDARD.encode(message.serialize()),
55        InstructionSerialization::Base58Legacy => {
56            let message = to_legacy_message(message)?;
57            bs58::encode(message.serialize()).into_string()
58        }
59    };
60    Ok(message)
61}
62
63/// Convert to legacy message.
64pub fn to_legacy_message<'a>(
65    message: &'a solana_sdk::message::VersionedMessage,
66) -> crate::Result<Cow<'a, solana_sdk::message::legacy::Message>> {
67    use solana_sdk::message::{legacy::Message, VersionedMessage};
68
69    match message {
70        VersionedMessage::Legacy(message) => Ok(Cow::Borrowed(message)),
71        VersionedMessage::V0(message) => {
72            if !message.address_table_lookups.is_empty() {
73                return Err(crate::Error::custom("a v0 message that includes address table lookups cannot be converted to a legacy message"));
74            }
75            Ok(Cow::Owned(Message {
76                header: message.header,
77                account_keys: message.account_keys.clone(),
78                recent_blockhash: message.recent_blockhash,
79                instructions: message.instructions.clone(),
80            }))
81        }
82    }
83}