diff --git a/processor/ethereum/contracts/src/lib.rs b/processor/ethereum/contracts/src/lib.rs index d0a5c076..9087eaed 100644 --- a/processor/ethereum/contracts/src/lib.rs +++ b/processor/ethereum/contracts/src/lib.rs @@ -10,7 +10,7 @@ pub mod erc20 { pub use super::abigen::erc20::IERC20::*; } pub mod router { - pub const BYTECODE: &str = - include_str!(concat!(env!("OUT_DIR"), "/serai-processor-ethereum-contracts/Router.bin")); + pub const BYTECODE: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/serai-processor-ethereum-contracts/Router.bin")); pub use super::abigen::router::Router::*; } diff --git a/processor/ethereum/erc20/src/lib.rs b/processor/ethereum/erc20/src/lib.rs index 560ea86c..51f68d0e 100644 --- a/processor/ethereum/erc20/src/lib.rs +++ b/processor/ethereum/erc20/src/lib.rs @@ -22,7 +22,8 @@ use alloy_provider::{Provider, RootProvider}; mod abi { alloy_sol_macro::sol!("contracts/IERC20.sol"); } -use abi::IERC20::{IERC20Calls, Transfer, transferCall, transferFromCall}; +use abi::IERC20::{IERC20Calls, transferCall, transferFromCall}; +pub use abi::IERC20::Transfer; /// A top-level ERC20 transfer #[derive(Clone, Debug)] @@ -50,12 +51,12 @@ impl Erc20 { pub async fn top_level_transfers( &self, block: u64, - to: [u8; 20], + to: Address, ) -> Result, RpcError> { let filter = Filter::new().from_block(block).to_block(block).address(self.1); let filter = filter.event_signature(Transfer::SIGNATURE_HASH); let mut to_topic = [0; 32]; - to_topic[12 ..].copy_from_slice(&to); + to_topic[12 ..].copy_from_slice(to.as_ref()); let filter = filter.topic2(B256::from(to_topic)); let logs = self.0.get_logs(&filter).await?; diff --git a/processor/ethereum/ethereum-serai/src/crypto.rs b/processor/ethereum/ethereum-serai/src/crypto.rs index fc51ae6b..3b9dc58a 100644 --- a/processor/ethereum/ethereum-serai/src/crypto.rs +++ b/processor/ethereum/ethereum-serai/src/crypto.rs @@ -18,48 +18,6 @@ pub use ethereum_schnorr_contract::*; use alloy_core::primitives::{Parity, Signature as AlloySignature, Address}; use alloy_consensus::{SignableTransaction, Signed, TxLegacy}; -pub(crate) fn keccak256(data: &[u8]) -> [u8; 32] { - alloy_core::primitives::keccak256(data).into() -} - -pub(crate) fn hash_to_scalar(data: &[u8]) -> Scalar { - >::reduce_bytes(&keccak256(data).into()) -} - -pub(crate) fn address(point: &ProjectivePoint) -> [u8; 20] { - let encoded_point = point.to_encoded_point(false); - **Address::from_raw_public_key(&encoded_point.as_ref()[1 .. 65]) -} - -/// Deterministically sign a transaction. -/// -/// This function panics if passed a transaction with a non-None chain ID. -pub fn deterministically_sign(tx: &TxLegacy) -> Signed { - assert!( - tx.chain_id.is_none(), - "chain ID was Some when deterministically signing a TX (causing a non-deterministic signer)" - ); - - let sig_hash = tx.signature_hash().0; - let mut r = hash_to_scalar(&[sig_hash.as_slice(), b"r"].concat()); - let mut s = hash_to_scalar(&[sig_hash.as_slice(), b"s"].concat()); - loop { - let r_bytes: [u8; 32] = r.to_repr().into(); - let s_bytes: [u8; 32] = s.to_repr().into(); - let v = Parity::NonEip155(false); - let signature = - AlloySignature::from_scalars_and_parity(r_bytes.into(), s_bytes.into(), v).unwrap(); - let tx = tx.clone().into_signed(signature); - if tx.recover_signer().is_ok() { - return tx; - } - - // Re-hash until valid - r = hash_to_scalar(r_bytes.as_ref()); - s = hash_to_scalar(s_bytes.as_ref()); - } -} - /// The HRAm to use for the Schnorr Solidity library. /// /// This will panic if the public key being signed for is not representable within the Schnorr diff --git a/processor/ethereum/ethereum-serai/src/deployer.rs b/processor/ethereum/ethereum-serai/src/deployer.rs deleted file mode 100644 index 88f4a5fb..00000000 --- a/processor/ethereum/ethereum-serai/src/deployer.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::sync::Arc; - -use alloy_core::primitives::{hex::FromHex, Address, B256, U256, Bytes, TxKind}; -use alloy_consensus::{Signed, TxLegacy}; - -use alloy_sol_types::{SolCall, SolEvent}; - -use alloy_rpc_types_eth::{BlockNumberOrTag, Filter}; -use alloy_simple_request_transport::SimpleRequest; -use alloy_provider::{Provider, RootProvider}; - -use crate::{ - Error, - crypto::{self, keccak256, PublicKey}, - router::Router, -}; -pub use crate::abi::deployer as abi; - -/// The Deployer contract for the Router contract. -/// -/// This Deployer has a deterministic address, letting it be immediately identified on any -/// compatible chain. It then supports retrieving the Router contract's address (which isn't -/// deterministic) using a single log query. -#[derive(Clone, Debug)] -pub struct Deployer; -impl Deployer { - /// Obtain the transaction to deploy this contract, already signed. - /// - /// The account this transaction is sent from (which is populated in `from`) must be sufficiently - /// funded for this transaction to be submitted. This account has no known private key to anyone, - /// so ETH sent can be neither misappropriated nor returned. - pub fn deployment_tx() -> Signed { - let bytecode = contracts::deployer::BYTECODE; - let bytecode = - Bytes::from_hex(bytecode).expect("compiled-in Deployer bytecode wasn't valid hex"); - - let tx = TxLegacy { - chain_id: None, - nonce: 0, - gas_price: 100_000_000_000u128, - // TODO: Use a more accurate gas limit - gas_limit: 1_000_000u128, - to: TxKind::Create, - value: U256::ZERO, - input: bytecode, - }; - - crypto::deterministically_sign(&tx) - } - - /// Obtain the deterministic address for this contract. - pub fn address() -> [u8; 20] { - let deployer_deployer = - Self::deployment_tx().recover_signer().expect("deployment_tx didn't have a valid signature"); - **Address::create(&deployer_deployer, 0) - } - - /// Construct a new view of the `Deployer`. - pub async fn new(provider: Arc>) -> Result, Error> { - let address = Self::address(); - let code = provider.get_code_at(address.into()).await.map_err(|_| Error::ConnectionError)?; - // Contract has yet to be deployed - if code.is_empty() { - return Ok(None); - } - Ok(Some(Self)) - } - - /// Yield the `ContractCall` necessary to deploy the Router. - pub fn deploy_router(&self, key: &PublicKey) -> TxLegacy { - TxLegacy { - to: TxKind::Call(Self::address().into()), - input: abi::deployCall::new((Router::init_code(key).into(),)).abi_encode().into(), - gas_limit: 1_000_000, - ..Default::default() - } - } - - /// Find the first Router deployed with the specified key as its first key. - /// - /// This is the Router Serai will use, and is the only way to construct a `Router`. - pub async fn find_router( - &self, - provider: Arc>, - key: &PublicKey, - ) -> Result, Error> { - let init_code = Router::init_code(key); - let init_code_hash = keccak256(&init_code); - - #[cfg(not(test))] - let to_block = BlockNumberOrTag::Finalized; - #[cfg(test)] - let to_block = BlockNumberOrTag::Latest; - - // Find the first log using this init code (where the init code is binding to the key) - // TODO: Make an abstraction for event filtering (de-duplicating common code) - let filter = - Filter::new().from_block(0).to_block(to_block).address(Address::from(Self::address())); - let filter = filter.event_signature(abi::Deployment::SIGNATURE_HASH); - let filter = filter.topic1(B256::from(init_code_hash)); - let logs = provider.get_logs(&filter).await.map_err(|_| Error::ConnectionError)?; - - let Some(first_log) = logs.first() else { return Ok(None) }; - let router = first_log - .log_decode::() - .map_err(|_| Error::ConnectionError)? - .inner - .data - .created; - - Ok(Some(Router::new(provider, router))) - } -}