1#![cfg(feature = "full")]
4
5use {
6 crate::{
7 pubkey::Pubkey,
8 signature::{PresignerError, Signature},
9 },
10 itertools::Itertools,
11 solana_derivation_path::DerivationPath,
12 solana_transaction_error::TransactionError,
13 std::{
14 error,
15 fs::{self, File, OpenOptions},
16 io::{Read, Write},
17 ops::Deref,
18 path::Path,
19 },
20 thiserror::Error,
21};
22
23pub mod keypair;
24pub mod null_signer;
25pub mod presigner;
26pub mod signers;
27
28#[derive(Debug, Error, PartialEq, Eq)]
29pub enum SignerError {
30 #[error("keypair-pubkey mismatch")]
31 KeypairPubkeyMismatch,
32
33 #[error("not enough signers")]
34 NotEnoughSigners,
35
36 #[error("transaction error")]
37 TransactionError(#[from] TransactionError),
38
39 #[error("custom error: {0}")]
40 Custom(String),
41
42 #[error("presigner error")]
44 PresignerError(#[from] PresignerError),
45
46 #[error("connection error: {0}")]
48 Connection(String),
49
50 #[error("invalid input: {0}")]
51 InvalidInput(String),
52
53 #[error("no device found")]
54 NoDeviceFound,
55
56 #[error("{0}")]
57 Protocol(String),
58
59 #[error("{0}")]
60 UserCancel(String),
61
62 #[error("too many signers")]
63 TooManySigners,
64}
65
66pub trait Signer {
70 fn pubkey(&self) -> Pubkey {
73 self.try_pubkey().unwrap_or_default()
74 }
75 fn try_pubkey(&self) -> Result<Pubkey, SignerError>;
77 fn sign_message(&self, message: &[u8]) -> Signature {
80 self.try_sign_message(message).unwrap_or_default()
81 }
82 fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError>;
84 fn is_interactive(&self) -> bool;
86}
87
88impl<Container: Deref<Target = impl Signer + ?Sized>> Signer for Container {
90 #[inline]
91 fn pubkey(&self) -> Pubkey {
92 self.deref().pubkey()
93 }
94
95 fn try_pubkey(&self) -> Result<Pubkey, SignerError> {
96 self.deref().try_pubkey()
97 }
98
99 fn sign_message(&self, message: &[u8]) -> Signature {
100 self.deref().sign_message(message)
101 }
102
103 fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError> {
104 self.deref().try_sign_message(message)
105 }
106
107 fn is_interactive(&self) -> bool {
108 self.deref().is_interactive()
109 }
110}
111
112impl PartialEq for dyn Signer {
113 fn eq(&self, other: &dyn Signer) -> bool {
114 self.pubkey() == other.pubkey()
115 }
116}
117
118impl Eq for dyn Signer {}
119
120impl std::fmt::Debug for dyn Signer {
121 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
122 write!(fmt, "Signer: {:?}", self.pubkey())
123 }
124}
125
126pub fn unique_signers(signers: Vec<&dyn Signer>) -> Vec<&dyn Signer> {
128 signers.into_iter().unique_by(|s| s.pubkey()).collect()
129}
130
131pub trait EncodableKey: Sized {
134 fn read<R: Read>(reader: &mut R) -> Result<Self, Box<dyn error::Error>>;
135 fn read_from_file<F: AsRef<Path>>(path: F) -> Result<Self, Box<dyn error::Error>> {
136 let mut file = File::open(path.as_ref())?;
137 Self::read(&mut file)
138 }
139 fn write<W: Write>(&self, writer: &mut W) -> Result<String, Box<dyn error::Error>>;
140 fn write_to_file<F: AsRef<Path>>(&self, outfile: F) -> Result<String, Box<dyn error::Error>> {
141 let outfile = outfile.as_ref();
142
143 if let Some(outdir) = outfile.parent() {
144 fs::create_dir_all(outdir)?;
145 }
146
147 let mut f = {
148 #[cfg(not(unix))]
149 {
150 OpenOptions::new()
151 }
152 #[cfg(unix)]
153 {
154 use std::os::unix::fs::OpenOptionsExt;
155 OpenOptions::new().mode(0o600)
156 }
157 }
158 .write(true)
159 .truncate(true)
160 .create(true)
161 .open(outfile)?;
162
163 self.write(&mut f)
164 }
165}
166
167pub trait SeedDerivable: Sized {
170 fn from_seed(seed: &[u8]) -> Result<Self, Box<dyn error::Error>>;
171 fn from_seed_and_derivation_path(
172 seed: &[u8],
173 derivation_path: Option<DerivationPath>,
174 ) -> Result<Self, Box<dyn error::Error>>;
175 fn from_seed_phrase_and_passphrase(
176 seed_phrase: &str,
177 passphrase: &str,
178 ) -> Result<Self, Box<dyn error::Error>>;
179}
180
181pub trait EncodableKeypair: EncodableKey {
184 type Pubkey: ToString;
185
186 fn encodable_pubkey(&self) -> Self::Pubkey;
188}
189
190#[cfg(test)]
191mod tests {
192 use {super::*, crate::signer::keypair::Keypair};
193
194 fn pubkeys(signers: &[&dyn Signer]) -> Vec<Pubkey> {
195 signers.iter().map(|x| x.pubkey()).collect()
196 }
197
198 #[test]
199 fn test_unique_signers() {
200 let alice = Keypair::new();
201 let bob = Keypair::new();
202 assert_eq!(
203 pubkeys(&unique_signers(vec![&alice, &bob, &alice])),
204 pubkeys(&[&alice, &bob])
205 );
206 }
207
208 #[test]
209 fn test_containers() {
210 use std::{rc::Rc, sync::Arc};
211
212 struct Foo<S: Signer> {
213 #[allow(unused)]
214 signer: S,
215 }
216
217 fn foo(_s: impl Signer) {}
218
219 let _arc_signer = Foo {
220 signer: Arc::new(Keypair::new()),
221 };
222 foo(Arc::new(Keypair::new()));
223
224 let _rc_signer = Foo {
225 signer: Rc::new(Keypair::new()),
226 };
227 foo(Rc::new(Keypair::new()));
228
229 let _ref_signer = Foo {
230 signer: &Keypair::new(),
231 };
232 foo(Keypair::new());
233
234 let _box_signer = Foo {
235 signer: Box::new(Keypair::new()),
236 };
237 foo(Box::new(Keypair::new()));
238
239 let _signer = Foo {
240 signer: Keypair::new(),
241 };
242 foo(Keypair::new());
243 }
244}