openassets/openassets/
address.rs

1use bitcoin::network::constants::Network;
2use bitcoin::util::address::Payload;
3use bitcoin::consensus::encode;
4use std::fmt::{self, Display, Formatter};
5use bitcoin::util::base58;
6use bitcoin::consensus::encode::Error::ParseFailed;
7
8/// A Open Assets Address
9#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub struct Address {
11
12    pub network: Network,
13    pub payload: Payload,
14
15}
16
17const NAMESPACE: u8 = 0x13;
18
19impl Address {
20
21    pub fn new(payload: Payload, network: bitcoin::network::constants::Network) -> Result<Self, encode::Error> {
22        match payload {
23            Payload::PubkeyHash(_) | Payload::ScriptHash(_) => {},
24            _ => {return Err(ParseFailed("The Open Assets Address of the witness program does not defined."));}
25        }
26        Ok(Address { payload, network })
27    }
28
29    pub fn to_btc_addr(&self) -> Result<bitcoin::Address, encode::Error> {
30        Ok(bitcoin::Address {network: self.network, payload: self.payload.clone()})
31    }
32}
33
34impl Display for Address{
35    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
36        let mut prefixed = [0; 22];
37        prefixed[0] = NAMESPACE;
38        prefixed[1] = match self.network {
39            bitcoin::network::constants::Network::Bitcoin => 0,
40            bitcoin::network::constants::Network::Testnet | bitcoin::network::constants::Network::Regtest => 111
41        };
42        match self.payload {
43            Payload::PubkeyHash(ref hash) => {
44                prefixed[2..].copy_from_slice(&hash[..]);
45                base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
46            },
47            Payload::ScriptHash(ref hash) => {
48                prefixed[2..].copy_from_slice(&hash[..]);
49                base58::check_encode_slice_to_fmt(fmt, &prefixed[..])
50            },
51            Payload::WitnessProgram(_) => {
52                fmt.write_str("The Open Assets Address of the witness program does not defined.")
53            },
54        }
55    }
56}
57
58pub trait OAAddressConverter {
59
60    fn to_oa_address(&self) -> Result<Address, encode::Error>;
61
62}
63
64impl OAAddressConverter for bitcoin::Address{
65    fn to_oa_address(&self) -> Result<Address, encode::Error> {
66        Address::new(self.payload.clone(), self.network)
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use std::str::FromStr;
73    use std::string::ToString;
74    use openassets::address::OAAddressConverter;
75
76    #[test]
77    fn test_oa_address_converter(){
78        let addr = bitcoin::Address::from_str("1F2AQr6oqNtcJQ6p9SiCLQTrHuM9en44H8").unwrap();
79        assert_eq!("akQz3f1v9JrnJAeGBC4pNzGNRdWXKan4U6E", addr.to_oa_address().unwrap().to_string());
80        assert_eq!(addr, addr.to_oa_address().unwrap().to_btc_addr().unwrap());
81
82
83        let testnet_addr = bitcoin::Address::from_str("mkgW6hNYBctmqDtTTsTJrsf2Gh2NPtoCU4").unwrap();
84        assert_eq!("bWvePLsBsf6nThU3pWVZVWjZbcJCYQxHCpE", testnet_addr.to_oa_address().unwrap().to_string());
85        assert_eq!(testnet_addr, testnet_addr.to_oa_address().unwrap().to_btc_addr().unwrap());
86
87        let segwit_addr = bitcoin::Address::from_str("bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw").unwrap();
88        assert!(segwit_addr.to_oa_address().is_err());
89    }
90
91}