1use alloy::primitives::{Address, Keccak256, B256, U256};
2use serde::{Deserialize, Serialize};
3
4const DOMAIN_BINDING: &str = "init4.sequencer.v0";
6
7#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
9#[serde(rename_all = "camelCase")]
10pub struct SignRequest {
11 pub host_block_number: U256,
13 pub host_chain_id: U256,
15 pub ru_chain_id: U256,
17 pub gas_limit: U256,
19 pub ru_reward_address: Address,
21 pub contents: B256,
23}
24
25impl SignRequest {
26 pub fn signing_hash(&self) -> B256 {
28 let mut hasher = Keccak256::new();
29 hasher.update(DOMAIN_BINDING);
30 hasher.update(self.host_chain_id.to_be_bytes::<32>());
31 hasher.update(self.ru_chain_id.to_be_bytes::<32>());
32 hasher.update(self.host_block_number.to_be_bytes::<32>());
33 hasher.update(self.gas_limit.to_be_bytes::<32>());
34 hasher.update(self.ru_reward_address);
35 hasher.update(self.contents);
36 hasher.finalize()
37 }
38}
39
40impl core::fmt::Display for SignRequest {
41 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42 write!(
43 f,
44 "SignRequest {{ host_chain_id: {}, host_block_number: {}, ru_chain_id: {}, gas_limit: {}, ru_reward_address: {}, contents: {} }}",
45 self.host_chain_id,
46 self.host_block_number,
47 self.ru_chain_id,
48 self.gas_limit,
49 self.ru_reward_address,
50 self.contents
51 )
52 }
53}
54
55#[cfg(test)]
56mod test {
57 use super::*;
58 use alloy::primitives::b256;
59
60 #[test]
61 fn roundtrip() {
62 let req = SignRequest {
63 host_block_number: U256::from(0),
64 host_chain_id: U256::from(1),
65 ru_chain_id: U256::from(2),
66 gas_limit: U256::from(5),
67 ru_reward_address: Address::repeat_byte(6),
68 contents: B256::repeat_byte(7),
69 };
70
71 let ser = serde_json::to_string(&req).unwrap();
72 let de: SignRequest = serde_json::from_str(&ser).unwrap();
73 assert_eq!(req, de);
74
75 assert_eq!(
76 req.signing_hash(),
77 b256!("74388c53a86cf15b3e8b11fa5f499dac87819fd00c20cfec4557b7d551b2c445")
78 );
79
80 assert_eq!(de.signing_hash(), req.signing_hash());
81 }
82}