thegraph_core/signed_message/
message.rs

1use alloy::{primitives::Signature, sol_types::SolStruct};
2
3/// EIP-712 signed message
4///
5/// This struct contains a message and the ECDSA signature of the message according to the
6/// EIP-712 standard.
7///
8/// For the message to be signed, it must either:
9/// - To be a _Solidity struct_, i.e., implement the `SolStruct` trait.
10/// - To be convertible into a _Solidity struct_, i.e., implement the `ToSolStruct` trait.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct SignedMessage<M> {
13    /// Message payload
14    pub message: M,
15    /// ECDSA message signature
16    pub signature: Signature,
17}
18
19impl<M> SignedMessage<M> {
20    /// Get the EIP-712 signature bytes.
21    ///
22    /// The ECDSA signature bytes can be used as a key in a [`BTreeMap`] (or [`HashMap`]) to
23    /// deduplicate signed messages based on their signature.
24    ///
25    /// [`BTreeMap`]: std::collections::BTreeMap
26    /// [`HashMap`]: std::collections::HashMap
27    pub fn signature_bytes(&self) -> SignatureBytes {
28        SignatureBytes(self.signature.as_bytes())
29    }
30
31    /// Hash the message struct according to [EIP-712 `hashStruct`](https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct).
32    ///
33    /// The resulting hash can be used to deduplicate messages. As the hash does not include the
34    /// signature, it is unique for a given message payload. This means that two [`SignedMessage`]s,
35    /// signed by two different signers, will have the same hash.
36    pub fn message_hash<MSol>(&self) -> MessageHash
37    where
38        M: ToSolStruct<MSol>,
39        MSol: SolStruct,
40    {
41        MessageHash(*self.message.to_sol_struct().eip712_hash_struct())
42    }
43}
44
45/// The EIP-712 ECDSA signature bytes.
46///
47/// See: [`SignedMessage::signature_bytes`]
48#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
49pub struct SignatureBytes([u8; 65]);
50
51impl SignatureBytes {
52    /// Get the signature bytes
53    pub fn as_bytes(&self) -> [u8; 65] {
54        self.0
55    }
56}
57
58impl std::ops::Deref for SignatureBytes {
59    type Target = [u8; 65];
60
61    fn deref(&self) -> &Self::Target {
62        &self.0
63    }
64}
65
66/// Message hash according to [EIP-712 `hashStruct`](https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct).
67///
68/// See: [`SignedMessage::message_hash`]
69#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
70pub struct MessageHash([u8; 32]);
71
72impl MessageHash {
73    /// Get the message hash bytes
74    pub fn as_bytes(&self) -> [u8; 32] {
75        self.0
76    }
77}
78
79impl std::ops::Deref for MessageHash {
80    type Target = [u8; 32];
81
82    fn deref(&self) -> &Self::Target {
83        &self.0
84    }
85}
86
87/// A conversion trait for converting a type into a solidity struct representation
88///
89/// This trait is used to convert a Rust type into a struct implementing the `SolStruct` trait.
90pub trait ToSolStruct<T: SolStruct> {
91    /// Convert into the solidity struct representation
92    fn to_sol_struct(&self) -> T;
93}
94
95impl<T> ToSolStruct<T> for T
96where
97    T: SolStruct + Clone,
98{
99    /// Convert into the solidity struct representation.
100    ///
101    /// If the type already implements the `SolStruct` trait, this method will return a clone of
102    /// the type without performing any conversion.
103    fn to_sol_struct(&self) -> T {
104        self.clone()
105    }
106}