signet_types/
magic_sig.rs1use crate::alias_address;
2use alloy::primitives::{Address, Signature, B256};
3use signet_zenith::MINTER_ADDRESS;
4
5pub(crate) const MAGIC_SIG_SENTINEL: [u8; 4] = [0xff, 0xee, 0xdd, 0xcc];
11
12#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[repr(u8)]
15pub(crate) enum Flags {
16 Enter = 0x01,
18 EnterToken = 0x02,
20 Transact = 0x03,
22}
23
24impl From<Flags> for u8 {
25 fn from(flag: Flags) -> u8 {
26 flag as u8
27 }
28}
29
30impl TryFrom<u8> for Flags {
31 type Error = ();
32
33 fn try_from(value: u8) -> Result<Self, Self::Error> {
34 match value {
35 0x01 => Ok(Self::Enter),
36 0x02 => Ok(Self::EnterToken),
37 0x03 => Ok(Self::Transact),
38 _ => Err(()),
39 }
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
46#[non_exhaustive]
47pub enum MagicSigInfo {
48 Enter,
50 EnterToken,
52 Transact {
54 sender: Address,
56 aliased: bool,
64 },
65}
66
67impl MagicSigInfo {
68 const fn flag(&self) -> u8 {
70 match self {
71 Self::Enter => Flags::Enter as u8,
72 Self::EnterToken => Flags::EnterToken as u8,
73 Self::Transact { .. } => Flags::Transact as u8,
74 }
75 }
76
77 pub fn write_into_s(&self, buf: &mut [u8]) {
79 debug_assert_eq!(buf.len(), 32);
80
81 buf[8] = self.flag();
82 if let Self::Transact { sender, aliased } = self {
83 buf[11] = *aliased as u8;
84 buf[12..32].copy_from_slice(sender.as_slice());
85 }
86 }
87
88 pub fn read_from_s(s: impl AsRef<[u8]>) -> Option<Self> {
90 let s = s.as_ref();
91 if s.len() < 32 {
92 return None;
93 }
94 let flag = s[8].try_into().ok()?;
95 match flag {
96 Flags::Enter => Some(Self::Enter),
97 Flags::EnterToken => Some(Self::EnterToken),
98 Flags::Transact => {
99 Some(Self::Transact { aliased: s[11] != 0, sender: Address::from_slice(&s[12..]) })
100 }
101 }
102 }
103
104 pub const fn raw_sender(&self) -> Address {
108 match self {
109 Self::Transact { sender, .. } => *sender,
110 _ => MINTER_ADDRESS,
111 }
112 }
113
114 pub fn rollup_sender(&self) -> Address {
118 match self {
119 Self::Transact { sender, aliased } => {
120 if *aliased {
121 alias_address(*sender)
122 } else {
123 *sender
124 }
125 }
126 _ => MINTER_ADDRESS,
127 }
128 }
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
165pub struct MagicSig {
166 pub ty: MagicSigInfo,
168 pub txid: B256,
170 pub event_idx: usize,
172}
173
174impl MagicSig {
175 pub fn try_from_signature(sig: &Signature) -> Option<Self> {
177 let s = sig.s();
178 let s_bytes: [u8; 32] = s.to_be_bytes();
179 if !s_bytes.starts_with(&MAGIC_SIG_SENTINEL) {
180 return None;
181 }
182
183 let ty = MagicSigInfo::read_from_s(s_bytes)?;
184 let txid = sig.r().to_le_bytes().into();
185
186 let mut buf = [0u8; 4];
187 buf.copy_from_slice(&s_bytes[4..8]);
188 let event_idx = u32::from_be_bytes(buf) as usize;
189
190 Some(Self { ty, txid, event_idx })
191 }
192
193 pub const fn enter(txid: B256, event_idx: usize) -> Self {
195 Self { ty: MagicSigInfo::Enter, txid, event_idx }
196 }
197
198 pub const fn enter_token(txid: B256, event_idx: usize) -> Self {
200 Self { ty: MagicSigInfo::EnterToken, txid, event_idx }
201 }
202
203 pub const fn transact(txid: B256, aliased: bool, event_idx: usize, sender: Address) -> Self {
205 Self { ty: MagicSigInfo::Transact { sender, aliased }, txid, event_idx }
206 }
207
208 pub fn rollup_sender(&self) -> Address {
210 self.ty.rollup_sender()
211 }
212}
213
214impl From<MagicSig> for Signature {
215 fn from(value: MagicSig) -> Self {
216 let mut buf = [0u8; 64];
217 buf[..32].copy_from_slice(value.txid.as_ref());
218 buf[32..36].copy_from_slice(&MAGIC_SIG_SENTINEL);
219 buf[36..40].copy_from_slice(&(value.event_idx as u32).to_be_bytes());
220 value.ty.write_into_s(&mut buf[32..]);
221
222 Signature::from_bytes_and_parity(&buf, false)
223 }
224}
225
226#[cfg(test)]
227mod test {
228
229 use super::*;
230
231 const ENTER_TOKEN_TX: &str = include_str!("../../../tests/artifacts/enter_tx.json");
234
235 #[test]
236 fn test_enter_roundtrip() {
237 let txid = B256::repeat_byte(0xcc);
238
239 let msig = MagicSig::enter_token(txid, 333);
240 let sig: Signature = msig.into();
241
242 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig))
243 }
244
245 #[test]
246 fn test_enter_token_roundtrip() {
247 let txid = B256::repeat_byte(0xcc);
248
249 let msig = MagicSig::enter_token(txid, 3821);
250 let sig: Signature = msig.into();
251
252 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig))
253 }
254
255 #[test]
256 fn test_transact_roundtrip() {
257 let txid = B256::repeat_byte(0xcc);
258 let sender = Address::repeat_byte(0x12);
259
260 let msig = MagicSig::transact(txid, false, u32::MAX as usize, sender);
261 let sig: Signature = msig.into();
262 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig));
263
264 let msig = MagicSig::transact(txid, true, 0, sender);
265 let sig: Signature = msig.into();
266 assert_eq!(MagicSig::try_from_signature(&sig), Some(msig));
267 }
268
269 #[test]
270 fn test_tx_decode_sig() {
271 let tx: alloy::consensus::TxEnvelope = serde_json::from_str(ENTER_TOKEN_TX).unwrap();
272 let sig = tx.signature();
273 let msig = MagicSig::try_from_signature(sig).unwrap();
274 assert_eq!(msig.rollup_sender(), MINTER_ADDRESS)
278 }
279}