diff --git a/Cargo.toml b/Cargo.toml index e6a32d5..a2a6160 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,3 +34,6 @@ log = "0.4.20" # [profile.dev] # debug = 0 + +[patch.'https://github.com/reown-com/erc6492.git'] +erc6492 = { path = "../erc6492-rs" } diff --git a/crates/ffi/src/account_client.rs b/crates/ffi/src/account_client.rs index fd28956..2690853 100644 --- a/crates/ffi/src/account_client.rs +++ b/crates/ffi/src/account_client.rs @@ -162,7 +162,12 @@ impl FFIAccountClient { }); } - Ok(self.account_client.do_sign_message(signatures2).await.to_string()) + Ok(self + .account_client + .do_sign_message(signatures2) + .await + .map_err(|e| FFIError::Unknown(e.to_string()))? + .to_string()) } pub async fn send_transactions( diff --git a/crates/yttrium/Cargo.toml b/crates/yttrium/Cargo.toml index 3bc69e5..8a11895 100644 --- a/crates/yttrium/Cargo.toml +++ b/crates/yttrium/Cargo.toml @@ -20,6 +20,7 @@ alloy = { version = "0.3.6", features = [ "signer-mnemonic", "eip712", ] } +erc6492 = { git = "https://github.com/reown-com/erc6492.git", branch = "feat/create-6492" } # foundry-block-explorers = "0.2.3" getrandom = { version = "0.2", features = ["js"] } @@ -48,7 +49,6 @@ reqwest.workspace = true [dev-dependencies] # mocking wiremock = "0.6.0" -erc6492 = { git = "https://github.com/reown-com/erc6492.git", branch = "feat/verify-message-hash" } # Networking reqwest.workspace = true diff --git a/crates/yttrium/src/account_client.rs b/crates/yttrium/src/account_client.rs index aad839a..51b271a 100644 --- a/crates/yttrium/src/account_client.rs +++ b/crates/yttrium/src/account_client.rs @@ -5,7 +5,9 @@ use crate::bundler::{ use crate::config::Config; use crate::private_key_service::PrivateKeyService; use crate::sign_service::SignService; -use crate::smart_accounts::safe::{prepare_sign, sign, PreparedSignature}; +use crate::smart_accounts::safe::{ + prepare_sign, sign, Owners, PreparedSignature, +}; use crate::transaction::send::safe_test::{ self, DoSendTransactionParams, OwnerSignature, PreparedSendTransaction, }; @@ -157,7 +159,7 @@ impl AccountClient { pub async fn do_sign_message( &self, signatures: Vec, - ) -> Bytes { + ) -> eyre::Result { if !self.safe { unimplemented!( "sign_message is not supported for non-safe accounts" @@ -170,12 +172,21 @@ impl AccountClient { self.config.endpoints.rpc.base_url.parse().unwrap(), ); - sign( - self.owner.parse::
().unwrap().into(), + Ok(sign( + Owners { + owners: vec![self.owner.parse::
().unwrap()], + threshold: 1, + }, + self.get_address() + .await + .unwrap() + .parse::
() + .unwrap() + .into(), signatures, &provider, ) - .await + .await) } pub async fn send_transactions( diff --git a/crates/yttrium/src/smart_accounts/safe.rs b/crates/yttrium/src/smart_accounts/safe.rs index 91f4ffc..166e0ad 100644 --- a/crates/yttrium/src/smart_accounts/safe.rs +++ b/crates/yttrium/src/smart_accounts/safe.rs @@ -16,6 +16,7 @@ use alloy::{ sol, sol_types::{SolCall, SolValue}, }; +use erc6492::create::create_erc6492_signature; use serde::{Deserialize, Serialize}; sol! { @@ -303,7 +304,11 @@ pub fn prepare_sign( PreparedSignature { safe_message, domain } } +// TODO refactor to make account_address optional, if not provided it will +// determine it based on Owners TODO refactor to make owners optional, in the +// case where it already being deployed is assumed pub async fn sign( + owners: Owners, account_address: AccountAddress, signatures: Vec, provider: &P, @@ -319,20 +324,29 @@ where let signature = Bytes::from(signatures[0].signature.as_bytes()); + // Null validator address for regular Safe signature + let signature = (Address::ZERO, signature).abi_encode_packed().into(); + + println!("signature: {:?}", signature); + let signature = if provider .get_code_at(account_address.into()) .await .unwrap() // TODO handle error .is_empty() { - // TODO check if deployed, if so do ERC-6492 - signature + create_erc6492_signature( + SAFE_PROXY_FACTORY_ADDRESS, + factory_data(owners).abi_encode().into(), + signature, + ) } else { signature }; - // Null validator address for regular Safe signature - (Address::ZERO, signature).abi_encode_packed().into() + println!("signature (w/ 6492): {:?}", signature); + + signature } #[cfg(test)] diff --git a/crates/yttrium/src/transaction/send/safe_test.rs b/crates/yttrium/src/transaction/send/safe_test.rs index 49cac8e..aa6588c 100644 --- a/crates/yttrium/src/transaction/send/safe_test.rs +++ b/crates/yttrium/src/transaction/send/safe_test.rs @@ -488,7 +488,9 @@ mod tests { providers::{ext::AnvilApi, PendingTransactionConfig, ProviderBuilder}, rpc::types::TransactionRequest, sol, + sol_types::SolValue, }; + use erc6492::create::ERC6492_MAGIC_BYTES; async fn use_faucet( provider: ReqwestProvider, @@ -831,12 +833,10 @@ mod tests { let owner = LocalSigner::random(); let owner_address = owner.address(); + let owners = Owners { owners: vec![owner.address()], threshold: 1 }; - let sender_address = get_account_address( - provider.clone(), - Owners { owners: vec![owner.address()], threshold: 1 }, - ) - .await; + let sender_address = + get_account_address(provider.clone(), owners.clone()).await; let receipt = send_transactions( vec![], @@ -865,6 +865,7 @@ mod tests { owner.sign_typed_data_sync(&safe_message, &domain).unwrap(); let signature = sign( + owners, sender_address, vec![OwnerSignature { owner: owner_address, signature }], &provider, @@ -897,7 +898,7 @@ mod tests { } #[tokio::test] - #[ignore = "not implemented yet"] + // #[ignore = "not implemented yet"] async fn test_sign_message_not_deployed() { let config = Config::local(); let provider = ReqwestProvider::::new_http( @@ -906,12 +907,10 @@ mod tests { let owner = LocalSigner::random(); let owner_address = owner.address(); + let owners = Owners { owners: vec![owner.address()], threshold: 1 }; - let sender_address = get_account_address( - provider.clone(), - Owners { owners: vec![owner.address()], threshold: 1 }, - ) - .await; + let sender_address = + get_account_address(provider.clone(), owners.clone()).await; assert!(provider .get_code_at(sender_address.into()) @@ -930,6 +929,7 @@ mod tests { owner.sign_typed_data_sync(&safe_message, &domain).unwrap(); let signature = sign( + owners, sender_address, vec![OwnerSignature { owner: owner_address, signature }], &provider, @@ -942,6 +942,45 @@ mod tests { .unwrap() .is_empty()); + let working_signature = alloy::primitives::bytes!("0000000000000000000000004e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001241688f0b9000000000000000000000000ebe001b3d534b9b6e2500fb78e67a1a137f561ce0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000007a6733696a793000000000000000000000000000000000000000000000000000000000000000000000844fff40e16f8df5c33b2c7d965da59c4388f834ccb5d47bd34540071e8f1d9dc5f01562e8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413166c6ce0ad1c80ff9451f750940773f745179462eed1c6be7f49fc3e213f59b2ff5dba38c2ca56b7ddef619a782837e7faf2a5aa50f1b0393444efd90a982eb20000000000000000000000000000000000000000000000000000000000000006492649264926492649264926492649264926492649264926492649264926492"); + + let sig = &working_signature[..working_signature.len() - 32]; + println!("sig working : {}", hex::encode(sig)); + let decoded: (Address, Bytes, Bytes) = + alloy::sol_types::SolValue::abi_decode_params(sig, true).unwrap(); + println!("decoded working: {:?}", decoded); + let working_signature: Bytes = ( + ( + decoded.0, + decoded.1, + (Address::ZERO, decoded.2).abi_encode_packed(), + ) + .abi_encode_para(), + ERC6492_MAGIC_BYTES, + ) + .abi_encode_packed() + .into(); + + assert!(erc6492::verify_signature( + working_signature.clone(), + alloy::primitives::address!( + "b9c5de50e15d52764eA43c858eD9F57C964960Cd" + ), + eip191_hash_message("Hello AppKit!"), + &ReqwestProvider::::new_http( + "https://rpc.sepolia.org".parse().unwrap(), + ) + ) + .await + .unwrap() + .is_valid()); + + // let sig = &signature[..signature.len() - 32]; + // println!("sig not working: {}", hex::encode(sig)); + // let decoded: (Address, Bytes, Bytes) = + // alloy::sol_types::SolValue::abi_decode_params(sig, true).unwrap(); + // println!("decoded not working: {:?}", decoded); + assert!(erc6492::verify_signature( signature, sender_address.into(),