apex_sdk_substrate/
signer.rs

1//! Custom signer implementation for Substrate transactions
2//!
3//! This module provides a custom signer that replaces the deprecated PairSigner
4//! from substrate-compat. It implements the subxt::tx::Signer trait for SR25519
5//! and ED25519 key pairs.
6
7use sp_core::{ed25519, sr25519, Pair as _};
8use subxt::tx::Signer;
9
10// Import AccountId32 and MultiSignature from subxt instead of sp_runtime
11type AccountId32 = subxt::utils::AccountId32;
12type MultiSignature = subxt::utils::MultiSignature;
13
14/// Custom signer for SR25519 key pairs
15#[derive(Clone)]
16pub struct Sr25519Signer {
17    pair: sr25519::Pair,
18    account_id: AccountId32,
19}
20
21impl Sr25519Signer {
22    /// Create a new SR25519 signer from a key pair
23    pub fn new(pair: sr25519::Pair) -> Self {
24        let public_key = pair.public();
25        // Convert sp_core public key to subxt AccountId32
26        let account_id = AccountId32::from(public_key.0);
27        Self { pair, account_id }
28    }
29
30    /// Get the account ID
31    pub fn account_id(&self) -> &AccountId32 {
32        &self.account_id
33    }
34
35    /// Get the public key
36    pub fn public_key(&self) -> sr25519::Public {
37        self.pair.public()
38    }
39}
40
41impl Signer<subxt::PolkadotConfig> for Sr25519Signer {
42    fn account_id(&self) -> AccountId32 {
43        self.account_id.clone()
44    }
45
46    fn sign(&self, payload: &[u8]) -> <subxt::PolkadotConfig as subxt::Config>::Signature {
47        let signature = self.pair.sign(payload);
48        // Convert sp_core signature to subxt MultiSignature
49        MultiSignature::Sr25519(signature.0)
50    }
51}
52
53/// Custom signer for ED25519 key pairs
54#[derive(Clone)]
55pub struct Ed25519Signer {
56    pair: ed25519::Pair,
57    account_id: AccountId32,
58}
59
60impl Ed25519Signer {
61    /// Create a new ED25519 signer from a key pair
62    pub fn new(pair: ed25519::Pair) -> Self {
63        let public_key = pair.public();
64        // Convert sp_core public key to subxt AccountId32
65        let account_id = AccountId32::from(public_key.0);
66        Self { pair, account_id }
67    }
68
69    /// Get the account ID
70    pub fn account_id(&self) -> &AccountId32 {
71        &self.account_id
72    }
73
74    /// Get the public key
75    pub fn public_key(&self) -> ed25519::Public {
76        self.pair.public()
77    }
78}
79
80impl Signer<subxt::PolkadotConfig> for Ed25519Signer {
81    fn account_id(&self) -> AccountId32 {
82        self.account_id.clone()
83    }
84
85    fn sign(&self, payload: &[u8]) -> <subxt::PolkadotConfig as subxt::Config>::Signature {
86        let signature = self.pair.sign(payload);
87        // Convert sp_core signature to subxt MultiSignature
88        MultiSignature::Ed25519(signature.0)
89    }
90}
91
92/// Enum to hold either SR25519 or ED25519 signer
93#[derive(Clone)]
94#[allow(clippy::large_enum_variant)]
95pub enum ApexSigner {
96    Sr25519(Sr25519Signer),
97    Ed25519(Ed25519Signer),
98}
99
100impl ApexSigner {
101    /// Create from SR25519 pair
102    pub fn from_sr25519(pair: sr25519::Pair) -> Self {
103        Self::Sr25519(Sr25519Signer::new(pair))
104    }
105
106    /// Create from ED25519 pair
107    pub fn from_ed25519(pair: ed25519::Pair) -> Self {
108        Self::Ed25519(Ed25519Signer::new(pair))
109    }
110}
111
112impl Signer<subxt::PolkadotConfig> for ApexSigner {
113    fn account_id(&self) -> AccountId32 {
114        match self {
115            Self::Sr25519(signer) => signer.account_id().clone(),
116            Self::Ed25519(signer) => signer.account_id().clone(),
117        }
118    }
119
120    fn sign(&self, payload: &[u8]) -> <subxt::PolkadotConfig as subxt::Config>::Signature {
121        match self {
122            Self::Sr25519(signer) => signer.sign(payload),
123            Self::Ed25519(signer) => signer.sign(payload),
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use sp_core::Pair;
132
133    #[test]
134    fn test_sr25519_signer() {
135        let (pair, _) = sr25519::Pair::generate();
136        let signer = Sr25519Signer::new(pair);
137
138        let account_id = signer.account_id();
139        assert_eq!(account_id.0.len(), 32);
140    }
141
142    #[test]
143    fn test_ed25519_signer() {
144        let (pair, _) = ed25519::Pair::generate();
145        let signer = Ed25519Signer::new(pair);
146
147        let account_id = signer.account_id();
148        assert_eq!(account_id.0.len(), 32);
149    }
150
151    #[test]
152    fn test_apex_signer_sr25519() {
153        let (pair, _) = sr25519::Pair::generate();
154        let signer = ApexSigner::from_sr25519(pair.clone());
155
156        let message = b"test message";
157        let _signature = signer.sign(message);
158
159        // Verify account ID is correct
160        assert_eq!(signer.account_id().0.len(), 32);
161    }
162
163    #[test]
164    fn test_apex_signer_ed25519() {
165        let (pair, _) = ed25519::Pair::generate();
166        let signer = ApexSigner::from_ed25519(pair);
167
168        let message = b"test message";
169        let _signature = signer.sign(message);
170
171        // Verify account ID is correct
172        assert_eq!(signer.account_id().0.len(), 32);
173    }
174}