waffles_solana_sdk/signer/
mod.rs

1//! Abstractions and implementations for transaction signers.
2
3#![cfg(feature = "full")]
4
5use {
6    crate::{
7        pubkey::Pubkey,
8        signature::{PresignerError, Signature},
9        transaction::TransactionError,
10    },
11    itertools::Itertools,
12    thiserror::Error,
13};
14
15pub mod keypair;
16pub mod null_signer;
17pub mod presigner;
18pub mod signers;
19
20#[derive(Debug, Error, PartialEq, Eq)]
21pub enum SignerError {
22    #[error("keypair-pubkey mismatch")]
23    KeypairPubkeyMismatch,
24
25    #[error("not enough signers")]
26    NotEnoughSigners,
27
28    #[error("transaction error")]
29    TransactionError(#[from] TransactionError),
30
31    #[error("custom error: {0}")]
32    Custom(String),
33
34    // Presigner-specific Errors
35    #[error("presigner error")]
36    PresignerError(#[from] PresignerError),
37
38    // Remote Keypair-specific Errors
39    #[error("connection error: {0}")]
40    Connection(String),
41
42    #[error("invalid input: {0}")]
43    InvalidInput(String),
44
45    #[error("no device found")]
46    NoDeviceFound,
47
48    #[error("{0}")]
49    Protocol(String),
50
51    #[error("{0}")]
52    UserCancel(String),
53
54    #[error("too many signers")]
55    TooManySigners,
56}
57
58/// The `Signer` trait declares operations that all digital signature providers
59/// must support. It is the primary interface by which signers are specified in
60/// `Transaction` signing interfaces
61pub trait Signer {
62    /// Infallibly gets the implementor's public key. Returns the all-zeros
63    /// `Pubkey` if the implementor has none.
64    fn pubkey(&self) -> Pubkey {
65        self.try_pubkey().unwrap_or_default()
66    }
67    /// Fallibly gets the implementor's public key
68    fn try_pubkey(&self) -> Result<Pubkey, SignerError>;
69    /// Infallibly produces an Ed25519 signature over the provided `message`
70    /// bytes. Returns the all-zeros `Signature` if signing is not possible.
71    fn sign_message(&self, message: &[u8]) -> Signature {
72        self.try_sign_message(message).unwrap_or_default()
73    }
74    /// Fallibly produces an Ed25519 signature over the provided `message` bytes.
75    fn try_sign_message(&self, message: &[u8]) -> Result<Signature, SignerError>;
76    /// Whether the impelmentation requires user interaction to sign
77    fn is_interactive(&self) -> bool;
78}
79
80impl<T> From<T> for Box<dyn Signer>
81where
82    T: Signer + 'static,
83{
84    fn from(signer: T) -> Self {
85        Box::new(signer)
86    }
87}
88
89impl PartialEq for dyn Signer {
90    fn eq(&self, other: &dyn Signer) -> bool {
91        self.pubkey() == other.pubkey()
92    }
93}
94
95impl std::fmt::Debug for dyn Signer {
96    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
97        write!(fmt, "Signer: {:?}", self.pubkey())
98    }
99}
100
101/// Removes duplicate signers while preserving order. O(n²)
102pub fn unique_signers(signers: Vec<&dyn Signer>) -> Vec<&dyn Signer> {
103    signers.into_iter().unique_by(|s| s.pubkey()).collect()
104}
105
106#[cfg(test)]
107mod tests {
108    use {super::*, crate::signer::keypair::Keypair};
109
110    fn pubkeys(signers: &[&dyn Signer]) -> Vec<Pubkey> {
111        signers.iter().map(|x| x.pubkey()).collect()
112    }
113
114    #[test]
115    fn test_unique_signers() {
116        let alice = Keypair::new();
117        let bob = Keypair::new();
118        assert_eq!(
119            pubkeys(&unique_signers(vec![&alice, &bob, &alice])),
120            pubkeys(&[&alice, &bob])
121        );
122    }
123}