Skip to main content

hypercall_signer/
encoding.rs

1use alloy::primitives::Address;
2
3use crate::RsmSignerError;
4
5pub fn encode_action_bytes(
6    version: u8,
7    id: u32,
8    inner_abi: &[u8],
9) -> Result<Vec<u8>, RsmSignerError> {
10    if id > 0x00ff_ffff {
11        return Err(RsmSignerError::InvalidAction(format!(
12            "action id {} exceeds uint24 range",
13            id
14        )));
15    }
16
17    let mut encoded = Vec::with_capacity(4 + inner_abi.len());
18    encoded.push(version);
19    let id_bytes = id.to_be_bytes();
20    encoded.extend_from_slice(&id_bytes[1..]);
21    encoded.extend_from_slice(inner_abi);
22    Ok(encoded)
23}
24
25pub fn encode_directive(account: Address, nonce: u64, action_bytes: &[u8]) -> Vec<u8> {
26    let mut directive = Vec::with_capacity(28 + action_bytes.len());
27    directive.extend_from_slice(account.as_slice());
28    directive.extend_from_slice(&nonce.to_be_bytes());
29    directive.extend_from_slice(action_bytes);
30    directive
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn encodes_action_id_as_uint24() {
39        let encoded = encode_action_bytes(2, 0x00ab_cdef, &[0x11, 0x22]).unwrap();
40        assert_eq!(encoded, vec![0x02, 0xab, 0xcd, 0xef, 0x11, 0x22]);
41    }
42
43    #[test]
44    fn rejects_action_id_outside_uint24_range() {
45        let err = encode_action_bytes(1, 0x0100_0000, &[])
46            .unwrap_err()
47            .to_string();
48        assert!(err.contains("exceeds uint24 range"));
49    }
50
51    #[test]
52    fn directive_is_account_nonce_then_action() {
53        let account = Address::repeat_byte(0x7a);
54        let directive = encode_directive(account, 42, &[0xaa, 0xbb]);
55
56        assert_eq!(&directive[..20], account.as_slice());
57        assert_eq!(&directive[20..28], 42_u64.to_be_bytes());
58        assert_eq!(&directive[28..], &[0xaa, 0xbb]);
59    }
60}