whisky_provider/maestro/utils/
utxo_utils.rs

1use whisky_common::{
2    models::{Asset, UTxO, UtxoInput, UtxoOutput},
3    WError,
4};
5use whisky_csl::{
6    apply_double_cbor_encoding,
7    csl::{self, NativeScript, PlutusScript, ScriptRef},
8};
9
10use crate::maestro::models::{utxo::Utxo, ScriptVersion};
11
12#[derive(Debug, Clone)]
13pub enum ScriptType {
14    Plutus(PlutusScript),
15    Native(NativeScript),
16}
17
18pub fn to_utxo(utxo: &Utxo) -> Result<UTxO, WError> {
19    let utxo = UTxO {
20        input: UtxoInput {
21            output_index: utxo.index as u32,
22            tx_hash: utxo.tx_hash.clone(),
23        },
24        output: UtxoOutput {
25            address: utxo.address.clone(),
26            amount: utxo
27                .assets
28                .iter()
29                .map(|asset| Asset::new(asset.unit.clone(), asset.amount.to_string()))
30                .collect(),
31            data_hash: utxo.datum.as_ref().and_then(|datum| {
32                datum
33                    .get("hash")
34                    .and_then(|hash| hash.as_str().map(|s| s.to_string()))
35            }),
36            plutus_data: utxo.datum.as_ref().and_then(|datum| {
37                datum
38                    .get("bytes")
39                    .and_then(|hash| hash.as_str().map(|s| s.to_string()))
40            }),
41            script_ref: resolve_script(utxo).map_err(WError::from_err("to_utxo - script_ref"))?,
42            script_hash: utxo
43                .reference_script
44                .as_ref()
45                .map(|script| script.hash.clone()),
46        },
47    };
48    Ok(utxo)
49}
50
51pub fn resolve_script(utxo: &Utxo) -> Result<Option<String>, WError> {
52    if let Some(ref_script) = &utxo.reference_script {
53        match ref_script.r#type {
54            ScriptVersion::Native => {
55                let script: NativeScript =
56                    NativeScript::from_json(&serde_json::json!(&ref_script.json).to_string())
57                        .map_err(WError::from_err("json to string"))?;
58                let script_ref = to_script_ref(&ScriptType::Native(script));
59                Ok(Some(
60                    script_ref
61                        .native_script()
62                        .ok_or_else(WError::from_opt("resolve_script", "script_ref"))?
63                        .to_hex(),
64                ))
65            }
66            ScriptVersion::Plutusv1 => {
67                let script_hex = &ref_script.bytes;
68                let normalized = normalize_plutus_script(script_hex)
69                    .map_err(WError::from_err("normalize_plutus_script"))?;
70                let script: PlutusScript = PlutusScript::from_hex_with_version(
71                    &normalized,
72                    &csl::Language::new_plutus_v1(),
73                )
74                .map_err(WError::from_err("from_hex_with_version"))?;
75                let script_ref = to_script_ref(&ScriptType::Plutus(script));
76                Ok(Some(
77                    script_ref
78                        .plutus_script()
79                        .ok_or_else(WError::from_opt("resolve_script", "script_ref"))?
80                        .to_hex(),
81                ))
82            }
83            ScriptVersion::Plutusv2 => {
84                let script_hex = &ref_script.bytes;
85                let normalized = normalize_plutus_script(script_hex)
86                    .map_err(WError::from_err("normalize_plutus_script"))?;
87                let script: PlutusScript = PlutusScript::from_hex_with_version(
88                    &normalized,
89                    &csl::Language::new_plutus_v2(),
90                )
91                .map_err(WError::from_err("from_hex_with_version"))?;
92                let script_ref = to_script_ref(&ScriptType::Plutus(script));
93                Ok(Some(
94                    script_ref
95                        .plutus_script()
96                        .ok_or_else(WError::from_opt("resolve_script", "script_ref"))?
97                        .to_hex(),
98                ))
99            }
100            ScriptVersion::Plutusv3 => {
101                let script_hex = &ref_script.bytes;
102                let normalized = normalize_plutus_script(script_hex)
103                    .map_err(WError::from_err("normalize_plutus_script"))?;
104                let script: PlutusScript = PlutusScript::from_hex_with_version(
105                    &normalized,
106                    &csl::Language::new_plutus_v3(),
107                )
108                .map_err(WError::from_err("from_hex_with_version"))?;
109                let script_ref = to_script_ref(&ScriptType::Plutus(script));
110                Ok(Some(
111                    script_ref
112                        .plutus_script()
113                        .ok_or_else(WError::from_opt("resolve_script", "script_ref"))?
114                        .to_hex(),
115                ))
116            }
117        }
118    } else {
119        Ok(None)
120        // TODO: handle none
121    }
122}
123
124pub fn normalize_plutus_script(script_hex: &str) -> Result<String, WError> {
125    apply_double_cbor_encoding(script_hex)
126}
127
128pub fn to_script_ref(script: &ScriptType) -> ScriptRef {
129    match script {
130        ScriptType::Plutus(plutus) => ScriptRef::new_plutus_script(plutus),
131        ScriptType::Native(native) => ScriptRef::new_native_script(native),
132    }
133}