diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index ae5a5b364..32976a29e 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -7,8 +7,6 @@ use std::convert::TryInto; use std::sync::Arc; use tokio::{sync::Mutex, task::AbortHandle}; use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; -use xmtp_id::associations::unverified::UnverifiedErc6492Signature; -use xmtp_id::associations::unverified::UnverifiedRecoverableEcdsaSignature; use xmtp_id::associations::unverified::UnverifiedSignature; use xmtp_id::associations::AccountId; use xmtp_id::associations::AssociationState; @@ -194,9 +192,7 @@ impl FfiSignatureRequest { let mut inner = self.inner.lock().await; inner .add_signature( - UnverifiedSignature::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature::new( - signature_bytes, - )), + UnverifiedSignature::new_recoverable_ecdsa(signature_bytes), &signature_verifier(), ) .await?; @@ -215,11 +211,11 @@ impl FfiSignatureRequest { let mut inner = self.inner.lock().await; let account_id = AccountId::new_evm(chain_id, address); - let signature = UnverifiedSignature::Erc6492(UnverifiedErc6492Signature::new( + let signature = UnverifiedSignature::new_smart_contract_wallet( signature_bytes, account_id, block_number, - )); + ); inner .add_signature(signature, &signature_verifier()) .await?; diff --git a/bindings_node/src/mls_client.rs b/bindings_node/src/mls_client.rs index 73b34030c..43385b79d 100644 --- a/bindings_node/src/mls_client.rs +++ b/bindings_node/src/mls_client.rs @@ -7,9 +7,7 @@ use std::sync::Arc; pub use xmtp_api_grpc::grpc_api_helper::Client as TonicApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; -use xmtp_id::associations::unverified::{ - UnverifiedErc6492Signature, UnverifiedRecoverableEcdsaSignature, UnverifiedSignature, -}; +use xmtp_id::associations::unverified::UnverifiedSignature; use xmtp_id::associations::{AccountId, MemberIdentifier}; use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; @@ -153,9 +151,7 @@ impl NapiClient { )); } - let signature = UnverifiedSignature::RecoverableEcdsa( - UnverifiedRecoverableEcdsaSignature::new(signature_bytes.deref().to_vec()), - ); + let signature = UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.deref().to_vec()); self.signatures.insert( MemberIdentifier::Address(self.account_address.clone().to_lowercase()), @@ -185,11 +181,11 @@ impl NapiClient { let account_id = AccountId::new_evm(chain_id_u64, account_address.clone()); - let signature = UnverifiedSignature::Erc6492(UnverifiedErc6492Signature::new( + let signature = UnverifiedSignature::new_smart_contract_wallet( signature_bytes.deref().to_vec(), account_id, block_number.get_u64().1, - )); + ); self.signatures.insert( MemberIdentifier::Address(account_address.clone().to_lowercase()), diff --git a/bindings_wasm/src/mls_client.rs b/bindings_wasm/src/mls_client.rs index 8f078666d..c84ac166b 100644 --- a/bindings_wasm/src/mls_client.rs +++ b/bindings_wasm/src/mls_client.rs @@ -5,12 +5,10 @@ use wasm_bindgen::prelude::{wasm_bindgen, JsError}; use wasm_bindgen::JsValue; use xmtp_api_http::XmtpHttpApiClient; use xmtp_cryptography::signature::ed25519_public_key_to_address; -use xmtp_id::associations::generate_inbox_id as xmtp_id_generate_inbox_id; -use xmtp_id::associations::unverified::{ - UnverifiedErc6492Signature, UnverifiedRecoverableEcdsaSignature, UnverifiedSignature, +use xmtp_id::associations::{ + generate_inbox_id as xmtp_id_generate_inbox_id, unverified::UnverifiedSignature, AccountId, + MemberIdentifier, }; -use xmtp_id::associations::{AccountId, MemberIdentifier}; -use xmtp_id::scw_verifier::{RpcSmartContractWalletVerifier, SmartContractSignatureVerifier}; use xmtp_mls::api::ApiClientWrapper; use xmtp_mls::builder::ClientBuilder; use xmtp_mls::identity::IdentityStrategy; @@ -150,14 +148,7 @@ impl WasmClient { )); } - let signature_text = match self.signature_text() { - Some(text) => text, - None => return Err(JsError::new("No signature text found")), - }; - - let signature = UnverifiedSignature::RecoverableEcdsa( - UnverifiedRecoverableEcdsaSignature::new(signature_bytes.to_vec()), - ); + let signature = UnverifiedSignature::new_recoverable_ecdsa(signature_bytes.to_vec()); self.signatures.insert( MemberIdentifier::Address(self.account_address.clone().to_lowercase()), @@ -183,18 +174,13 @@ impl WasmClient { )); } - let signature_text = match self.signature_text() { - Some(text) => text, - None => return Err(JsError::new("No signature text found")), - }; - let account_id = AccountId::new_evm(chain_id, account_address.clone()); - let signature = UnverifiedSignature::Erc6492(UnverifiedErc6492Signature::new( + let signature = UnverifiedSignature::new_smart_contract_wallet( signature_bytes.to_vec(), account_id, block_number, - )); + ); self.signatures.insert( MemberIdentifier::Address(account_address.clone().to_lowercase()), diff --git a/xmtp_id/src/associations/builder.rs b/xmtp_id/src/associations/builder.rs index d9bf6148a..b8f6b1ff8 100644 --- a/xmtp_id/src/associations/builder.rs +++ b/xmtp_id/src/associations/builder.rs @@ -239,7 +239,7 @@ impl SignatureRequest { return Err(SignatureRequestError::UnknownSigner); } - self.signatures.insert(signer_identity.clone(), signature); + self.signatures.insert(verified_sig.signer, signature); Ok(()) } diff --git a/xmtp_id/src/associations/serialization.rs b/xmtp_id/src/associations/serialization.rs index 6d7f76573..0e67e37e6 100644 --- a/xmtp_id/src/associations/serialization.rs +++ b/xmtp_id/src/associations/serialization.rs @@ -10,9 +10,9 @@ use super::{ }, unverified::{ UnverifiedAction, UnverifiedAddAssociation, UnverifiedChangeRecoveryAddress, - UnverifiedCreateInbox, UnverifiedErc6492Signature, UnverifiedIdentityUpdate, - UnverifiedInstallationKeySignature, UnverifiedLegacyDelegatedSignature, - UnverifiedRecoverableEcdsaSignature, UnverifiedRevokeAssociation, UnverifiedSignature, + UnverifiedCreateInbox, UnverifiedIdentityUpdate, UnverifiedInstallationKeySignature, + UnverifiedLegacyDelegatedSignature, UnverifiedRecoverableEcdsaSignature, + UnverifiedRevokeAssociation, UnverifiedSignature, UnverifiedSmartContractWalletSignature, }, verified_signature::VerifiedSignature, MemberIdentifier, SignatureError, @@ -168,13 +168,13 @@ impl TryFrom for UnverifiedSignature { SignatureKindProto::InstallationKey(sig) => UnverifiedSignature::InstallationKey( UnverifiedInstallationKeySignature::new(sig.bytes, sig.public_key), ), - SignatureKindProto::Erc6492(sig) => { - UnverifiedSignature::Erc6492(UnverifiedErc6492Signature::new( + SignatureKindProto::Erc6492(sig) => UnverifiedSignature::SmartContractWallet( + UnverifiedSmartContractWalletSignature::new( sig.signature, sig.account_id.try_into()?, sig.block_number, - )) - } + ), + ), }; Ok(unverified_sig) @@ -252,7 +252,7 @@ impl From for IdentityActionProto { impl From for SignatureWrapperProto { fn from(value: UnverifiedSignature) -> Self { let signature = match value { - UnverifiedSignature::Erc6492(sig) => { + UnverifiedSignature::SmartContractWallet(sig) => { SignatureKindProto::Erc6492(SmartContractWalletSignatureProto { account_id: sig.account_id.into(), block_number: sig.block_number, @@ -565,15 +565,42 @@ mod tests { let identity_update = UnverifiedIdentityUpdate::new( inbox_id, client_timestamp_ns, - vec![UnverifiedAction::CreateInbox(UnverifiedCreateInbox { - initial_address_signature: UnverifiedSignature::RecoverableEcdsa( - UnverifiedRecoverableEcdsaSignature::new(signature_bytes), - ), - unsigned_action: UnsignedCreateInbox { - nonce, - account_address, - }, - })], + vec![ + UnverifiedAction::CreateInbox(UnverifiedCreateInbox { + initial_address_signature: UnverifiedSignature::RecoverableEcdsa( + UnverifiedRecoverableEcdsaSignature::new(signature_bytes), + ), + unsigned_action: UnsignedCreateInbox { + nonce, + account_address, + }, + }), + UnverifiedAction::AddAssociation(UnverifiedAddAssociation { + new_member_signature: UnverifiedSignature::new_recoverable_ecdsa(vec![1, 2, 3]), + existing_member_signature: UnverifiedSignature::new_recoverable_ecdsa(vec![ + 4, 5, 6, + ]), + unsigned_action: UnsignedAddAssociation { + new_member_identifier: rand_string().into(), + }, + }), + UnverifiedAction::ChangeRecoveryAddress(UnverifiedChangeRecoveryAddress { + recovery_address_signature: UnverifiedSignature::new_recoverable_ecdsa(vec![ + 7, 8, 9, + ]), + unsigned_action: UnsignedChangeRecoveryAddress { + new_recovery_address: rand_string(), + }, + }), + UnverifiedAction::RevokeAssociation(UnverifiedRevokeAssociation { + recovery_address_signature: UnverifiedSignature::new_recoverable_ecdsa(vec![ + 10, 11, 12, + ]), + unsigned_action: UnsignedRevokeAssociation { + revoked_member: rand_string().into(), + }, + }), + ], ); let serialized_update = IdentityUpdateProto::from(identity_update.clone()); @@ -582,13 +609,15 @@ mod tests { serialized_update.client_timestamp_ns, identity_update.client_timestamp_ns ); - assert_eq!(serialized_update.actions.len(), 1); + assert_eq!(serialized_update.actions.len(), 4); let deserialized_update: UnverifiedIdentityUpdate = serialized_update .clone() .try_into() .expect("deserialization error"); + assert_eq!(deserialized_update, identity_update); + let reserialized = IdentityUpdateProto::from(deserialized_update); assert_eq!(serialized_update, reserialized); diff --git a/xmtp_id/src/associations/signature.rs b/xmtp_id/src/associations/signature.rs index b69ec78df..ef49e9ef7 100644 --- a/xmtp_id/src/associations/signature.rs +++ b/xmtp_id/src/associations/signature.rs @@ -62,7 +62,7 @@ impl std::fmt::Display for SignatureKind { } } // CAIP-10[https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct AccountId { pub(crate) chain_id: String, pub(crate) account_address: String, diff --git a/xmtp_id/src/associations/test_utils.rs b/xmtp_id/src/associations/test_utils.rs index 5e5f8c6f7..6f7b624a6 100644 --- a/xmtp_id/src/associations/test_utils.rs +++ b/xmtp_id/src/associations/test_utils.rs @@ -1,10 +1,7 @@ use super::{ builder::SignatureRequest, unsigned_actions::UnsignedCreateInbox, - unverified::{ - UnverifiedAction, UnverifiedCreateInbox, UnverifiedInstallationKeySignature, - UnverifiedRecoverableEcdsaSignature, UnverifiedSignature, - }, + unverified::{UnverifiedAction, UnverifiedCreateInbox, UnverifiedSignature}, AccountId, }; use crate::{ @@ -66,9 +63,9 @@ impl SmartContractSignatureVerifier for MockSmartContractSignatureVerifier { pub async fn add_wallet_signature(signature_request: &mut SignatureRequest, wallet: &LocalWallet) { let signature_text = signature_request.signature_text(); let sig = wallet.sign_message(signature_text).await.unwrap().to_vec(); - let unverified_sig = - UnverifiedSignature::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature::new(sig)); + let unverified_sig = UnverifiedSignature::new_recoverable_ecdsa(sig); let scw_verifier = MockSmartContractSignatureVerifier::new(false); + signature_request .add_signature(unverified_sig, &scw_verifier) .await @@ -87,11 +84,10 @@ pub async fn add_installation_key_signature( let sig = installation_key .sign_prehashed(prehashed, Some(INSTALLATION_KEY_SIGNATURE_CONTEXT)) .unwrap(); - let unverified_sig = - UnverifiedSignature::InstallationKey(UnverifiedInstallationKeySignature::new( - sig.to_bytes().to_vec(), - verifying_key.as_bytes().to_vec(), - )); + let unverified_sig = UnverifiedSignature::new_installation_key( + sig.to_bytes().to_vec(), + verifying_key.as_bytes().to_vec(), + ); signature_request .add_signature( @@ -102,12 +98,6 @@ pub async fn add_installation_key_signature( .expect("should succeed"); } -impl UnverifiedSignature { - pub fn new_test_recoverable_ecdsa(signature: Vec) -> Self { - Self::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature::new(signature)) - } -} - impl UnverifiedAction { pub fn new_test_create_inbox(account_address: &str, nonce: &u64) -> Self { Self::CreateInbox(UnverifiedCreateInbox::new( @@ -115,7 +105,7 @@ impl UnverifiedAction { account_address: account_address.to_owned(), nonce: *nonce, }, - UnverifiedSignature::new_test_recoverable_ecdsa(vec![1, 2, 3]), + UnverifiedSignature::new_recoverable_ecdsa(vec![1, 2, 3]), )) } } diff --git a/xmtp_id/src/associations/unsigned_actions.rs b/xmtp_id/src/associations/unsigned_actions.rs index 4c89e2d31..b0c21f9bf 100644 --- a/xmtp_id/src/associations/unsigned_actions.rs +++ b/xmtp_id/src/associations/unsigned_actions.rs @@ -11,7 +11,7 @@ pub trait SignatureTextCreator { fn signature_text(&self) -> String; } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct UnsignedCreateInbox { pub nonce: u64, pub account_address: String, @@ -23,7 +23,7 @@ impl SignatureTextCreator for UnsignedCreateInbox { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct UnsignedAddAssociation { pub new_member_identifier: MemberIdentifier, } @@ -40,7 +40,7 @@ impl SignatureTextCreator for UnsignedAddAssociation { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct UnsignedRevokeAssociation { pub revoked_member: MemberIdentifier, } @@ -57,7 +57,7 @@ impl SignatureTextCreator for UnsignedRevokeAssociation { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct UnsignedChangeRecoveryAddress { pub new_recovery_address: String, } @@ -73,7 +73,7 @@ impl SignatureTextCreator for UnsignedChangeRecoveryAddress { } #[allow(dead_code)] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum UnsignedAction { CreateInbox(UnsignedCreateInbox), AddAssociation(UnsignedAddAssociation), @@ -92,7 +92,7 @@ impl SignatureTextCreator for UnsignedAction { } } -#[derive(Clone)] +#[derive(Clone, Debug, PartialEq)] pub struct UnsignedIdentityUpdate { pub inbox_id: String, pub client_timestamp_ns: u64, diff --git a/xmtp_id/src/associations/unverified.rs b/xmtp_id/src/associations/unverified.rs index 4ab8f4cca..b9120758c 100644 --- a/xmtp_id/src/associations/unverified.rs +++ b/xmtp_id/src/associations/unverified.rs @@ -14,7 +14,7 @@ use super::{ use futures::future::try_join_all; use xmtp_proto::xmtp::message_contents::SignedPublicKey as LegacySignedPublicKeyProto; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedIdentityUpdate { pub inbox_id: String, pub client_timestamp_ns: u64, @@ -73,7 +73,7 @@ impl UnverifiedIdentityUpdate { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum UnverifiedAction { CreateInbox(UnverifiedCreateInbox), AddAssociation(UnverifiedAddAssociation), @@ -164,7 +164,7 @@ impl UnverifiedAction { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedCreateInbox { pub(crate) unsigned_action: UnsignedCreateInbox, pub(crate) initial_address_signature: UnverifiedSignature, @@ -182,7 +182,7 @@ impl UnverifiedCreateInbox { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedAddAssociation { pub(crate) unsigned_action: UnsignedAddAssociation, pub(crate) new_member_signature: UnverifiedSignature, @@ -202,7 +202,7 @@ impl UnverifiedAddAssociation { } } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedRevokeAssociation { pub(crate) recovery_address_signature: UnverifiedSignature, pub(crate) unsigned_action: UnsignedRevokeAssociation, @@ -220,7 +220,7 @@ impl UnverifiedRevokeAssociation { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedChangeRecoveryAddress { pub(crate) recovery_address_signature: UnverifiedSignature, pub(crate) unsigned_action: UnsignedChangeRecoveryAddress, @@ -238,11 +238,11 @@ impl UnverifiedChangeRecoveryAddress { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum UnverifiedSignature { InstallationKey(UnverifiedInstallationKeySignature), RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature), - Erc6492(UnverifiedErc6492Signature), + SmartContractWallet(UnverifiedSmartContractWalletSignature), LegacyDelegated(UnverifiedLegacyDelegatedSignature), } @@ -261,7 +261,7 @@ impl UnverifiedSignature { UnverifiedSignature::RecoverableEcdsa(sig) => { VerifiedSignature::from_recoverable_ecdsa(signature_text, &sig.signature_bytes) } - UnverifiedSignature::Erc6492(sig) => { + UnverifiedSignature::SmartContractWallet(sig) => { VerifiedSignature::from_smart_contract_wallet( signature_text, scw_verifier, @@ -278,9 +278,42 @@ impl UnverifiedSignature { ), } } + + pub fn new_recoverable_ecdsa(signature: Vec) -> Self { + Self::RecoverableEcdsa(UnverifiedRecoverableEcdsaSignature::new(signature)) + } + + pub fn new_installation_key(signature: Vec, verifying_key: Vec) -> Self { + Self::InstallationKey(UnverifiedInstallationKeySignature::new( + signature, + verifying_key, + )) + } + + pub fn new_smart_contract_wallet( + signature: Vec, + account_id: AccountId, + block_number: u64, + ) -> Self { + Self::SmartContractWallet(UnverifiedSmartContractWalletSignature::new( + signature, + account_id, + block_number, + )) + } + + pub fn new_legacy_delegated( + signature: Vec, + signed_public_key_proto: LegacySignedPublicKeyProto, + ) -> Self { + Self::LegacyDelegated(UnverifiedLegacyDelegatedSignature::new( + UnverifiedRecoverableEcdsaSignature::new(signature), + signed_public_key_proto, + )) + } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedInstallationKeySignature { pub(crate) signature_bytes: Vec, pub(crate) verifying_key: Vec, @@ -295,7 +328,7 @@ impl UnverifiedInstallationKeySignature { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedRecoverableEcdsaSignature { pub(crate) signature_bytes: Vec, } @@ -306,14 +339,14 @@ impl UnverifiedRecoverableEcdsaSignature { } } -#[derive(Debug, Clone)] -pub struct UnverifiedErc6492Signature { +#[derive(Debug, Clone, PartialEq)] +pub struct UnverifiedSmartContractWalletSignature { pub(crate) signature_bytes: Vec, pub(crate) account_id: AccountId, pub(crate) block_number: u64, } -impl UnverifiedErc6492Signature { +impl UnverifiedSmartContractWalletSignature { pub fn new(signature_bytes: Vec, account_id: AccountId, block_number: u64) -> Self { Self { signature_bytes, @@ -323,7 +356,7 @@ impl UnverifiedErc6492Signature { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct UnverifiedLegacyDelegatedSignature { pub(crate) legacy_key_signature: UnverifiedRecoverableEcdsaSignature, pub(crate) signed_public_key_proto: LegacySignedPublicKeyProto,