Skip to content

Commit

Permalink
fix: get it working
Browse files Browse the repository at this point in the history
  • Loading branch information
chris13524 committed Oct 25, 2024
1 parent 74c6618 commit c93caf9
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 112 deletions.
7 changes: 6 additions & 1 deletion crates/ffi/src/account_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion crates/yttrium/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ alloy = { version = "0.3.6", features = [
"eip712",
] }
alloy-provider = { version = "0.3.6", features = ["erc4337-api"] }
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"] }

Expand Down Expand Up @@ -54,7 +55,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
Expand Down
24 changes: 20 additions & 4 deletions crates/yttrium/src/account_client.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use crate::bundler::models::user_operation_receipt::UserOperationReceipt;
use crate::bundler::pimlico::paymaster::client::PaymasterClient;
use crate::bundler::{client::BundlerClient, config::BundlerConfig};
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,
};
Expand All @@ -14,7 +17,7 @@ use crate::transaction::{send::send_transactions, Transaction};
use alloy::network::Ethereum;
use alloy::primitives::{Address, Bytes, B256, U256, U64};
use alloy::providers::ReqwestProvider;
use alloy::signers::local::PrivateKeySigner;
use alloy::signers::local::{LocalSigner, PrivateKeySigner};
use std::sync::Arc;
use tokio::sync::Mutex;

Expand Down Expand Up @@ -156,7 +159,7 @@ impl AccountClient {
pub async fn do_sign_message(
&self,
signatures: Vec<OwnerSignature>,
) -> Bytes {
) -> eyre::Result<Bytes> {
if !self.safe {
unimplemented!(
"sign_message is not supported for non-safe accounts"
Expand All @@ -170,9 +173,22 @@ impl AccountClient {
);

sign(
self.owner.parse::<Address>().unwrap().into(),
Owners {
owners: vec![self.owner.parse::<Address>().unwrap()],
threshold: 1,
},
self.get_address()
.await
.unwrap()
.parse::<Address>()
.unwrap()
.into(),
signatures,
&provider,
LocalSigner::random(),
PaymasterClient::new(BundlerConfig::new(
self.config.endpoints.paymaster.base_url.parse().unwrap(),
)),
)
.await
}
Expand Down
30 changes: 16 additions & 14 deletions crates/yttrium/src/entry_point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,27 @@ pub const ENTRYPOINT_ADDRESS_V07: Address =
pub const ENTRYPOINT_V06_TYPE: &str = "v0.6";
pub const ENTRYPOINT_V07_TYPE: &str = "v0.7";

sol! (
struct PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
bytes32 accountGasLimits;
uint256 preVerificationGas;
bytes32 gasFees;
bytes paymasterAndData;
bytes signature;
}
);

sol! {
#[sol(rpc)]
contract EntryPoint {
struct PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
bytes32 accountGasLimits;
uint256 preVerificationGas;
bytes32 gasFees;
bytes paymasterAndData;
bytes signature;
}

function getSenderAddress(bytes calldata initCode);
function getNonce(address sender, uint192 key) returns (uint256 nonce);
function handleOps(
PackedUserOperation[] calldata ops,
address payable beneficiary
);
}
}

Expand Down
110 changes: 98 additions & 12 deletions crates/yttrium/src/smart_accounts/safe.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
use crate::bundler::pimlico::paymaster::client::PaymasterClient;
use crate::entry_point::EntryPoint::PackedUserOperation;
use crate::entry_point::{EntryPoint, ENTRYPOINT_ADDRESS_V07};
use crate::transaction::send::safe_test::{
encode_send_transactions, prepare_send_transactions_inner,
PreparedSendTransaction,
};
use crate::transaction::Transaction;
use crate::user_operation::hash::pack_v07::combine::combine_and_trim_first_16_bytes;
use crate::user_operation::hash::pack_v07::hashed_paymaster_and_data::get_data;
use crate::{
smart_accounts::account_address::AccountAddress,
transaction::send::safe_test::OwnerSignature,
};
use alloy::network::Network;
use alloy::primitives::B256;
use alloy::primitives::{B256, U128};
use alloy::providers::Provider;
use alloy::signers::k256::ecdsa::SigningKey;
use alloy::signers::local::LocalSigner;
use alloy::signers::SignerSync;
use alloy::transports::Transport;
use alloy::{
dyn_abi::{DynSolValue, Eip712Domain},
primitives::{
address, bytes, keccak256, Address, Bytes, FixedBytes, Uint, U256,
},
providers::ReqwestProvider,
sol,
sol_types::{SolCall, SolValue},
};
use erc6492::create::create_erc6492_signature;
use serde::{Deserialize, Serialize};

sol! {
Expand Down Expand Up @@ -196,12 +208,17 @@ pub fn factory_data(
}
}

pub async fn get_account_address(
provider: ReqwestProvider,
pub async fn get_account_address<P, T, N>(
provider: P,
owners: Owners,
) -> AccountAddress {
) -> AccountAddress
where
T: Transport + Clone,
P: Provider<T, N>,
N: Network,
{
let creation_code =
SafeProxyFactory::new(SAFE_PROXY_FACTORY_ADDRESS, provider.clone())
SafeProxyFactory::new(SAFE_PROXY_FACTORY_ADDRESS, provider)
.proxyCreationCode()
.call()
.await
Expand Down Expand Up @@ -303,36 +320,105 @@ 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<P, T, N>(
owners: Owners,
account_address: AccountAddress,
signatures: Vec<OwnerSignature>,
provider: &P,
) -> Bytes
owner: LocalSigner<SigningKey>, // TODO remove
paymaster_client: PaymasterClient,
) -> eyre::Result<Bytes>
where
T: Transport + Clone,
P: Provider<T, N>,
N: Network,
{
if signatures.len() > 1 {
unimplemented!("multi-signature is not supported");
unimplemented!("multi-signature is not yet supported");
}

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();

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
let eip1559_est = provider.estimate_eip1559_fees(None).await?;
let PreparedSendTransaction {
safe_op,
domain,
hash: _,
do_send_transaction_params,
} = prepare_send_transactions_inner(
vec![],
owners,
Some(account_address),
None,
provider,
U128::from(eip1559_est.max_fee_per_gas).to(),
U128::from(eip1559_est.max_priority_fee_per_gas).to(),
paymaster_client,
)
.await?;

// TODO don't do the signing here, allow wallet to do it
let user_op_signature = vec![OwnerSignature {
owner: owner.address(),
signature: owner.sign_typed_data_sync(&safe_op, &domain).unwrap(),
}];

let user_op = encode_send_transactions(
user_op_signature,
do_send_transaction_params,
)
.await
.unwrap();

let factory_address = ENTRYPOINT_ADDRESS_V07;
let factory_data = EntryPoint::handleOpsCall {
ops: vec![PackedUserOperation {
paymasterAndData: get_data(&user_op),
sender: user_op.sender.into(),
nonce: user_op.nonce,
initCode: [
// TODO refactor to remove unwrap()
// This code double-checks for code deployed unnecessesarly
user_op.factory.unwrap().to_vec().into(),
user_op.factory_data.unwrap(),
]
.concat()
.into(),
callData: user_op.call_data,
accountGasLimits: combine_and_trim_first_16_bytes(
user_op.verification_gas_limit,
user_op.call_gas_limit,
),
preVerificationGas: user_op.pre_verification_gas,
gasFees: combine_and_trim_first_16_bytes(
user_op.max_priority_fee_per_gas,
user_op.max_fee_per_gas,
),
signature: user_op.signature,
}],
beneficiary: user_op.sender.into(),
}
.abi_encode()
.into();

create_erc6492_signature(factory_address, factory_data, signature)
} else {
signature
};

// Null validator address for regular Safe signature
(Address::ZERO, signature).abi_encode_packed().into()
Ok(signature)
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit c93caf9

Please sign in to comment.