use df_hyperliquid_core::client::evm::abi::{AbiError, Token};
use crate::bridge::Contracts;
use crate::client::read::Fields;
use crate::client::{BadLog, Event, Log};
use crate::utils::Address;
use crate::{B256, U256};
pub const MESSAGE_DELIVERED: Event = Event::new(
"MessageDelivered(uint256,bytes32,address,uint8,address,bytes32,uint256,uint64)",
"uint256 indexed messageIndex, bytes32 indexed beforeInboxAcc, address inbox, uint8 kind, address sender, \
bytes32 messageDataHash, uint256 baseFeeL1, uint64 timestamp",
);
pub const INBOX_MESSAGE_DELIVERED: Event =
Event::new("InboxMessageDelivered(uint256,bytes)", "uint256 indexed messageNum, bytes data");
pub const INBOX_MESSAGE_DELIVERED_FROM_ORIGIN: Event =
Event::new("InboxMessageDeliveredFromOrigin(uint256)", "uint256 indexed messageNum");
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MessageKind {
L2Message,
L2FundedByL1,
SubmitRetryable,
Initialization,
EthDeposit,
BatchPostingReport,
Other(u8),
}
impl MessageKind {
#[must_use]
pub const fn from_byte(byte: u8) -> MessageKind {
match byte {
3 => MessageKind::L2Message,
7 => MessageKind::L2FundedByL1,
9 => MessageKind::SubmitRetryable,
11 => MessageKind::Initialization,
12 => MessageKind::EthDeposit,
13 => MessageKind::BatchPostingReport,
other => MessageKind::Other(other),
}
}
#[must_use]
pub const fn byte(self) -> u8 {
match self {
MessageKind::L2Message => 3,
MessageKind::L2FundedByL1 => 7,
MessageKind::SubmitRetryable => 9,
MessageKind::Initialization => 11,
MessageKind::EthDeposit => 12,
MessageKind::BatchPostingReport => 13,
MessageKind::Other(byte) => byte,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Message {
pub number: U256,
pub kind: MessageKind,
pub sender: Address,
pub base_fee_l1: U256,
pub timestamp: u64,
pub data_hash: B256,
pub data: Option<Vec<u8>>,
}
impl Message {
pub fn in_logs(logs: &[Log], contracts: &Contracts) -> Result<Vec<Message>, BadLog> {
let mut messages = Vec::new();
for log in logs.iter().filter(|log| log.address == contracts.bridge && MESSAGE_DELIVERED.matches(log)) {
let tokens = MESSAGE_DELIVERED.decode(log)?;
let abi = |error: AbiError| BadLog::Abi { event: "MessageDelivered", error };
let mut fields = Fields::of("MessageDelivered", &tokens);
let number = fields.uint().map_err(abi)?;
let _before_inbox_acc = fields.word().map_err(abi)?;
let inbox = fields.address().map_err(abi)?;
if inbox != contracts.inbox {
continue;
}
let kind = MessageKind::from_byte(fields.u8().map_err(abi)?);
let sender = fields.address().map_err(abi)?;
let data_hash = fields.word().map_err(abi)?;
let base_fee_l1 = fields.uint().map_err(abi)?;
let timestamp = fields.u64().map_err(abi)?;
let data = inbox_data(logs, contracts.inbox, number)?;
messages.push(Message { number, kind, sender, base_fee_l1, timestamp, data_hash, data });
}
Ok(messages)
}
}
fn inbox_data(logs: &[Log], inbox: Address, number: U256) -> Result<Option<Vec<u8>>, BadLog> {
for log in logs.iter().filter(|log| log.address == inbox && INBOX_MESSAGE_DELIVERED.matches(log)) {
let tokens = INBOX_MESSAGE_DELIVERED.decode(log)?;
if let [Token::Uint(logged), Token::Bytes(data)] = tokens.as_slice()
&& *logged == number
{
return Ok(Some(data.clone()));
}
}
Ok(None)
}