use alloc::vec;
use alloy_primitives::{keccak256, Address, Bytes, Log, B256, U256};
use alloy_sol_types::{sol, SolEvent, SolType};
use derive_more::{AsRef, From};
sol! {
#[derive(Default, Debug, PartialEq, Eq)]
struct MessageIdentifierAbi {
address origin;
uint256 blockNumber;
uint256 logIndex;
uint256 timestamp;
uint256 chainId;
}
#[derive(Default, Debug, PartialEq, Eq)]
event ExecutingMessageAbi(bytes32 msgHash, MessageIdentifierAbi id);
function executeMessage(
MessageIdentifierAbi calldata _id,
address _target,
bytes calldata _message
) external;
}
#[derive(Debug, Clone, From, AsRef, PartialEq, Eq)]
pub struct MessagePayload(Bytes);
impl From<Log> for MessagePayload {
fn from(log: Log) -> Self {
let mut data = vec![0u8; log.topics().len() * 32 + log.data.data.len()];
for (i, topic) in log.topics().iter().enumerate() {
data[i * 32..(i + 1) * 32].copy_from_slice(topic.as_ref());
}
data[(log.topics().len() * 32)..].copy_from_slice(log.data.data.as_ref());
Bytes::from(data).into()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct MessageIdentifier {
pub origin: Address,
pub block_number: u64,
pub log_index: u64,
pub timestamp: u64,
#[cfg_attr(feature = "serde", serde(rename = "chainID"))]
pub chain_id: u64,
}
impl MessageIdentifier {
pub fn abi_decode(data: &[u8], validate: bool) -> Result<Self, alloy_sol_types::Error> {
MessageIdentifierAbi::abi_decode(data, validate).map(|abi| abi.into())
}
}
impl From<MessageIdentifierAbi> for MessageIdentifier {
fn from(abi: MessageIdentifierAbi) -> Self {
Self {
origin: abi.origin,
block_number: abi.blockNumber.to(),
log_index: abi.logIndex.to(),
timestamp: abi.timestamp.to(),
chain_id: abi.chainId.to(),
}
}
}
impl From<MessageIdentifier> for MessageIdentifierAbi {
fn from(id: MessageIdentifier) -> Self {
Self {
origin: id.origin,
blockNumber: U256::from(id.block_number),
logIndex: U256::from(id.log_index),
timestamp: U256::from(id.timestamp),
chainId: U256::from(id.chain_id),
}
}
}
impl From<executeMessageCall> for ExecutingMessageAbi {
fn from(call: executeMessageCall) -> Self {
Self { id: call._id, msgHash: keccak256(call._message.as_ref()) }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct ExecutingMessage {
pub id: MessageIdentifier,
pub msg_hash: B256,
}
impl ExecutingMessage {
pub fn abi_decode(data: &[u8], validate: bool) -> Result<Self, alloy_sol_types::Error> {
ExecutingMessageAbi::abi_decode_data(data, validate).map(|abi| abi.into())
}
}
impl From<(B256, MessageIdentifierAbi)> for ExecutingMessage {
fn from((msg_hash, id): (B256, MessageIdentifierAbi)) -> Self {
Self { id: id.into(), msg_hash }
}
}
impl From<ExecutingMessageAbi> for ExecutingMessage {
fn from(event: ExecutingMessageAbi) -> Self {
Self { id: event.id.into(), msg_hash: event.msgHash }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_message_identifier_serde() {
let raw_id = r#"
{
"origin": "0x6887246668a3b87F54DeB3b94Ba47a6f63F32985",
"blockNumber": 123456,
"logIndex": 789,
"timestamp": 1618932000,
"chainID": 420
}
"#;
let id: MessageIdentifier = serde_json::from_str(raw_id).unwrap();
let expected = MessageIdentifier {
origin: "0x6887246668a3b87F54DeB3b94Ba47a6f63F32985".parse().unwrap(),
block_number: 123456,
log_index: 789,
timestamp: 1618932000,
chain_id: 420,
};
assert_eq!(id, expected);
}
#[test]
fn test_executing_message_serde() {
let raw_msg = r#"
{
"id": {
"origin": "0x6887246668a3b87F54DeB3b94Ba47a6f63F32985",
"blockNumber": 123456,
"logIndex": 789,
"timestamp": 1618932000,
"chainID": 420
},
"msgHash": "0xef8cc21bdbab8d2b60b054460768b1db67c8906b6a2bdf9bc287b3654326fc76"
}
"#;
let msg: ExecutingMessage = serde_json::from_str(raw_msg).unwrap();
let expected = ExecutingMessage {
id: MessageIdentifier {
origin: "0x6887246668a3b87F54DeB3b94Ba47a6f63F32985".parse().unwrap(),
block_number: 123456,
log_index: 789,
timestamp: 1618932000,
chain_id: 420,
},
msg_hash: "0xef8cc21bdbab8d2b60b054460768b1db67c8906b6a2bdf9bc287b3654326fc76"
.parse()
.unwrap(),
};
assert_eq!(msg, expected);
}
}