Skip to main content

smart_account_auth/
impls.rs

1#[cfg(feature = "replay")]
2use super::traits::ReplayProtection;
3use core::ops::Deref;
4
5use saa_common::{CredentialError, Identifiable, ensure};
6use crate::{credential::CredentialName, Credential, CredentialData, caller::Caller};
7use crate::traits::CredentialsWrapper;
8
9
10impl From<Caller> for Credential {
11    fn from(c: Caller) -> Self {
12        Credential::Native(c)
13    }
14}
15
16
17impl From<&str> for Credential {
18    fn from(s: &str) -> Self {
19        Caller::from(s).into()
20    }
21}
22
23
24#[cfg(feature = "eth_personal")]
25impl From<saa_auth::ethereum::EthPersonalSign> for Credential {
26    fn from(c: saa_auth::ethereum::EthPersonalSign) -> Self {
27        Credential::EthPersonalSign(c)
28    }
29}
30
31#[cfg(feature = "eth_typed_data")]
32impl From<saa_auth::ethereum::EthTypedData> for Credential {
33    fn from(c: saa_auth::ethereum::EthTypedData) -> Self {
34        Credential::EthTypedData(c)
35    }
36}
37
38
39#[cfg(any(feature = "cosmos_arb", feature = "cosmos_arb_addr"))]
40impl From<saa_auth::cosmos::CosmosArbitrary> for Credential {
41    fn from(c: saa_auth::cosmos::CosmosArbitrary) -> Self {
42        Credential::CosmosArbitrary(c)
43    }
44}
45
46
47#[cfg(feature = "ed25519")]
48impl From<saa_curves::ed25519::Ed25519> for Credential {
49    fn from(c: saa_curves::ed25519::Ed25519) -> Self {
50        Credential::Ed25519(c)
51    }
52}
53
54
55#[cfg(feature = "secp256k1")]
56impl From<saa_curves::secp256k1::Secp256k1> for Credential {
57    fn from(c: saa_curves::secp256k1::Secp256k1) -> Self {
58        Credential::Secp256k1(c)
59    }
60}
61
62#[cfg(feature = "secp256r1")]
63impl From<saa_passkeys::Secp256r1> for Credential {
64    fn from(c: saa_passkeys::Secp256r1) -> Self {
65        Credential::Secp256r1(c)
66    }
67}
68
69
70#[cfg(feature = "passkeys")]
71impl From<saa_passkeys::PasskeyCredential> for Credential {
72    fn from(c: saa_passkeys::PasskeyCredential) -> Self {
73        Credential::Passkey(c)
74    }
75}
76
77
78
79impl Identifiable for Credential {
80    fn cred_id(&self) -> String {
81        self.deref().cred_id()
82    }
83    fn name(&self) -> CredentialName {
84        self.deref().name()
85    }
86}
87
88
89impl Deref for Credential {
90    #[cfg(not(feature = "replay"))]
91    type Target = dyn saa_common::Verifiable;
92    #[cfg(feature = "replay")]
93    type Target = dyn ReplayProtection;
94
95
96    fn deref(&self) -> &Self::Target {
97        match self {
98            Credential::Native(c) => c,
99            #[cfg(feature = "eth_personal")]
100            Credential::EthPersonalSign(c) => c,
101            #[cfg(feature = "eth_typed_data")]
102            Credential::EthTypedData(c) => c,
103            #[cfg(any(feature = "cosmos_arb", feature = "cosmos_arb_addr"))]
104            Credential::CosmosArbitrary(c) => c,
105            #[cfg(feature = "passkeys")]
106            Credential::Passkey(c) => c,
107            #[cfg(feature = "secp256r1")]
108            Credential::Secp256r1(c) => c,
109            #[cfg(feature = "secp256k1")]
110            Credential::Secp256k1(c) => c,
111            #[cfg(feature = "ed25519")]
112            Credential::Ed25519(c) => c,
113        }
114    }
115}
116
117
118
119
120
121
122impl CredentialData {
123    /// Pre-validate without params using self.credentials() or post-validate using verified records
124    pub(crate) fn validate_logic(
125        &self, sender: &str, 
126        records: Option<&Vec<crate::credential::CredentialRecord>>
127    ) -> Result<(), CredentialError> {
128        // self.credentials for pre-validated and parsed recprds for post-validation
129        let iter: Box<dyn Iterator<Item = (String, CredentialName)> + '_> = match records {
130            Some(
131                records
132            ) => Box::new(records.iter().map(|(id, info)| (id.clone(), info.name.clone()))),
133            None => Box::new(self.credentials.iter().map(|c| (c.cred_id(), c.name()))),
134        };
135        // count of credentials, native credentials and whether the sender is found
136        let (count, native_count, sender_found) = iter.fold(
137            (0, 0, false),
138            |(count, native_count, sender_found), (id, name)| (
139                    count + 1, 
140                    if name == CredentialName::Native { native_count + 1 } else { native_count }, 
141                    sender_found || id == sender
142            )
143        );
144        ensure!(count > 0, CredentialError::NoCredentials);
145        ensure!(count <= 255, CredentialError::TooManyCredentials(count));
146
147        if let Some(index) = self.primary_index {
148            ensure!(index < count, CredentialError::IndexOutOfBounds(index, count));
149        }
150        if self.use_native.unwrap_or_default() {
151            ensure!(native_count > 0 && sender_found, CredentialError::NoNativeCaller);
152        }
153        // if all are native make sure that at least one is a validated by the node / environment
154        if native_count == count {
155            ensure!(sender_found, CredentialError::OnlyCustomNatives);
156        }
157        Ok(())
158    }
159}
160
161
162
163impl CredentialData {
164
165    #[cfg(feature = "utils")]
166    pub fn new(
167        credentials: Vec<Credential>,
168        use_native: Option<bool>,
169    ) -> Self {
170        Self {
171            credentials,
172            use_native,
173            primary_index: None,
174            pre_validate: None,
175            override_primary: None,
176        }
177    }
178
179    /// Check whether with_caller flag is set and then ether ignore the arguemnt returning self
180    /// or constucting a new wrapper with the Caller credential being injected 
181    /// @param cal: native caller of the environment
182    /// @return: checked wrapper 
183    pub fn with_native<C: Into::<Caller>> (&self, cal: C) -> Self {
184        if !self.use_native.unwrap_or(false) {
185            return self.clone()
186        }
187        let caller : Caller = cal.into();
188        let mut credentials = self.credentials.clone();
189        match self.cred_index( &caller.0, CredentialName::Native) {
190            Some(index) => credentials[index] = caller.into(),
191            None => credentials.push(caller.into())
192        };
193        Self { 
194            credentials, 
195            ..self.clone()
196        }
197    }
198
199
200}
201