hpl_interface/types/
metadata.rs

1use std::collections::BTreeMap;
2
3use cosmwasm_schema::cw_serde;
4use cosmwasm_std::{Addr, HexBinary, Uint256};
5
6use super::bech32_encode;
7
8const SIGNATURE_LENGTH: usize = 65;
9
10#[cw_serde]
11pub struct MerkleRootMultisigIsmMetadata {
12    pub origin_mailbox: HexBinary,
13    // bytes32
14    pub checkpoint_index: u32,
15    pub message_id: HexBinary,
16    // bytes32
17    pub proof: HexBinary,
18    // bytes32[32]
19    pub signatures: HexBinary, // threshold * 65
20}
21
22impl From<MerkleRootMultisigIsmMetadata> for HexBinary {
23    fn from(v: MerkleRootMultisigIsmMetadata) -> Self {
24        v.origin_mailbox
25            .to_vec()
26            .iter()
27            .chain(v.checkpoint_index.to_be_bytes().iter())
28            .chain(v.message_id.to_vec().iter())
29            .chain(v.proof.to_vec().iter())
30            .chain(v.signatures.to_vec().iter())
31            .cloned()
32            .collect::<Vec<u8>>()
33            .into()
34    }
35}
36
37impl From<HexBinary> for MerkleRootMultisigIsmMetadata {
38    fn from(v: HexBinary) -> Self {
39        Self {
40            origin_mailbox: v[0..32].to_vec().into(),
41            checkpoint_index: u32::from_be_bytes(v[32..36].try_into().unwrap()),
42            message_id: v[36..68].to_vec().into(),
43            proof: v[68..1092].to_vec().into(),
44            signatures: v[1092..].to_vec().into(),
45        }
46    }
47}
48
49impl MerkleRootMultisigIsmMetadata {
50    pub fn signatures_len(&self) -> Result<usize, &'static str> {
51        if self.signatures.len() % SIGNATURE_LENGTH != 0 {
52            return Err("Invalid signatures length");
53        }
54
55        Ok(self.signatures.len() / SIGNATURE_LENGTH)
56    }
57
58    pub fn signature_at(&self, index: usize) -> HexBinary {
59        // FIXME: handle index out of length
60        self.signatures[index * SIGNATURE_LENGTH..(index + 1) * SIGNATURE_LENGTH]
61            .to_vec()
62            .into()
63    }
64}
65
66#[cw_serde]
67pub struct MessageIdMultisigIsmMetadata {
68    pub origin_merkle_tree: HexBinary,
69
70    pub merkle_root: HexBinary,
71
72    pub merkle_index: HexBinary,
73
74    pub signatures: Vec<HexBinary>,
75}
76
77impl From<MessageIdMultisigIsmMetadata> for HexBinary {
78    fn from(v: MessageIdMultisigIsmMetadata) -> Self {
79        let mut origin_merkle_tree = [0u8; 32];
80        origin_merkle_tree[32 - v.origin_merkle_tree.len()..]
81            .copy_from_slice(&v.origin_merkle_tree);
82
83        origin_merkle_tree
84            .to_vec()
85            .iter()
86            .chain(v.merkle_root.to_vec().iter())
87            .chain(v.merkle_index.to_vec().iter())
88            .chain(
89                v.signatures
90                    .iter()
91                    .flat_map(|x| x.to_vec())
92                    .collect::<Vec<_>>()
93                    .iter(),
94            )
95            .cloned()
96            .collect::<Vec<u8>>()
97            .into()
98    }
99}
100
101impl From<HexBinary> for MessageIdMultisigIsmMetadata {
102    fn from(v: HexBinary) -> Self {
103        let signatures = v[68..]
104            .to_vec()
105            .chunks_exact(SIGNATURE_LENGTH)
106            .map(|v| v.into())
107            .collect::<Vec<HexBinary>>();
108
109        Self {
110            origin_merkle_tree: v[0..32].to_vec().into(),
111            merkle_root: v[32..64].to_vec().into(),
112            merkle_index: v[64..68].to_vec().into(),
113            signatures,
114        }
115    }
116}
117
118impl MessageIdMultisigIsmMetadata {
119    pub fn merkle_index(&self) -> u32 {
120        u32::from_be_bytes(self.merkle_index.to_vec().try_into().unwrap())
121    }
122}
123
124use std::convert::AsMut;
125
126fn clone_into_array<A, T>(slice: &[T]) -> A
127where
128    A: Sized + Default + AsMut<[T]>,
129    T: Clone,
130{
131    let mut a = Default::default();
132    <A as AsMut<[T]>>::as_mut(&mut a).clone_from_slice(slice);
133    a
134}
135
136#[cw_serde]
137pub struct AggregateMetadata(BTreeMap<Addr, HexBinary>);
138
139impl AggregateMetadata {
140    pub const RANGE_SIZE: usize = 4;
141
142    pub fn new(set: Vec<(Addr, HexBinary)>) -> Self {
143        Self(set.into_iter().collect())
144    }
145}
146
147impl Iterator for AggregateMetadata {
148    type Item = (Addr, HexBinary);
149
150    fn next(&mut self) -> Option<Self::Item> {
151        self.0.pop_first()
152    }
153}
154
155impl AggregateMetadata {
156    pub fn from_hex(v: HexBinary, addrs: Vec<Addr>) -> Self {
157        Self(
158            addrs
159                .into_iter()
160                .enumerate()
161                .map(|(i, ism)| {
162                    let start = i * Self::RANGE_SIZE * 2;
163                    let mid = start + Self::RANGE_SIZE;
164                    let end = mid + Self::RANGE_SIZE;
165
166                    let mut meta_start = [0u8; 4];
167                    meta_start.copy_from_slice(&v[start..mid]);
168                    let mut meta_end = [0u8; 4];
169                    meta_end.copy_from_slice(&v[mid..end]);
170
171                    let meta_start = u32::from_be_bytes(meta_start) as usize;
172                    let meta_end = u32::from_be_bytes(meta_end) as usize;
173
174                    (ism, v[meta_start..meta_end].to_vec().into())
175                })
176                .collect(),
177        )
178    }
179}
180
181impl From<AggregateMetadata> for HexBinary {
182    fn from(v: AggregateMetadata) -> Self {
183        let pos_start = v.0.len() * AggregateMetadata::RANGE_SIZE * 2;
184
185        let ls: Vec<(
186            [u8; AggregateMetadata::RANGE_SIZE],
187            [u8; AggregateMetadata::RANGE_SIZE],
188            HexBinary,
189        )> =
190            v.0.values()
191                .fold(vec![] as Vec<(usize, usize, HexBinary)>, |mut acc, m| {
192                    let l = acc.last().map(|v| v.1).unwrap_or(pos_start);
193
194                    acc.push((l, l + m.len(), m.clone()));
195                    acc
196                })
197                .into_iter()
198                .map(|(start, end, metadata)| {
199                    (
200                        clone_into_array(&start.to_be_bytes()[AggregateMetadata::RANGE_SIZE..]),
201                        clone_into_array(&end.to_be_bytes()[AggregateMetadata::RANGE_SIZE..]),
202                        metadata,
203                    )
204                })
205                .collect();
206
207        let mut pos = vec![];
208        let mut metadata = vec![];
209
210        for (start, end, meta) in ls {
211            pos.extend_from_slice(&start);
212            pos.extend_from_slice(&end);
213            metadata.extend_from_slice(meta.as_slice());
214        }
215
216        [pos, metadata].concat().into()
217    }
218}
219
220#[cw_serde]
221pub struct IGPMetadata {
222    pub gas_limit: Uint256,
223    pub refund_address: HexBinary,
224}
225
226impl From<IGPMetadata> for HexBinary {
227    fn from(v: IGPMetadata) -> Self {
228        v.gas_limit
229            .to_be_bytes()
230            .iter()
231            .chain(v.refund_address.to_vec().iter())
232            .cloned()
233            .collect::<Vec<u8>>()
234            .into()
235    }
236}
237
238impl From<HexBinary> for IGPMetadata {
239    fn from(v: HexBinary) -> Self {
240        Self {
241            gas_limit: Uint256::from_be_bytes(v[0..32].try_into().unwrap()),
242            refund_address: v[32..].to_vec().into(),
243        }
244    }
245}
246
247impl IGPMetadata {
248    pub fn get_refund_address(&self, hrp: &str, default: Addr) -> Addr {
249        if self.refund_address.to_vec().len() != 20 && self.refund_address.to_vec().len() != 32 {
250            return default;
251        }
252
253        let raw_addr = match self
254            .refund_address
255            .to_vec()
256            .iter()
257            .take(16)
258            .all(|&byte| byte == 0)
259        {
260            true => self.refund_address.to_vec()[16..].to_vec(),
261            false => self.refund_address.to_vec(),
262        };
263
264        bech32_encode(hrp, &raw_addr).unwrap()
265    }
266}
267
268#[cfg(test)]
269mod test {
270    use ibcx_test_utils::{addr, gen_bz, hex};
271
272    use super::*;
273
274    #[test]
275    fn test_aggregate() {
276        let set = vec![
277            (addr("test1"), gen_bz(12)),
278            (addr("test2"), gen_bz(12)),
279            (addr("test3"), gen_bz(12)),
280        ];
281
282        let metadata = AggregateMetadata::new(set);
283        let isms = metadata.0.clone().into_keys().collect();
284
285        let metadata_bz: HexBinary = metadata.clone().into();
286
287        let new_metadata = AggregateMetadata::from_hex(metadata_bz, isms);
288        assert_eq!(metadata, new_metadata);
289    }
290
291    #[test]
292    fn test_message_id_multisig_metadata() {
293        let testdata = hex("fadafdf4db5e6264d450bafa5951b2180b8fe8aac2e012f280784ae841e9a7f732a2601709a27a5e370a59f98a67b5da6baa522b6421edf2ea240d94d84511a800000000df4eaf1947af0858139b90054561d5ab2a423b4ad8d75a5ec7f9e860fd3de1bb3924e2593e29b595aae2717538c0af6d6ae9fc20477da49d223a0d928a1efb311bdf4eaf1947af0858139b90054561d5ab2a423b4ad8d75a5ec7f9e860fd3de1bb3924e2593e29b595aae2717538c0af6d6ae9fc20477da49d223a0d928a1efb311b");
294
295        let metadata: MessageIdMultisigIsmMetadata = testdata.clone().into();
296
297        assert_eq!(metadata.signatures.len(), 2);
298        assert_eq!(
299            metadata.signatures.iter().flat_map(|v| v.to_vec()).count(),
300            SIGNATURE_LENGTH * 2
301        );
302
303        let recovered: HexBinary = metadata.into();
304
305        assert_eq!(recovered, testdata);
306    }
307}