Skip to main content

stellar_axelar_std/
address.rs

1use soroban_sdk::{Address, Bytes, Env, String};
2
3const ZERO_ADDRESS: &str = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
4const STELLAR_ADDRESS_LEN: usize = ZERO_ADDRESS.len();
5
6pub trait AddressExt {
7    fn zero(env: &Env) -> Address;
8
9    fn to_string_bytes(&self) -> Bytes;
10
11    fn to_raw_bytes(&self) -> [u8; STELLAR_ADDRESS_LEN];
12}
13
14impl AddressExt for Address {
15    /// Returns Stellar's ["dead"](https://github.com/stellar/js-stellar-base/blob/master/test/unit/address_test.js) address, represented by the constant `ZERO_ADDRESS`.
16    fn zero(env: &Env) -> Address {
17        Self::from_string(&String::from_str(env, ZERO_ADDRESS))
18    }
19
20    /// Converts Stellar address to a string represented as bytes
21    fn to_string_bytes(&self) -> Bytes {
22        let mut address_string_bytes = [0u8; STELLAR_ADDRESS_LEN];
23        self.to_string().copy_into_slice(&mut address_string_bytes);
24        Bytes::from_slice(self.env(), &address_string_bytes)
25    }
26
27    fn to_raw_bytes(&self) -> [u8; STELLAR_ADDRESS_LEN] {
28        let mut address_string_bytes = [0u8; STELLAR_ADDRESS_LEN];
29        self.to_string().copy_into_slice(&mut address_string_bytes);
30        address_string_bytes
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use stellar_axelar_std::testutils::Address as _;
37    use stellar_axelar_std::{Address, Bytes, Env, String};
38
39    use super::{AddressExt, ZERO_ADDRESS};
40    use crate as stellar_axelar_std;
41
42    #[test]
43    fn zero_address_to_string() {
44        let env = &Env::default();
45        assert_eq!(
46            Address::zero(env).to_string(),
47            String::from_str(env, ZERO_ADDRESS)
48        );
49    }
50
51    #[test]
52    fn string_to_address_to_string() {
53        let env = &Env::default();
54        let cases = [
55            ZERO_ADDRESS,
56            "GC7OHFPWPSWXL4HMN6TXAG54MTZSMJIASWHO6KVRQNHNCXEAHWDSGGC3",
57            "CB6743BTQ2TZHTUCRSUFAH2X5ICOZGI6I3UCQBY3VFSSJ7IERGXUM7TX",
58        ]
59        .into_iter()
60        .map(|s| Bytes::from_slice(env, s.as_bytes()));
61
62        for address_bytes in cases {
63            let address = Address::from_string_bytes(&address_bytes);
64            assert_eq!(address.to_string_bytes(), address_bytes);
65        }
66    }
67
68    #[test]
69    fn address_to_string_to_address() {
70        let env = &Env::default();
71
72        let cases = [
73            Address::zero(env),
74            Address::generate(env),
75            env.register_stellar_asset_contract_v2(Address::generate(env))
76                .address(),
77        ];
78
79        for address in cases {
80            let address_bytes = address.to_string_bytes();
81            assert_eq!(Address::from_string_bytes(&address_bytes), address);
82        }
83    }
84
85    #[test]
86    #[should_panic(expected = "HostError: Error(Value, InvalidInput)")]
87    fn unsupported_muxed_address_format_fails_on_conversion() {
88        let env = &Env::default();
89
90        let unsupported_address =
91            "MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAACJUQ";
92        Address::from_string(&String::from_str(env, unsupported_address));
93    }
94
95    #[test]
96    #[should_panic(expected = "HostError: Error(Value, InvalidInput)")]
97    fn unsupported_signed_payload_address_format_fails_on_conversion() {
98        let env = &Env::default();
99
100        let unsupported_address = "PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUAAAAFGBU";
101        Address::from_string(&String::from_str(env, unsupported_address));
102    }
103}