use crate::prelude::*;
use alloy_sol_types::{SolType, SolValue, abi::TokenSeq};
#[doc(hidden)]
#[cfg(target_arch = "wasm32")]
pub(crate) fn __emit_eth_event<TEvents>(event: TEvents) -> crate::errors::Result<()>
where
TEvents: crate::EthEvent,
{
with_optimized_encode(event, |payload| {
gstd::msg::send_bytes(crate::solidity::ETH_EVENT_ADDR, payload, 0)?;
Ok(())
})
}
#[cfg(target_arch = "wasm32")]
fn with_optimized_encode<T, E: EthEvent>(event: E, f: impl FnOnce(&[u8]) -> T) -> T {
use crate::utils::MaybeUninitBufferWriter;
let topics = event.topics();
let data = event.data();
let size = 1 + topics.len() * 32 + data.len();
gcore::stack_buffer::with_byte_buffer(size, |buffer| {
let mut buffer_writer = MaybeUninitBufferWriter::new(buffer);
buffer_writer.write(&[topics.len() as u8]);
for topic in topics {
buffer_writer.write(topic.as_slice());
}
buffer_writer.write(data.as_slice());
buffer_writer.with_buffer(f)
})
}
pub type EthEventExpo = (
&'static str, &'static str, [u8; 32], );
pub trait EthEvent {
const SIGNATURES: &'static [EthEventExpo];
fn topics(&self) -> Vec<alloy_primitives::B256>;
fn data(&self) -> Vec<u8>;
fn topic_hash<T: SolValue>(value: &T) -> alloy_primitives::B256 {
if <T::SolType as SolType>::DYNAMIC {
alloy_primitives::keccak256(SolValue::abi_encode(value))
} else {
let encoded = SolValue::abi_encode(value);
let mut topic = [0u8; 32];
topic[(32 - encoded.len())..].copy_from_slice(&encoded);
topic.into()
}
}
#[inline]
fn encode_sequence<T: SolValue>(value: &T) -> Vec<u8>
where
for<'a> <T::SolType as SolType>::Token<'a>: TokenSeq<'a>,
{
alloy_sol_types::SolValue::abi_encode_sequence(value)
}
}
#[cfg(test)]
mod tests {
#![allow(unused_assignments)]
use super::*;
use crate::{self as sails_rs, Encode, String, TypeInfo, event};
#[allow(unused)]
#[event]
#[derive(Encode, TypeInfo)]
enum Events {
MyEvent1 {
#[indexed]
sender: u128,
#[indexed]
amount: u128,
note: String,
},
MyEvent2(u128, u128, String),
MyEvent3,
}
#[test]
fn eth_event_sig() {
const SIG_TOPIC: [u8; 32] = [
148, 157, 201, 65, 144, 217, 114, 52, 67, 86, 206, 75, 197, 220, 61, 74, 138, 251, 52,
61, 243, 110, 252, 93, 62, 91, 109, 51, 209, 107, 68, 200,
];
let ev = Events::MyEvent1 {
sender: 1,
amount: 2,
note: "hello".to_string(),
};
assert_eq!(SIG_TOPIC.as_slice(), ev.topics()[0].as_slice());
}
#[test]
fn eth_event_topic_1() {
const SENDER_TOPIC: [u8; 32] = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1,
];
let ev = Events::MyEvent1 {
sender: 1,
amount: 2,
note: "hello".to_string(),
};
assert_eq!(SENDER_TOPIC.as_slice(), ev.topics()[1].as_slice());
}
#[test]
fn eth_event_data() {
const DATA: &[u8] = &[
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 5, 104, 101, 108, 108, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
let ev = Events::MyEvent1 {
sender: 1,
amount: 2,
note: "hello".to_string(),
};
assert_eq!(DATA, ev.data().as_slice());
}
}