lwk/blockdata/
address.rs

1//! Liquid address
2
3use crate::{LwkError, Script};
4use std::{fmt::Display, sync::Arc};
5
6/// A Liquid address
7#[derive(uniffi::Object)]
8#[uniffi::export(Display)]
9pub struct Address {
10    inner: elements::Address,
11}
12
13impl From<elements::Address> for Address {
14    fn from(inner: elements::Address) -> Self {
15        Self { inner }
16    }
17}
18
19impl AsRef<elements::Address> for Address {
20    fn as_ref(&self) -> &elements::Address {
21        &self.inner
22    }
23}
24
25impl From<Address> for elements::Address {
26    fn from(addr: Address) -> Self {
27        addr.inner
28    }
29}
30
31impl From<&Address> for elements::Address {
32    fn from(addr: &Address) -> Self {
33        addr.inner.clone()
34    }
35}
36
37impl Display for Address {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "{}", self.inner)
40    }
41}
42
43#[uniffi::export]
44impl Address {
45    /// Construct an Address object
46    #[uniffi::constructor]
47    pub fn new(s: &str) -> Result<Arc<Self>, LwkError> {
48        let inner: elements::Address = s.parse()?;
49        Ok(Arc::new(Self { inner }))
50    }
51
52    /// Return the script pubkey of the address.
53    pub fn script_pubkey(&self) -> Arc<Script> {
54        Arc::new(self.inner.script_pubkey().into())
55    }
56
57    /// Return true if the address is blinded.
58    pub fn is_blinded(&self) -> bool {
59        self.inner.is_blinded()
60    }
61
62    /// Return the unconfidential address.
63    pub fn to_unconfidential(&self) -> Arc<Self> {
64        Arc::new(self.inner.to_unconfidential().into())
65    }
66
67    /// Returns a string encoding an image in a uri
68    ///
69    /// The string can be open in the browser or be used as `src` field in `img` in HTML
70    ///
71    /// For max efficiency we suggest to pass `None` to `pixel_per_module`, get a very small image
72    /// and use styling to scale up the image in the browser. eg
73    /// `style="image-rendering: pixelated; border: 20px solid white;"`
74    pub fn qr_code_uri(&self, pixel_per_module: Option<u8>) -> Result<String, LwkError> {
75        Ok(lwk_common::address_to_uri_qr(
76            &self.inner,
77            pixel_per_module,
78        )?)
79    }
80
81    /// Returns a string of the QR code printable in a terminal environment
82    pub fn qr_code_text(&self) -> Result<String, LwkError> {
83        Ok(lwk_common::address_to_text_qr(&self.inner)?)
84    }
85}
86
87#[cfg(test)]
88mod tests {
89
90    use super::Address;
91
92    #[test]
93    fn address() {
94        let address_str = "tlq1qq2xvpcvfup5j8zscjq05u2wxxjcyewk7979f3mmz5l7uw5pqmx6xf5xy50hsn6vhkm5euwt72x878eq6zxx2z58hd7zrsg9qn";
95
96        let address = Address::new(address_str).unwrap();
97        assert_eq!(address.to_string(), address_str);
98
99        assert_eq!(
100            address.script_pubkey().to_string(),
101            "0014d0c4a3ef09e997b6e99e397e518fe3e41a118ca1"
102        );
103
104        assert!(address.is_blinded());
105
106        assert_eq!(
107            address.to_unconfidential().to_string(),
108            "tex1q6rz28mcfaxtmd6v789l9rrlrusdprr9p634wu8"
109        );
110
111        println!("{}", address.qr_code_text().unwrap());
112
113        let expected = "
114███████████████████████████████████████████████
115███████████████████████████████████████████████
116███ ▄▄▄▄▄ █▄▄▀▄▄▄▀▀▄█▀ ▀  ▀▀  █  █  █ ▄▄▄▄▄ ███
117███ █   █ █▀▀ ███▄██ ▄▀ ▀▄█▄█▄▄▀▀▀▄▄█ █   █ ███
118███ █▄▄▄█ █ █  ▄▄████▀█  ▀█▄▄▀▄█▀ ▀▀█ █▄▄▄█ ███
119███▄▄▄▄▄▄▄█ ▀▄▀ ▀ █▄█▄█ ▀ █▄█ █▄▀ █▄█▄▄▄▄▄▄▄███
120███▄▀█▀ █▄▄ █ ███▀█▀▄ ▄▄█▄▄▀█▄ █ █▄█▄▄▄ ▄██▄███
121███ ▀▄██ ▄▄▀█▀██▄  █▄▀▀▄   ▄▀▄ ▄▀ █ █▀█▄▀█▀▄███
122███▄ ▀▄█▄▄ █▀█ ▄▄▄█▀ █ ▄█▄█▀▄▀█▀█  ▀ ▀█▄ ▀ ▀███
123███▀  ▄▀▄▄██▄ █▄▀    █ ▀▀  ▄███▄▄▀█▄▄▀ ▀ █▀████
124███ █▀██▄▄▄▀  ▀▀▀█▄█▀███▄▄▀ ▄ ▄▀█▀▄▀▄▀▀▀█▀▀▀███
125███ █▄  ▄▄█▄█▄█▄██▀▄█▄▄▀ ▄▄  ▄█  ▀▀█  ██ █  ███
126███  █▄▄▀▄█ ▄ ▀▀▄▄▄ ▀▀█▀▀▀ ▀▄▀▄▀█▄▄█ █▄█▀ ▄▀███
127████ ▄▄█▄▄██▀▀ ▄ ▄▄▀██▄▄▀  ▄  █  ▄█▄▄█▄▄█ █ ███
128███▄▄ ▀▀█▄█▀█ █ ████ ██▄█ ▀▄▄█▀ ▄▀▄▄▀█▀▄▀▄▄▄███
129███▄▄█▄▀█▄▀ ▄▀▄█▀█  ▄ ▄███ ▄▄▄ █▀██▀  ▀  █ ████
130███ ▄▀█ █▄ █ █▀ ▀ █▄ █▀▀▄▀▄▄ ▄█▄ ▄ ▄██▄█▀▀▀████
131█████▄   ▄█▄▀  ▀ ▄▀▀▀▄█▄▀▄█▀ ▀ ▀   ▀▀ ▀█  ▄████
132███▄▄█▄▄█▄▄ ██ ▀ █  ██ █ █ ▄ █▀ ▀ ▀ ▄▄▄  ▀  ███
133███ ▄▄▄▄▄ █▄██▀█▄▀ ▀ ▀█▀█▀ ▄█▀█▄█▄█ █▄█  █▀▀███
134███ █   █ █▄▀█▀█▄ ▀█▀▄ █▀▄▄▄▄▄▄ ▀▀█  ▄ ▄███▄███
135███ █▄▄▄█ ██ ▀█▄   █▄▀█▄█▀▄██▀▄▄▀▄▀▄▀███▄   ███
136███▄▄▄▄▄▄▄█▄█▄█▄▄▄█▄▄█▄▄█▄▄███▄█▄█▄██▄█▄▄▄▄████
137███████████████████████████████████████████████";
138
139        assert!(address.qr_code_text().unwrap().contains(expected.trim()));
140
141        assert_eq!(address.qr_code_uri(None).unwrap(), "data:image/bmp;base64,Qk2GAQAAAAAAAD4AAAAoAAAAKQAAACkAAAABAAEAAAAAAEgBAAAAAgAAAAIAAAIAAAACAAAA////AAAAAAD+rtsVLwAAAIJnIiVDgAAAuk9JGoeAAAC6U1QO0AAAALqGM/j4gAAAghPrII2AAAD+hUGKrAAAAACdlV+PgAAA25WVyv2AAAAcfcT/9gAAAD62KlcnAAAAqV5aRQcAAADLSsXvkAAAAAmloRT9AAAA0tHx8G0AAAA4qEMaVAAAAOIoSs2LgAAAQHSHbAKAAAB2Hxvu2oAAAMS476hGgAAA2ueBU1MAAACYAQzPZYAAAL6ot+xlgAAAoPxBqruAAACHYQbxQAAAAOgn3wI9AAAAdmvTjNQAAABhUNCr54AAANceWkNNAAAAxKM3VqUAAACnB0+6iIAAAFiioJQIAAAAi6B7NXyAAAAA3g4mAAAAAP6qqqq/gAAAgrAuJ6CAAAC6vAzSLoAAALrgXA4ugAAAuiJqsa6AAACCIz/toIAAAP7clm2/gAAA");
142    }
143}