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                let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
60                Ok(result)
61            }
62            ScriptVersion::Plutusv1 => {
63                let script_hex = &ref_script.bytes;
64                let normalized = normalize_plutus_script(script_hex)
65                    .map_err(WError::from_err("normalize_plutus_script"))?;
66                let script: PlutusScript = PlutusScript::from_hex_with_version(
67                    &normalized,
68                    &csl::Language::new_plutus_v1(),
69                )
70                .map_err(WError::from_err("from_hex_with_version"))?;
71                let script_ref = to_script_ref(&ScriptType::Plutus(script));
72                let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
73                Ok(result)
74            }
75            ScriptVersion::Plutusv2 => {
76                let script_hex = &ref_script.bytes;
77                let normalized = normalize_plutus_script(script_hex)
78                    .map_err(WError::from_err("normalize_plutus_script"))?;
79                let script: PlutusScript = PlutusScript::from_hex_with_version(
80                    &normalized,
81                    &csl::Language::new_plutus_v2(),
82                )
83                .map_err(WError::from_err("from_hex_with_version"))?;
84                let script_ref = to_script_ref(&ScriptType::Plutus(script));
85                let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
86                Ok(result)
87            }
88            ScriptVersion::Plutusv3 => {
89                let script_hex = &ref_script.bytes;
90                let normalized = normalize_plutus_script(script_hex)
91                    .map_err(WError::from_err("normalize_plutus_script"))?;
92                let script: PlutusScript = PlutusScript::from_hex_with_version(
93                    &normalized,
94                    &csl::Language::new_plutus_v3(),
95                )
96                .map_err(WError::from_err("from_hex_with_version"))?;
97                let script_ref = to_script_ref(&ScriptType::Plutus(script));
98                let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
99                Ok(result)
100            }
101        }
102    } else {
103        Ok(None)
104        // TODO: handle none
105    }
106}
107
108pub fn normalize_plutus_script(script_hex: &str) -> Result<String, WError> {
109    apply_double_cbor_encoding(script_hex)
110}
111
112pub fn to_script_ref(script: &ScriptType) -> ScriptRef {
113    match script {
114        ScriptType::Plutus(plutus) => ScriptRef::new_plutus_script(plutus),
115        ScriptType::Native(native) => ScriptRef::new_native_script(native),
116    }
117}