xmtp_id/
lib.rs

1#![warn(clippy::unwrap_used)]
2
3pub mod associations;
4pub mod constants;
5pub mod scw_verifier;
6pub mod utils;
7
8pub use alloy::primitives::{BlockNumber, Bytes};
9use alloy::{signers::SignerSync, signers::local::PrivateKeySigner};
10use associations::{
11    Identifier,
12    unverified::{UnverifiedRecoverableEcdsaSignature, UnverifiedSignature},
13};
14use openmls_traits::types::CryptoError;
15use thiserror::Error;
16use xmtp_common::{MaybeSend, MaybeSync};
17use xmtp_cryptography::signature::{IdentifierValidationError, SignatureError, h160addr_to_string};
18
19#[derive(Debug, Error)]
20pub enum IdentityError {
21    #[error("generating key-pairs: {0}")]
22    KeyGenerationError(#[from] CryptoError),
23    #[error("uninitialized identity")]
24    UninitializedIdentity,
25    #[error("protobuf deserialization: {0}")]
26    Deserialization(#[from] prost::DecodeError),
27    #[error(transparent)]
28    UrlParseError(#[from] url::ParseError),
29    #[error("MLS signer error {0}")]
30    Signing(#[from] xmtp_cryptography::SignerError),
31}
32
33/// The global InboxID Reference Type.
34pub type InboxIdRef<'a> = &'a str;
35
36/// Global InboxID Owned Type.
37pub type InboxId = String;
38
39pub type WalletAddress = String;
40
41use crate::associations::unverified::UnverifiedIdentityUpdate;
42use xmtp_proto::ConversionError;
43use xmtp_proto::xmtp::identity::api::v1::get_identity_updates_response::IdentityUpdateLog;
44
45#[derive(Clone, Debug)]
46pub struct InboxUpdate {
47    pub sequence_id: u64,
48    pub server_timestamp_ns: u64,
49    pub update: UnverifiedIdentityUpdate,
50}
51
52impl TryFrom<IdentityUpdateLog> for InboxUpdate {
53    type Error = ConversionError;
54
55    fn try_from(update: IdentityUpdateLog) -> Result<Self, Self::Error> {
56        Ok(Self {
57            sequence_id: update.sequence_id,
58            server_timestamp_ns: update.server_timestamp_ns,
59            update: update
60                .update
61                .ok_or(ConversionError::Missing {
62                    item: "update",
63                    r#type: std::any::type_name::<IdentityUpdateLog>(),
64                })?
65                .try_into()?,
66        })
67    }
68}
69
70pub trait AsIdRef: MaybeSend + MaybeSync {
71    fn as_ref(&'_ self) -> InboxIdRef<'_>;
72}
73
74impl AsIdRef for InboxId {
75    fn as_ref(&self) -> InboxIdRef<'_> {
76        self
77    }
78}
79impl AsIdRef for &InboxId {
80    fn as_ref(&self) -> InboxIdRef<'_> {
81        self
82    }
83}
84impl AsIdRef for InboxIdRef<'_> {
85    fn as_ref(&self) -> InboxIdRef<'_> {
86        self
87    }
88}
89
90pub trait InboxOwner {
91    /// Get address string of the wallet.
92    fn get_identifier(&self) -> Result<Identifier, IdentifierValidationError>;
93
94    /// Sign text with the wallet.
95    fn sign(&self, text: &str) -> Result<UnverifiedSignature, SignatureError>;
96}
97
98impl InboxOwner for PrivateKeySigner {
99    fn get_identifier(&self) -> Result<Identifier, IdentifierValidationError> {
100        Identifier::eth(h160addr_to_string(self.address()))
101    }
102
103    fn sign(&self, text: &str) -> Result<UnverifiedSignature, SignatureError> {
104        let signature_bytes = self.sign_message_sync(text.as_bytes())?;
105        let sig = UnverifiedSignature::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature {
106            signature_bytes: signature_bytes.into(),
107        });
108        Ok(sig)
109    }
110}
111
112impl<T> InboxOwner for &T
113where
114    T: InboxOwner,
115{
116    fn get_identifier(&self) -> Result<Identifier, IdentifierValidationError> {
117        (**self).get_identifier()
118    }
119
120    fn sign(&self, text: &str) -> Result<UnverifiedSignature, SignatureError> {
121        (**self).sign(text)
122    }
123}