From 9f366f202eca69c2cacd7ef90af1dd4f7f3685ad Mon Sep 17 00:00:00 2001 From: Dakota Brink <779390+codabrink@users.noreply.github.com> Date: Thu, 3 Oct 2024 17:05:44 -0400 Subject: [PATCH] Make scw block number optional for front-end (#1112) * optional block number for the front-end * a better path * lint * be more specific in trait * return error instead of todo * cleanup * lint --- bindings_ffi/src/lib.rs | 2 + bindings_ffi/src/mls.rs | 13 +++++- xmtp_id/src/associations/test_utils.rs | 6 ++- xmtp_id/src/associations/unverified.rs | 2 +- .../src/associations/verified_signature.rs | 6 +-- .../src/scw_verifier/chain_rpc_verifier.rs | 16 ++++--- xmtp_id/src/scw_verifier/mod.rs | 44 +++++++++++++++---- 7 files changed, 69 insertions(+), 20 deletions(-) diff --git a/bindings_ffi/src/lib.rs b/bindings_ffi/src/lib.rs index 2faef1ae2..60aa0f4c8 100755 --- a/bindings_ffi/src/lib.rs +++ b/bindings_ffi/src/lib.rs @@ -40,6 +40,8 @@ pub enum GenericError { SignatureRequestError(#[from] xmtp_id::associations::builder::SignatureRequestError), #[error(transparent)] Erc1271SignatureError(#[from] xmtp_id::associations::signature::SignatureError), + #[error(transparent)] + Verifier(#[from] xmtp_id::scw_verifier::VerifierError), } impl From for GenericError { diff --git a/bindings_ffi/src/mls.rs b/bindings_ffi/src/mls.rs index 8c0e46cff..e0dd1fd64 100644 --- a/bindings_ffi/src/mls.rs +++ b/bindings_ffi/src/mls.rs @@ -206,11 +206,22 @@ impl FfiSignatureRequest { signature_bytes: Vec, address: String, chain_id: u64, - block_number: u64, + block_number: Option, ) -> Result<(), GenericError> { let mut inner = self.inner.lock().await; let account_id = AccountId::new_evm(chain_id, address); + let block_number = match block_number { + Some(bn) => bn, + None => { + self.scw_verifier + .current_block_number(&chain_id.to_string()) + .await + .map_err(GenericError::Verifier)? + .0[0] + } + }; + let signature = UnverifiedSignature::new_smart_contract_wallet( signature_bytes, account_id, diff --git a/xmtp_id/src/associations/test_utils.rs b/xmtp_id/src/associations/test_utils.rs index 5ef4f28b3..9a64aa68b 100644 --- a/xmtp_id/src/associations/test_utils.rs +++ b/xmtp_id/src/associations/test_utils.rs @@ -12,7 +12,7 @@ use ed25519_dalek::SigningKey as Ed25519SigningKey; use ethers::{ core::types::BlockNumber, signers::{LocalWallet, Signer}, - types::Bytes, + types::{Bytes, U64}, }; use rand::{distributions::Alphanumeric, Rng}; use sha2::{Digest, Sha512}; @@ -59,6 +59,10 @@ impl SmartContractSignatureVerifier for MockSmartContractSignatureVerifier { ) -> Result { Ok(self.is_valid_signature) } + + async fn current_block_number(&self, _chain_id: &str) -> Result { + Ok(1.into()) + } } pub async fn add_wallet_signature(signature_request: &mut SignatureRequest, wallet: &LocalWallet) { diff --git a/xmtp_id/src/associations/unverified.rs b/xmtp_id/src/associations/unverified.rs index b9120758c..9ce787fb0 100644 --- a/xmtp_id/src/associations/unverified.rs +++ b/xmtp_id/src/associations/unverified.rs @@ -267,7 +267,7 @@ impl UnverifiedSignature { scw_verifier, &sig.signature_bytes, sig.account_id.clone(), - sig.block_number, + Some(sig.block_number), ) .await } diff --git a/xmtp_id/src/associations/verified_signature.rs b/xmtp_id/src/associations/verified_signature.rs index ad17051da..d33f034af 100644 --- a/xmtp_id/src/associations/verified_signature.rs +++ b/xmtp_id/src/associations/verified_signature.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use ed25519_dalek::{Signature as Ed25519Signature, VerifyingKey as Ed25519VerifyingKey}; -use ethers::types::{BlockNumber, Signature as EthersSignature, U64}; +use ethers::types::Signature as EthersSignature; use ethers::utils::hash_message; use ethers::{core::k256::ecdsa::VerifyingKey as EcdsaVerifyingKey, utils::public_key_to_address}; use sha2::{Digest, Sha512}; @@ -125,14 +125,14 @@ impl VerifiedSignature { signature_verifier: &dyn SmartContractSignatureVerifier, signature_bytes: &[u8], account_id: AccountId, - block_number: u64, + block_number: Option, ) -> Result { let is_valid = signature_verifier .is_valid_signature( account_id.clone(), hash_message(signature_text.as_ref()).into(), signature_bytes.to_vec().into(), - Some(BlockNumber::Number(U64::from(block_number))), + block_number.map(|n| n.into()), ) .await?; diff --git a/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs b/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs index e13afdf5f..440692d2d 100644 --- a/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs +++ b/xmtp_id/src/scw_verifier/chain_rpc_verifier.rs @@ -5,7 +5,7 @@ use ethers::abi::{Constructor, Param, ParamType, Token}; use ethers::contract::abigen; use ethers::providers::{Http, Middleware, Provider}; use ethers::types::transaction::eip2718::TypedTransaction; -use ethers::types::{Address, BlockNumber, Bytes, TransactionRequest}; +use ethers::types::{Address, BlockNumber, Bytes, TransactionRequest, U64}; use hex::{FromHex, FromHexError}; use std::sync::Arc; @@ -87,14 +87,20 @@ impl SmartContractSignatureVerifier for RpcSmartContractWalletVerifier { ]; let data = constructor.encode_input(code, tokens)?; let tx: TypedTransaction = TransactionRequest::new().data(data).into(); - let block_number = if let Some(number) = block_number { - number - } else { - BlockNumber::Number(self.provider.get_block_number().await?) + let block_number = match block_number { + Some(bn) => bn, + None => BlockNumber::Number(self.current_block_number(&signer.chain_id).await?), }; let res = self.provider.call(&tx, Some(block_number.into())).await?; Ok(res == Bytes::from_hex("0x01").expect("Hardcoded hex will not fail.")) } + + async fn current_block_number(&self, _chain_id: &str) -> Result { + self.provider + .get_block_number() + .await + .map_err(VerifierError::Provider) + } } #[cfg(test)] diff --git a/xmtp_id/src/scw_verifier/mod.rs b/xmtp_id/src/scw_verifier/mod.rs index f4f380c13..7d479f16b 100644 --- a/xmtp_id/src/scw_verifier/mod.rs +++ b/xmtp_id/src/scw_verifier/mod.rs @@ -5,8 +5,9 @@ use std::{collections::HashMap, fs, path::Path, str::FromStr}; use async_trait::async_trait; use dyn_clone::DynClone; use ethers::{ - providers::{Http, Provider}, - types::{BlockNumber, Bytes}, + contract::ContractError, + providers::{Http, Provider, ProviderError}, + types::{BlockNumber, Bytes, U64}, }; use thiserror::Error; use url::Url; @@ -33,6 +34,7 @@ pub enum VerifierError { #[async_trait] pub trait SmartContractSignatureVerifier: Send + Sync + DynClone + 'static { + async fn current_block_number(&self, chain_id: &str) -> Result; async fn is_valid_signature( &self, account_id: AccountId, @@ -57,6 +59,10 @@ impl SmartContractSignatureVerifier f .is_valid_signature(account_id, hash, signature, block_number) .await } + + async fn current_block_number(&self, chain_id: &str) -> Result { + (**self).current_block_number(chain_id).await + } } #[derive(Clone)] @@ -116,16 +122,36 @@ impl SmartContractSignatureVerifier for MultiSmartContractSignatureVerifier { account_id: AccountId, hash: [u8; 32], signature: Bytes, - _block_number: Option, + block_number: Option, ) -> Result { - let id: u64 = account_id.chain_id.parse().unwrap(); + let id: u64 = account_id.chain_id.parse().map_err(|e| { + VerifierError::Contract(ContractError::DecodingError( + ethers::core::abi::Error::ParseInt(e), + )) + })?; + if let Some(verifier) = self.verifiers.get(&id) { + return verifier + .is_valid_signature(account_id, hash, signature, block_number) + .await; + } + + Err(VerifierError::Provider(ProviderError::CustomError( + "Verifier not present".to_string(), + ))) + } + + async fn current_block_number(&self, chain_id: &str) -> Result { + let id: u64 = chain_id.parse().map_err(|e| { + VerifierError::Contract(ContractError::DecodingError( + ethers::core::abi::Error::ParseInt(e), + )) + })?; if let Some(verifier) = self.verifiers.get(&id) { - return Ok(verifier - .is_valid_signature(account_id, hash, signature, None) - .await - .unwrap()); + return verifier.current_block_number(chain_id).await; } - todo!() + Err(VerifierError::Provider(ProviderError::CustomError( + "Verifier not present".to_string(), + ))) } }