Skip to main content

wormhole/
byte_utils.rs

1use cosmwasm_std::CanonicalAddr;
2
3pub trait ByteUtils {
4    fn get_u8(&self, index: usize) -> u8;
5    fn get_u16(&self, index: usize) -> u16;
6    fn get_u32(&self, index: usize) -> u32;
7    fn get_u64(&self, index: usize) -> u64;
8
9    fn get_u128_be(&self, index: usize) -> u128;
10    /// High 128 then low 128
11    fn get_u256(&self, index: usize) -> (u128, u128);
12    fn get_address(&self, index: usize) -> CanonicalAddr;
13    fn get_bytes32(&self, index: usize) -> &[u8];
14    fn get_bytes(&self, index: usize, bytes: usize) -> &[u8];
15    fn get_const_bytes<const N: usize>(&self, index: usize) -> [u8; N];
16}
17
18impl ByteUtils for &[u8] {
19    fn get_u8(&self, index: usize) -> u8 {
20        self[index]
21    }
22    fn get_u16(&self, index: usize) -> u16 {
23        let mut bytes: [u8; 16 / 8] = [0; 16 / 8];
24        bytes.copy_from_slice(&self[index..index + 2]);
25        u16::from_be_bytes(bytes)
26    }
27    fn get_u32(&self, index: usize) -> u32 {
28        let mut bytes: [u8; 32 / 8] = [0; 32 / 8];
29        bytes.copy_from_slice(&self[index..index + 4]);
30        u32::from_be_bytes(bytes)
31    }
32    fn get_u64(&self, index: usize) -> u64 {
33        let mut bytes: [u8; 64 / 8] = [0; 64 / 8];
34        bytes.copy_from_slice(&self[index..index + 8]);
35        u64::from_be_bytes(bytes)
36    }
37    fn get_u128_be(&self, index: usize) -> u128 {
38        let mut bytes: [u8; 128 / 8] = [0; 128 / 8];
39        bytes.copy_from_slice(&self[index..index + 128 / 8]);
40        u128::from_be_bytes(bytes)
41    }
42    fn get_u256(&self, index: usize) -> (u128, u128) {
43        (self.get_u128_be(index), self.get_u128_be(index + 128 / 8))
44    }
45    fn get_address(&self, index: usize) -> CanonicalAddr {
46        // 32 bytes are reserved for addresses, but only the last 20 bytes are taken by the actual address
47        if self.get_u128_be(index) >> 32 != 0 {
48            panic!("invalid Terra address");
49        }
50        CanonicalAddr::from(&self[index + 32 - 20..index + 32])
51    }
52    fn get_bytes32(&self, index: usize) -> &[u8] {
53        &self[index..index + 32]
54    }
55
56    fn get_bytes(&self, index: usize, bytes: usize) -> &[u8] {
57        &self[index..index + bytes]
58    }
59
60    fn get_const_bytes<const N: usize>(&self, index: usize) -> [u8; N] {
61        let mut bytes: [u8; N] = [0; N];
62        bytes.copy_from_slice(&self[index..index + N]);
63        bytes
64    }
65}
66
67/// Left-pad a 20 byte address with 0s
68pub fn extend_address_to_32(addr: &CanonicalAddr) -> Vec<u8> {
69    extend_address_to_32_array(addr).to_vec()
70}
71
72pub fn extend_address_to_32_array(addr: &CanonicalAddr) -> [u8; 32] {
73    let mut v: Vec<u8> = vec![0; 12];
74    v.extend(addr.as_slice());
75    let mut result: [u8; 32] = [0; 32];
76    result.copy_from_slice(&v);
77    result
78}
79
80/// Turn a string into a fixed length array. If the string is shorter than the
81/// resulting array, it gets padded with \0s on the right. If longer, it gets
82/// truncated.
83pub fn string_to_array<const N: usize>(s: &str) -> [u8; N] {
84    let bytes = s.as_bytes();
85    let len = usize::min(N, bytes.len());
86    let zeros = vec![0; N - len];
87    let padded = [bytes[..len].to_vec(), zeros].concat();
88    let mut result: [u8; N] = [0; N];
89    result.copy_from_slice(&padded);
90    result
91}
92
93pub fn extend_string_to_32(s: &str) -> Vec<u8> {
94    string_to_array::<32>(s).to_vec()
95}
96
97pub fn get_string_from_32(v: &[u8]) -> String {
98    let s = String::from_utf8_lossy(v);
99    s.chars().filter(|c| c != &'\0').collect()
100}