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
33pub type InboxIdRef<'a> = &'a str;
35
36pub 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 fn get_identifier(&self) -> Result<Identifier, IdentifierValidationError>;
93
94 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}