gmsol_solana_utils/
signer.rs1use std::{collections::HashMap, fmt, ops::Deref, sync::Arc};
2
3use dyn_clone::{clone_trait_object, DynClone};
4use solana_sdk::{
5 hash::Hash,
6 pubkey::Pubkey,
7 signature::Signature,
8 signer::{Signer, SignerError},
9 transaction::VersionedTransaction,
10};
11
12use crate::{
13 address_lookup_table::AddressLookupTables, instruction_group::GetInstructionsOptions,
14 AtomicGroup,
15};
16
17pub type LocalBoxSigner = Box<dyn Signer>;
19
20#[derive(Clone)]
22pub struct BoxClonableSigner<'a>(pub Box<dyn CloneableSigner + 'a>);
23
24impl fmt::Debug for BoxClonableSigner<'_> {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 f.debug_struct("BoxClonableSigner")
27 .field("pubkey", &self.0.pubkey())
28 .finish_non_exhaustive()
29 }
30}
31
32impl<'a> BoxClonableSigner<'a> {
33 pub fn new(signer: impl Signer + Clone + 'a) -> Self {
35 Self(Box::new(signer))
36 }
37}
38
39pub trait CloneableSigner: Signer + DynClone {}
41
42impl<T: Signer + Clone> CloneableSigner for T {}
43
44clone_trait_object!(CloneableSigner);
45
46impl Signer for BoxClonableSigner<'_> {
47 fn pubkey(&self) -> Pubkey {
48 self.0.pubkey()
49 }
50
51 fn sign_message(&self, message: &[u8]) -> Signature {
52 self.0.sign_message(message)
53 }
54
55 fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
56 self.0.try_pubkey()
57 }
58
59 fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
60 self.0.try_sign_message(message)
61 }
62
63 fn is_interactive(&self) -> bool {
64 self.0.is_interactive()
65 }
66}
67
68pub struct BoxSigner(Box<dyn Signer + Send + Sync>);
70
71impl Signer for BoxSigner {
72 fn pubkey(&self) -> Pubkey {
73 self.0.pubkey()
74 }
75
76 fn try_pubkey(&self) -> Result<Pubkey, solana_sdk::signer::SignerError> {
77 self.0.try_pubkey()
78 }
79
80 fn sign_message(&self, message: &[u8]) -> solana_sdk::signature::Signature {
81 self.0.sign_message(message)
82 }
83
84 fn try_sign_message(
85 &self,
86 message: &[u8],
87 ) -> Result<solana_sdk::signature::Signature, solana_sdk::signer::SignerError> {
88 self.0.try_sign_message(message)
89 }
90
91 fn is_interactive(&self) -> bool {
92 self.0.is_interactive()
93 }
94}
95
96pub type SignerRef = Arc<BoxSigner>;
98
99pub fn shared_signer(signer: impl Signer + Send + Sync + 'static) -> SignerRef {
101 SignerRef::new(BoxSigner(Box::new(signer)))
102}
103
104#[derive(Debug, Clone)]
106pub struct TransactionSigners<C> {
107 signers: HashMap<Pubkey, C>,
108}
109
110impl<C> Default for TransactionSigners<C> {
111 fn default() -> Self {
112 Self {
113 signers: Default::default(),
114 }
115 }
116}
117
118impl<C> TransactionSigners<C> {
119 fn project(&self, ag: &AtomicGroup) -> HashMap<Pubkey, &C> {
120 ag.external_signers()
121 .filter_map(|pubkey| self.signers.get(pubkey).map(|s| (*pubkey, s)))
122 .collect()
123 }
124}
125
126impl<C: Deref<Target = impl Signer>> TransactionSigners<C> {
127 pub fn insert(&mut self, signer: C) -> Option<C> {
129 self.signers.insert(signer.pubkey(), signer)
130 }
131
132 pub fn sign_atomic_instruction_group(
134 &self,
135 ag: &AtomicGroup,
136 recent_blockhash: Hash,
137 options: GetInstructionsOptions,
138 luts: Option<&AddressLookupTables>,
139 allow_partial_sign: bool,
140 ) -> crate::Result<VersionedTransaction> {
141 let signers = self.project(ag);
142 let mut tx = ag.partially_signed_transaction_with_blockhash_and_options(
143 recent_blockhash,
144 options,
145 luts,
146 )?;
147 let message = tx.message.serialize();
148 let expected_signers = &tx.message.static_account_keys()
149 [0..(tx.message.header().num_required_signatures as usize)];
150 let default_signature = Signature::default();
151 for (idx, signature) in tx.signatures.iter_mut().enumerate() {
152 if *signature == default_signature {
153 let pubkey = expected_signers[idx];
154 let Some(signer) = signers.get(&pubkey) else {
155 if allow_partial_sign {
156 continue;
157 } else {
158 return Err(crate::Error::Signer(SignerError::Custom(format!(
159 "missing signer for {pubkey}"
160 ))));
161 }
162 };
163 *signature = signer.sign_message(&message);
164 }
165 }
166 Ok(tx)
167 }
168}
169
170impl<C: Deref<Target = impl Signer>> FromIterator<C> for TransactionSigners<C> {
171 fn from_iter<T: IntoIterator<Item = C>>(iter: T) -> Self {
172 let mut this = Self::default();
173 for signer in iter {
174 this.insert(signer);
175 }
176 this
177 }
178}
179
180impl<C: Deref<Target = impl Signer>> Extend<C> for TransactionSigners<C> {
181 fn extend<T: IntoIterator<Item = C>>(&mut self, iter: T) {
182 for signer in iter {
183 self.insert(signer);
184 }
185 }
186}