whisky_provider/blockfrost/utils/
utxo_utils.rs1use 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::blockfrost::{
11 models::{utxo::BlockfrostUtxo, Script, Type},
12 BlockfrostProvider,
13};
14
15#[derive(Debug, Clone)]
16pub enum ScriptType {
17 Plutus(PlutusScript),
18 Native(NativeScript),
19}
20
21impl BlockfrostProvider {
22 pub async fn to_utxo(&self, utxo: &BlockfrostUtxo) -> Result<UTxO, WError> {
23 let utxo = UTxO {
24 input: UtxoInput {
25 output_index: utxo.output_index as u32,
26 tx_hash: utxo.tx_hash.clone(),
27 },
28 output: UtxoOutput {
29 address: utxo.address.clone(),
30 amount: utxo
31 .amount
32 .iter()
33 .map(|asset| Asset::new(asset.unit.clone(), asset.quantity.to_string()))
34 .collect(),
35 data_hash: utxo.data_hash.clone(),
36 plutus_data: utxo.inline_datum.clone(),
37 script_ref: match &utxo.reference_script_hash {
38 Some(s) => self
39 .resolve_script_ref(s)
40 .await
41 .map_err(WError::from_err("resolve_script_ref"))?,
42 None => None,
43 },
44 script_hash: utxo.reference_script_hash.clone(),
45 },
46 };
47 Ok(utxo)
48 }
49
50 pub async fn resolve_script_ref(&self, script_hash: &str) -> Result<Option<String>, WError> {
51 let script: Script = self
52 .blockfrost_client
53 .fetch_specific_script(script_hash)
54 .await?;
55 match script.r#type {
56 Type::Timelock => {
57 let script_json = self
58 .blockfrost_client
59 .fetch_native_script_json(script_hash)
60 .await?;
61 let script: NativeScript =
62 NativeScript::from_json(&serde_json::json!(script_json).to_string())
63 .map_err(WError::from_err("json to string"))?;
64 let script_ref = to_script_ref(&ScriptType::Native(script));
65 Ok(Some(
66 script_ref
67 .native_script()
68 .ok_or_else(WError::from_opt("resolve_script_ref", "script_ref"))?
69 .to_hex(),
70 ))
71 }
72 Type::PlutusV1 => {
73 let script_cbor = self
74 .blockfrost_client
75 .fetch_plutus_script_cbor(script_hash)
76 .await?;
77
78 let normalized = normalize_plutus_script(&script_cbor)
79 .map_err(WError::from_err("normalize_plutus_script"))?;
80 let script: PlutusScript = PlutusScript::from_hex_with_version(
81 &normalized,
82 &csl::Language::new_plutus_v1(),
83 )
84 .map_err(WError::from_err("from_hex_with_version"))?;
85 let script_ref: ScriptRef = to_script_ref(&ScriptType::Plutus(script));
86 let result = Some(
87 script_ref
88 .plutus_script()
89 .ok_or_else(WError::from_opt("resolve_script_ref", "script_ref"))?
90 .to_hex(),
91 );
92
93 Ok(result)
94 }
95 Type::PlutusV2 => {
96 let script_cbor = self
97 .blockfrost_client
98 .fetch_plutus_script_cbor(script_hash)
99 .await?;
100
101 let normalized = normalize_plutus_script(&script_cbor)
102 .map_err(WError::from_err("normalize_plutus_script"))?;
103 let script: PlutusScript = PlutusScript::from_hex_with_version(
104 &normalized,
105 &csl::Language::new_plutus_v2(),
106 )
107 .map_err(WError::from_err("from_hex_with_version"))?;
108 let script_ref: ScriptRef = to_script_ref(&ScriptType::Plutus(script));
109 let result = Some(
110 script_ref
111 .plutus_script()
112 .ok_or_else(WError::from_opt("resolve_script_ref", "script_ref"))?
113 .to_hex(),
114 );
115
116 Ok(result)
117 }
118 Type::PlutusV3 => {
119 let script_cbor = self
120 .blockfrost_client
121 .fetch_plutus_script_cbor(script_hash)
122 .await?;
123
124 let normalized = normalize_plutus_script(&script_cbor)
125 .map_err(WError::from_err("normalize_plutus_script"))?;
126 let script: PlutusScript = PlutusScript::from_hex_with_version(
127 &normalized,
128 &csl::Language::new_plutus_v3(),
129 )
130 .map_err(WError::from_err("from_hex_with_version"))?;
131 let script_ref: ScriptRef = to_script_ref(&ScriptType::Plutus(script));
132 let result = Some(
133 script_ref
134 .plutus_script()
135 .ok_or_else(WError::from_opt("resolve_script_ref", "script_ref"))?
136 .to_hex(),
137 );
138
139 Ok(result)
140 }
141 }
142 }
143}
144
145pub fn normalize_plutus_script(script_hex: &str) -> Result<String, WError> {
146 apply_double_cbor_encoding(script_hex)
147}
148
149pub fn to_script_ref(script: &ScriptType) -> ScriptRef {
150 match script {
151 ScriptType::Plutus(plutus) => ScriptRef::new_plutus_script(plutus),
152 ScriptType::Native(native) => ScriptRef::new_native_script(native),
153 }
154}