Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion core/src/rpc_clients/bundler.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use alloy::consensus::{Receipt, ReceiptWithBloom};
use alloy::primitives::{Address, Bytes, U256};
use alloy::eips::eip7702::Authorization;
use alloy::primitives::{Address, Bytes, TxHash, U256};
use alloy::rpc::client::RpcClient;
use alloy::rpc::types::{Log, TransactionReceipt};
use alloy::transports::{IntoBoxTransport, TransportResult};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;

use crate::userop::VersionedUserOp;
Expand Down Expand Up @@ -114,4 +116,28 @@ impl BundlerClient {

Ok(result)
}

/// Execute an EIP-7702 transaction via the bundler
pub async fn tw_execute(
&self,
eoa_address: Address,
wrapped_calls: &Value,
signature: &str,
authorization: Option<&Authorization>,
) -> TransportResult<String> {
let params = serde_json::json!([eoa_address, wrapped_calls, signature, authorization]);

let response: String = self.inner.request("tw_execute", params).await?;

Ok(response)
}

/// Get transaction hash from bundler using transaction ID
pub async fn tw_get_transaction_hash(&self, transaction_id: &str) -> TransportResult<String> {
let params = serde_json::json!([transaction_id]);

let response: String = self.inner.request("tw_getTransactionHash", params).await?;

Ok(response)
}
}
77 changes: 73 additions & 4 deletions core/src/signer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use alloy::{
dyn_abi::TypedData,
eips::eip7702::SignedAuthorization,
hex::FromHex,
primitives::{Address, Bytes, ChainId},
primitives::{Address, Bytes, ChainId, U256},
rpc::types::Authorization,
};
use serde::{Deserialize, Serialize};
use serde_with::{DisplayFromStr, PickFirst, serde_as};
Expand Down Expand Up @@ -176,6 +178,16 @@ pub trait AccountSigner {
typed_data: &TypedData,
credentials: SigningCredential,
) -> impl std::future::Future<Output = Result<String, EngineError>> + Send;

/// Sign EIP-7702 authorization
fn sign_authorization(
&self,
options: Self::SigningOptions,
chain_id: u64,
address: Address,
nonce: alloy::primitives::U256,
credentials: SigningCredential,
) -> impl std::future::Future<Output = Result<SignedAuthorization, EngineError>> + Send;
}

/// EOA signer implementation
Expand All @@ -188,7 +200,10 @@ pub struct EoaSigner {
impl EoaSigner {
/// Create a new EOA signer
pub fn new(vault_client: VaultClient, iaw_client: IAWClient) -> Self {
Self { vault_client, iaw_client }
Self {
vault_client,
iaw_client,
}
}
}

Expand Down Expand Up @@ -221,7 +236,10 @@ impl AccountSigner for EoaSigner {

Ok(vault_result.signature)
}
SigningCredential::Iaw { auth_token, thirdweb_auth } => {
SigningCredential::Iaw {
auth_token,
thirdweb_auth,
} => {
// Convert MessageFormat to IAW MessageFormat
let iaw_format = match format {
MessageFormat::Text => thirdweb_core::iaw::MessageFormat::Text,
Expand Down Expand Up @@ -268,7 +286,10 @@ impl AccountSigner for EoaSigner {

Ok(vault_result.signature)
}
SigningCredential::Iaw { auth_token, thirdweb_auth } => {
SigningCredential::Iaw {
auth_token,
thirdweb_auth,
} => {
let iaw_result = self
.iaw_client
.sign_typed_data(
Expand All @@ -287,6 +308,54 @@ impl AccountSigner for EoaSigner {
}
}
}

async fn sign_authorization(
&self,
options: EoaSigningOptions,
chain_id: u64,
address: Address,
nonce: U256,
credentials: SigningCredential,
) -> Result<SignedAuthorization, EngineError> {
// Create the Authorization struct that both clients expect
let authorization = Authorization {
chain_id: U256::from(chain_id),
address,
nonce: nonce.to::<u64>(),
};

match credentials {
SigningCredential::Vault(auth_method) => {
let vault_result = self
.vault_client
.sign_authorization(auth_method, options.from, authorization)
.await
.map_err(|e| {
tracing::error!("Error signing authorization with EOA (Vault): {:?}", e);
e
})?;

// Return the signed authorization as Authorization
Ok(vault_result.signed_authorization)
}
SigningCredential::Iaw {
auth_token,
thirdweb_auth,
} => {
let iaw_result = self
.iaw_client
.sign_authorization(auth_token, thirdweb_auth, options.from, authorization)
.await
.map_err(|e| {
tracing::error!("Error signing authorization with EOA (IAW): {:?}", e);
EngineError::from(e)
})?;

// Return the signed authorization as Authorization
Ok(iaw_result.signed_authorization)
}
}
}
}

/// Parameters for signing a message (used in routes)
Expand Down
Loading