signet_types/
magic_sig.rs1use alloy::primitives::{Address, Signature, B256};
2use signet_zenith::MINTER_ADDRESS;
3
4pub(crate) const MAGIC_SIG_SENTINEL: [u8; 4] = [0xff, 0xee, 0xdd, 0xcc];
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[repr(u8)]
14pub(crate) enum Flags {
15 Enter = 0x01,
17 EnterToken = 0x02,
19 Transact = 0x03,
21}
22
23impl From<Flags> for u8 {
24 fn from(flag: Flags) -> u8 {
25 flag as u8
26 }
27}
28
29impl TryFrom<u8> for Flags {
30 type Error = ();
31
32 fn try_from(value: u8) -> Result<Self, Self::Error> {
33 match value {
34 0x01 => Ok(Self::Enter),
35 0x02 => Ok(Self::EnterToken),
36 0x03 => Ok(Self::Transact),
37 _ => Err(()),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[non_exhaustive]
46pub enum MagicSigInfo {
47 Enter,
49 EnterToken,
51 Transact {
53 sender: Address,
55 },
56}
57
58impl MagicSigInfo {
59 const fn flag(&self) -> u8 {
61 match self {
62 Self::Enter => Flags::Enter as u8,
63 Self::EnterToken => Flags::EnterToken as u8,
64 Self::Transact { .. } => Flags::Transact as u8,
65 }
66 }
67
68 pub fn write_into_s(&self, buf: &mut [u8]) {
70 debug_assert_eq!(buf.len(), 32);
71
72 buf[8] = self.flag();
73 if let Self::Transact { sender } = self {
74 buf[12..32].copy_from_slice(sender.as_slice());
75 }
76 }
77
78 pub fn read_from_s(s: impl AsRef<[u8]>) -> Option<Self> {
80 let s = s.as_ref();
81 if s.len() < 32 {
82 return None;
83 }
84 let flag = s[8].try_into().ok()?;
85 match flag {
86 Flags::Enter => Some(Self::Enter),
87 Flags::EnterToken => Some(Self::EnterToken),
88 Flags::Transact => Some(Self::Transact { sender: Address::from_slice(&s[12..]) }),
89 }
90 }
91
92 pub const fn sender(&self) -> Address {
96 match self {
97 Self::Transact { sender } => *sender,
98 _ => MINTER_ADDRESS,
99 }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
137pub struct MagicSig {
138 pub ty: MagicSigInfo,
140 pub txid: B256,
142 pub event_idx: usize,
144}
145
146impl MagicSig {
147 pub fn try_from_signature(sig: &Signature) -> Option<Self> {
149 let s = sig.s();
150 let s_bytes: [u8; 32] = s.to_be_bytes();
151 if !s_bytes.starts_with(&MAGIC_SIG_SENTINEL) {
152 return None;
153 }
154
155 let ty = MagicSigInfo::read_from_s(s_bytes)?;
156 let txid = sig.r().to_le_bytes().into();
157
158 let mut buf = [0u8; 4];
159 buf.copy_from_slice(&s_bytes[4..8]);
160 let event_idx = u32::from_be_bytes(buf) as usize;
161
162 Some(Self { ty, txid, event_idx })
163 }
164
165 pub const fn enter(txid: B256, event_idx: usize) -> Self {
167 Self { ty: MagicSigInfo::Enter, txid, event_idx }
168 }
169
170 pub const fn enter_token(txid: B256, event_idx: usize) -> Self {
172 Self { ty: MagicSigInfo::EnterToken, txid, event_idx }
173 }
174
175 pub const fn transact(txid: B256, event_idx: usize, sender: Address) -> Self {
177 Self { ty: MagicSigInfo::Transact { sender }, txid, event_idx }
178 }
179
180 pub const fn sender(&self) -> Address {
182 self.ty.sender()
183 }
184}
185
186impl From<MagicSig> for Signature {
187 fn from(value: MagicSig) -> Self {
188 let mut buf = [0u8; 64];
189 buf[..32].copy_from_slice(value.txid.as_ref());
190 buf[32..36].copy_from_slice(&MAGIC_SIG_SENTINEL);
191 buf[36..40].copy_from_slice(&(value.event_idx as u32).to_be_bytes());
192 value.ty.write_into_s(&mut buf[32..]);
193
194 Signature::from_bytes_and_parity(&buf, false)
195 }
196}
197
198#[cfg(test)]
199mod test {
200
201 use super::*;
202
203 const ENTER_TOKEN_TX: &str = include_str!("../../../tests/artifacts/enter_tx.json");
206
207 #[test]
208 fn test_enter_roundtrip() {
209 let txid = B256::repeat_byte(0xcc);
210
211 let msig = MagicSig::enter_token(txid, 333);
212 let sig: Signature = msig.into();
213
214 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig))
215 }
216
217 #[test]
218 fn test_enter_token_roundtrip() {
219 let txid = B256::repeat_byte(0xcc);
220
221 let msig = MagicSig::enter_token(txid, 3821);
222 let sig: Signature = msig.into();
223
224 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig))
225 }
226
227 #[test]
228 fn test_transact_roundtrip() {
229 let txid = B256::repeat_byte(0xcc);
230 let sender = Address::repeat_byte(0x12);
231
232 let msig = MagicSig::transact(txid, u32::MAX as usize, sender);
233 let sig: Signature = msig.into();
234
235 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig))
236 }
237
238 #[test]
239 fn test_tx_decode_sig() {
240 let tx: alloy::consensus::TxEnvelope = serde_json::from_str(ENTER_TOKEN_TX).unwrap();
241 let sig = tx.signature();
242 let msig = MagicSig::try_from_signature(sig).unwrap();
243 assert_eq!(msig.sender(), MINTER_ADDRESS)
246 }
247}