bittensor_rs/wallet/
signer.rs

1//! # Wallet Signer
2//!
3//! A subxt-compatible signer wrapper for Bittensor wallets.
4
5use subxt_signer::sr25519::Keypair;
6
7/// A signer that wraps an sr25519 keypair for use with subxt
8///
9/// This implements the signing required by subxt for signing extrinsics.
10#[derive(Clone)]
11pub struct WalletSigner {
12    inner: Keypair,
13}
14
15impl WalletSigner {
16    /// Create a new signer from a subxt-signer keypair
17    ///
18    /// # Example
19    ///
20    /// ```ignore
21    /// use bittensor_rs::wallet::WalletSigner;
22    /// use subxt_signer::sr25519::Keypair;
23    ///
24    /// let keypair = Keypair::from_uri(&"//Alice".parse().unwrap()).unwrap();
25    /// let signer = WalletSigner::new(keypair);
26    /// ```
27    pub fn new(keypair: Keypair) -> Self {
28        Self { inner: keypair }
29    }
30
31    /// Create a signer from an sp_core sr25519 Pair
32    ///
33    /// This converts the sp_core keypair to a subxt-signer keypair.
34    pub fn from_sp_core_pair(pair: sp_core::sr25519::Pair) -> Self {
35        use sp_core::Pair;
36        // Get the seed bytes from the pair by converting to raw bytes
37        // The secret key is the first 64 bytes (32 bytes key + 32 bytes nonce)
38        let seed = pair.to_raw_vec();
39        let keypair = Keypair::from_secret_key(seed[..32].try_into().unwrap())
40            .expect("Valid 32-byte seed");
41        Self { inner: keypair }
42    }
43
44    /// Create a signer from a seed phrase (mnemonic or hex seed)
45    pub fn from_seed(seed: &str) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
46        use subxt_signer::SecretUri;
47        
48        let uri: SecretUri = seed.parse()?;
49        let keypair = Keypair::from_uri(&uri)?;
50        Ok(Self { inner: keypair })
51    }
52
53    /// Get the underlying Keypair for advanced usage
54    pub fn keypair(&self) -> &Keypair {
55        &self.inner
56    }
57
58    /// Get the public key bytes
59    pub fn public_key(&self) -> [u8; 32] {
60        self.inner.public_key().0
61    }
62}
63
64impl std::fmt::Debug for WalletSigner {
65    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66        f.debug_struct("WalletSigner")
67            .field("public_key", &hex::encode(self.public_key()))
68            .finish()
69    }
70}
71
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn test_signer_from_uri() {
79        let signer = WalletSigner::from_seed("//Alice").unwrap();
80        // Alice's public key should be well-known
81        assert!(!signer.public_key().iter().all(|&b| b == 0));
82    }
83
84    #[test]
85    fn test_signer_debug() {
86        let signer = WalletSigner::from_seed("//Alice").unwrap();
87        let debug_str = format!("{:?}", signer);
88        assert!(debug_str.contains("WalletSigner"));
89        assert!(debug_str.contains("public_key"));
90    }
91}