Skip to main content

thruput_event/
lib.rs

1//! Event types for Thruput contracts: the [`Event`] trait that
2//! `#[derive(Event)]` implements, topics ([`Topic`], [`TopicSrc`]), and the
3//! [`EmittedEvent`] and [`TypedEvent`] views of an emitted event.
4//!
5//! Split out of `thruput-sdk` so host-side tooling can decode events without
6//! the SDK. Contracts use the re-exports in `thruput_sdk`.
7
8#![no_std]
9
10mod emitted_event;
11pub use emitted_event::{EmittedEvent, TOPIC_SIZE, TypedEvent};
12
13/// A topic is a fixed-length, opaque 32-byte array.
14pub type Topic = [u8; 32];
15
16/// An `impl Event` publishes each topic as a `TopicSrc` value.
17pub enum TopicSrc<'a> {
18    /// The topic is this owned value.
19    Owned(Topic),
20    /// The topic is available via a reference into the event
21    /// (or a `'static` reference).
22    Shared(&'a Topic),
23}
24
25// A `TopicSrc` can be converted to an owned `Topic`.
26impl<'a> From<TopicSrc<'a>> for Topic {
27    fn from(src: TopicSrc<'a>) -> Topic {
28        match src {
29            TopicSrc::Owned(topic) => topic,
30            TopicSrc::Shared(topic) => *topic,
31        }
32    }
33}
34
35/// Trait implemented by event types that can be emitted by contracts.
36///
37/// Provides the number of topics and their values. Topic 0 is
38/// conventionally the event-type discriminant (e.g. a hash of the
39/// event name). The XDR-serialized payload is everything *after*
40/// the topics in the on-chain representation.
41pub trait Event: xdrs::WriteXDR {
42    /// The decoded payload type. Uses a GAT so it can borrow from
43    /// the input bytes (e.g. `&'a [u8]` fields stay borrowed).
44    type Payload<'a>;
45
46    /// Number of topics this event type carries (0..=3), including the
47    /// signature topic when present.
48    ///
49    /// This is a static property of the type: every emission carries the
50    /// same count, and typed-event matching ([`TypedEvent::try_new`] /
51    /// [`TypedEvent::new`]) rejects a raw event whose `num_topics` differs —
52    /// so a matching topic 0 plus a coincidentally decodable payload cannot
53    /// pass for an `E` emitted with a different topic count.
54    fn num_topics() -> u32
55    where
56        Self: Sized;
57
58    /// The static topic-0 discriminant for this event type, if it has one.
59    ///
60    /// Topic 0 is conventionally the event-type discriminant (see the trait
61    /// docs). Return `Some(sig)` when topic 0 is a fixed per-type constant:
62    /// [`TypedEvent::new`](crate::TypedEvent::new) then rejects a raw event
63    /// whose topic 0 belongs to a different type before trusting the decoded
64    /// payload. Return `None` only when topic 0 is data-dependent (computed
65    /// from payload fields, or absent), which opts out of that check.
66    ///
67    /// This is deliberately not defaulted: a silent `None` would let an impl
68    /// with a fixed discriminant skip the check by omission. `#[derive(Event)]`
69    /// implements it as `Some(Self::SIGNATURE)`.
70    fn signature() -> Option<&'static Topic>
71    where
72        Self: Sized;
73
74    /// Retrieve the topic at the given index.
75    fn topic<'a>(&'a self, index: u32) -> Option<TopicSrc<'a>> {
76        let _ = index;
77        None
78    }
79
80    /// Decode the payload portion of a serialized event.
81    fn decode_payload<'a>(
82        bytes: &'a [u8],
83    ) -> Result<Self::Payload<'a>, xdrs::ReadError>;
84}