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 let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
66 Ok(result)
67 }
68 Type::PlutusV1 => {
69 let script_cbor = self
70 .blockfrost_client
71 .fetch_plutus_script_cbor(script_hash)
72 .await?;
73
74 let normalized = normalize_plutus_script(&script_cbor)
75 .map_err(WError::from_err("normalize_plutus_script"))?;
76 let script: PlutusScript = PlutusScript::from_hex_with_version(
77 &normalized,
78 &csl::Language::new_plutus_v1(),
79 )
80 .map_err(WError::from_err("from_hex_with_version"))?;
81 let script_ref: ScriptRef = to_script_ref(&ScriptType::Plutus(script));
82 let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
83
84 Ok(result)
85 }
86 Type::PlutusV2 => {
87 let script_cbor = self
88 .blockfrost_client
89 .fetch_plutus_script_cbor(script_hash)
90 .await?;
91
92 let normalized = normalize_plutus_script(&script_cbor)
93 .map_err(WError::from_err("normalize_plutus_script"))?;
94 let script: PlutusScript = PlutusScript::from_hex_with_version(
95 &normalized,
96 &csl::Language::new_plutus_v2(),
97 )
98 .map_err(WError::from_err("from_hex_with_version"))?;
99 let script_ref: ScriptRef = to_script_ref(&ScriptType::Plutus(script));
100 let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
101
102 Ok(result)
103 }
104 Type::PlutusV3 => {
105 let script_cbor = self
106 .blockfrost_client
107 .fetch_plutus_script_cbor(script_hash)
108 .await?;
109
110 let normalized = normalize_plutus_script(&script_cbor)
111 .map_err(WError::from_err("normalize_plutus_script"))?;
112 let script: PlutusScript = PlutusScript::from_hex_with_version(
113 &normalized,
114 &csl::Language::new_plutus_v3(),
115 )
116 .map_err(WError::from_err("from_hex_with_version"))?;
117 let script_ref: ScriptRef = to_script_ref(&ScriptType::Plutus(script));
118 let result = Some(hex::encode(script_ref.to_unwrapped_bytes()));
119
120 Ok(result)
121 }
122 }
123 }
124}
125
126pub fn normalize_plutus_script(script_hex: &str) -> Result<String, WError> {
127 apply_double_cbor_encoding(script_hex)
128}
129
130pub fn to_script_ref(script: &ScriptType) -> ScriptRef {
131 match script {
132 ScriptType::Plutus(plutus) => ScriptRef::new_plutus_script(plutus),
133 ScriptType::Native(native) => ScriptRef::new_native_script(native),
134 }
135}