solana_trader_client_rust/common/
signing.rs
1use anyhow::Result;
2use base64::{engine::general_purpose::STANDARD, Engine};
3use bincode::{deserialize, serialize};
4use serde::Serialize;
5use solana_hash::Hash;
6use solana_sdk::{
7 instruction::Instruction,
8 message::VersionedMessage,
9 pubkey::Pubkey,
10 signature::{Keypair, Signature},
11 signer::Signer,
12 transaction::{Transaction, VersionedTransaction},
13};
14use solana_trader_proto::api;
15
16use crate::provider::utils::IntoTransactionMessage;
17
18#[derive(Debug, Clone, Serialize)]
19pub struct SubmitParams {
20 pub skip_pre_flight: bool,
21 pub front_running_protection: bool,
22 pub use_staked_rpcs: bool,
23 pub fast_best_effort: bool,
24 pub submit_strategy: api::SubmitStrategy,
25 pub allow_back_run: Option<bool>,
26 pub revenue_address: Option<String>,
27 pub allow_revert: Option<bool>,
28}
29
30impl Default for SubmitParams {
31 fn default() -> Self {
32 Self {
33 skip_pre_flight: true,
34 front_running_protection: false,
35 use_staked_rpcs: false,
36 fast_best_effort: false,
37 submit_strategy: api::SubmitStrategy::PSubmitAll,
38 allow_back_run: None,
39 revenue_address: None,
40 allow_revert: None,
41 }
42 }
43}
44
45#[derive(Debug, Serialize)]
46pub struct SignedTransaction {
47 pub content: String,
48 pub is_cleanup: bool,
49}
50
51pub async fn sign_transaction<T>(
52 tx: &T,
53 keypair: &Keypair,
54 blockhash: String,
55) -> Result<SignedTransaction>
56where
57 T: IntoTransactionMessage + Clone,
58{
59 let tx_message = tx.clone().into_transaction_message();
60 let rawbytes = STANDARD.decode(&tx_message.content)?;
61 let parsed_hash = blockhash.parse()?;
62
63 let signed_data = match deserialize(&rawbytes) {
64 Ok(versioned_tx) => sign_versioned_transaction(versioned_tx, keypair, parsed_hash)?,
65 Err(_) => sign_legacy_transaction(&rawbytes, keypair, parsed_hash)?,
66 };
67
68 Ok(SignedTransaction {
69 content: STANDARD.encode(signed_data),
70 is_cleanup: tx_message.is_cleanup,
71 })
72}
73
74fn sign_versioned_transaction(
75 mut tx: VersionedTransaction,
76 keypair: &Keypair,
77 blockhash: solana_sdk::hash::Hash,
78) -> Result<Vec<u8>> {
79 match &mut tx.message {
80 VersionedMessage::Legacy(message) => {
81 message.recent_blockhash = blockhash;
82 }
83 VersionedMessage::V0(message) => {
84 message.recent_blockhash = blockhash;
85 }
86 }
87
88 tx.signatures = vec![Signature::default()];
89 let message_data = tx.message.serialize();
90 tx.signatures[0] = keypair.sign_message(&message_data);
91
92 Ok(serialize(&tx)?)
93}
94
95fn sign_legacy_transaction(
96 rawbytes: &[u8],
97 keypair: &Keypair,
98 blockhash: solana_sdk::hash::Hash,
99) -> Result<Vec<u8>> {
100 let mut tx: Transaction = deserialize(rawbytes)?;
101 tx.try_partial_sign(&[keypair], blockhash)?;
102 Ok(serialize(&tx)?)
103}
104
105pub fn create_signed_transaction(
106 instruction: Vec<Instruction>,
107 payer: &Pubkey,
108 keypair: &Keypair,
109 block_hash: Hash,
110) -> anyhow::Result<Transaction> {
111 let mut transaction =
112 Transaction::new_signed_with_payer(&instruction, Some(payer), &[keypair], block_hash);
113
114 let message_data = transaction.message.serialize();
115 transaction.signatures = vec![Signature::default()];
116 transaction.signatures[0] = keypair.sign_message(&message_data);
117
118 Ok(transaction)
119}