use crate::{
abi,
config,
};
use anyhow::anyhow;
use ethers_contract::EthEvent;
use ethers_core::{
abi::RawLog,
types::Log,
};
use fuel_core_types::{
blockchain::primitives::DaBlockHeight,
entities::{
RelayedTransaction,
relayer::{
message::{
Message,
MessageV1,
},
transaction::RelayedTransactionV1,
},
},
fuel_types::{
Address,
Nonce,
Word,
},
};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MessageLog {
pub sender: Address,
pub recipient: Address,
pub nonce: Nonce,
pub amount: Word,
pub data: Vec<u8>,
pub da_height: DaBlockHeight,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TransactionLog {
pub nonce: Nonce,
pub max_gas: u64,
pub serialized_transaction: Vec<u8>,
pub da_height: DaBlockHeight,
}
impl From<&MessageLog> for Message {
fn from(message: &MessageLog) -> Self {
MessageV1 {
sender: message.sender,
recipient: message.recipient,
nonce: message.nonce,
amount: message.amount,
data: message.data.clone(),
da_height: message.da_height,
}
.into()
}
}
impl From<TransactionLog> for RelayedTransaction {
fn from(transaction: TransactionLog) -> Self {
RelayedTransactionV1 {
nonce: transaction.nonce,
max_gas: transaction.max_gas,
serialized_transaction: transaction.serialized_transaction,
da_height: transaction.da_height,
}
.into()
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum EthEventLog {
Message(MessageLog),
Transaction(TransactionLog),
Ignored,
}
impl TryFrom<&Log> for EthEventLog {
type Error = anyhow::Error;
fn try_from(log: &Log) -> Result<Self, Self::Error> {
if log.topics.is_empty() {
return Err(anyhow!("Topic list is empty"))
}
let log = match log.topics[0] {
n if n == *config::ETH_LOG_MESSAGE => parse_message_to_event(log)?,
n if n == *config::ETH_FORCED_TX => parse_forced_tx_to_event(log)?,
_ => Self::Ignored,
};
Ok(log)
}
}
fn parse_message_to_event(log: &Log) -> anyhow::Result<EthEventLog> {
if log.topics.len() != 4 {
return Err(anyhow!("Malformed topics for Message"))
}
let raw_log = RawLog {
topics: log.topics.clone(),
data: log.data.to_vec(),
};
let message = abi::bridge::MessageSentFilter::decode_log(&raw_log)
.map_err(anyhow::Error::msg)?;
let amount = message.amount;
let data = message.data.to_vec();
let mut nonce = Nonce::zeroed();
message.nonce.to_big_endian(nonce.as_mut());
let recipient = Address::from(message.recipient);
let sender = Address::from(message.sender);
Ok(EthEventLog::Message(MessageLog {
amount,
data,
nonce,
sender,
recipient,
da_height: DaBlockHeight::from(
log.block_number
.ok_or(anyhow!("Log missing block height"))?
.as_u64(),
),
}))
}
fn parse_forced_tx_to_event(log: &Log) -> anyhow::Result<EthEventLog> {
if log.topics.len() != 2 {
return Err(anyhow!("Malformed topics for forced Transaction"))
}
let raw_log = RawLog {
topics: log.topics.clone(),
data: log.data.to_vec(),
};
let event = abi::bridge::TransactionFilter::decode_log(&raw_log)
.map_err(anyhow::Error::msg)?;
let mut nonce = Nonce::zeroed();
event.nonce.to_big_endian(nonce.as_mut());
let max_gas = event.max_gas;
let serialized_transaction = event.canonically_serialized_tx;
Ok(EthEventLog::Transaction(TransactionLog {
nonce,
max_gas,
serialized_transaction: serialized_transaction.to_vec(),
da_height: DaBlockHeight::from(
log.block_number
.ok_or(anyhow!("Log missing block height"))?
.as_u64(),
),
}))
}