whisky_pallas/utils/
address.rs

1use std::str::FromStr;
2
3use pallas::ledger::addresses::{Address, Network, ShelleyAddress, ShelleyDelegationPart};
4use pallas_crypto::hash::Hash;
5use whisky_common::{DeserializedAddress, WError};
6
7pub fn script_to_address(
8    network_id: u8,
9    script_hash: &str,
10    stake_cred: Option<(&str, bool)>,
11) -> String {
12    let stake_cred = match stake_cred {
13        Some((stake, is_script)) => {
14            let stake_cred = if is_script {
15                ShelleyDelegationPart::Script(Hash::from_str(stake).unwrap())
16            } else {
17                ShelleyDelegationPart::Key(Hash::from_str(stake).unwrap())
18            };
19            stake_cred
20        }
21        None => ShelleyDelegationPart::Null,
22    };
23    let payment_cred =
24        pallas::ledger::addresses::ShelleyPaymentPart::Script(Hash::from_str(script_hash).unwrap());
25
26    let address = ShelleyAddress::new(
27        Network::try_from(network_id).unwrap(),
28        payment_cred,
29        stake_cred,
30    );
31    address.to_bech32().unwrap()
32}
33
34pub fn serialize_address_obj(
35    address_obj: DeserializedAddress,
36    network_id: u8,
37) -> Result<String, WError> {
38    let payment_cred = match (
39        address_obj.pub_key_hash.as_str(),
40        address_obj.script_hash.as_str(),
41    ) {
42        (pub_key_hash, "") => {
43            pallas::ledger::addresses::ShelleyPaymentPart::Key(Hash::from_str(pub_key_hash).unwrap())
44        }
45        ("", script_hash) => {
46            pallas::ledger::addresses::ShelleyPaymentPart::Script(Hash::from_str(script_hash).unwrap())
47        }
48        _ => Err(WError::new(
49            "serialze_address_obj",
50            &format!(
51                "Must provide exactly one of pub_key_hash or script_hash, pub_key_hash: {}, script_hash: {}",
52                address_obj.pub_key_hash, address_obj.script_hash
53            ),
54        ))?,
55    };
56
57    let stake_cred_opt = match (
58        address_obj.stake_key_hash.as_str(),
59        address_obj.stake_key_script_hash.as_str(),
60    ) {
61        ("","") => None,
62        (stake_key_hash, "") => Some(ShelleyDelegationPart::Key(Hash::from_str(stake_key_hash).unwrap())),
63        ("", stake_script_hash) => Some(ShelleyDelegationPart::Script(Hash::from_str(stake_script_hash).unwrap())),
64        _ => Err(WError::new(
65            "serialze_address_obj",
66            &format!(
67                "Must provide at most one of stake_key_hash or stake_script_hash, stake_key_hash: {}, stake_script_hash: {}",
68                address_obj.stake_key_hash, address_obj.stake_key_script_hash
69            ),
70        ))?,
71    };
72
73    match stake_cred_opt {
74        Some(stake_cred) => Ok(ShelleyAddress::new(
75            Network::try_from(network_id).unwrap(),
76            payment_cred,
77            stake_cred,
78        )
79        .to_bech32()
80        .unwrap()),
81        None => Ok(ShelleyAddress::new(
82            Network::try_from(network_id).unwrap(),
83            payment_cred,
84            ShelleyDelegationPart::Null,
85        )
86        .to_bech32()
87        .unwrap()),
88    }
89}
90
91pub fn deserialize_address(bech32_address: &str) -> Result<DeserializedAddress, WError> {
92    let address = Address::from_bech32(bech32_address).map_err(|e| {
93        WError::new(
94            "deserialize_address",
95            &format!(
96                "Failed to parse address from bech32: {}, error: {}",
97                bech32_address, e
98            ),
99        )
100    })?;
101
102    match address {
103        Address::Byron(byron_address) => {
104            return Err(WError::new(
105                "deserialize_address",
106                &format!(
107                    "Byron addresses are not supported: {}",
108                    byron_address.to_base58()
109                ),
110            ))?
111        }
112        Address::Shelley(shelley_address) => {
113            let (payment_pkh, payment_script_hash) = match shelley_address.payment() {
114                pallas::ledger::addresses::ShelleyPaymentPart::Key(key_hash) => {
115                    (key_hash.to_string(), String::new())
116                }
117                pallas::ledger::addresses::ShelleyPaymentPart::Script(script_hash) => {
118                    (String::new(), script_hash.to_string())
119                }
120            };
121            let (stake_pkh, stake_script_hash) = match shelley_address.delegation() {
122                ShelleyDelegationPart::Null => (String::new(), String::new()),
123                ShelleyDelegationPart::Key(stake_key_hash) => {
124                    (stake_key_hash.to_string(), String::new())
125                }
126                ShelleyDelegationPart::Script(stake_script_hash) => {
127                    (String::new(), stake_script_hash.to_string())
128                }
129                ShelleyDelegationPart::Pointer(_pointer) => {
130                    return Err(WError::new(
131                        "deserialize_address",
132                        "Pointer stake keys are not supported",
133                    ))
134                }
135            };
136
137            Ok(DeserializedAddress::new(
138                &payment_pkh,
139                &payment_script_hash,
140                &stake_pkh,
141                &stake_script_hash,
142            ))
143        }
144        Address::Stake(stake_address) => {
145            let stake_payload = stake_address.payload();
146            let (stake_pkh, stake_script_hash) = match stake_payload {
147                pallas::ledger::addresses::StakePayload::Stake(hash) => {
148                    (hash.to_string(), String::new())
149                }
150                pallas::ledger::addresses::StakePayload::Script(hash) => {
151                    (String::new(), hash.to_string())
152                }
153            };
154
155            Ok(DeserializedAddress::new(
156                &String::new(),
157                &String::new(),
158                &stake_pkh,
159                &stake_script_hash,
160            ))
161        }
162    }
163}