whisky_provider/maestro/
evaluator.rs

1use async_trait::async_trait;
2use whisky_csl::{calculate_tx_hash, CSLParser};
3
4use uplc::tx::SlotConfig;
5use whisky_common::models::{Network, UTxO};
6
7use whisky_common::*;
8
9use super::*;
10
11#[derive(Serialize)]
12pub struct AdditionalUtxo {
13    pub tx_hash: String,
14    pub index: u32,
15    pub txout_cbor: String,
16}
17
18#[derive(Serialize)]
19pub struct EvaluateTx {
20    cbor: String,
21    additional_utxos: Vec<AdditionalUtxo>,
22}
23
24#[async_trait]
25impl Evaluator for MaestroProvider {
26    async fn evaluate_tx(
27        &self,
28        tx: &str,
29        _inputs: &[UTxO], // TODO: parse this also into additional_txs
30        additional_txs: &[String],
31        _network: &Network,
32        _slot_config: &SlotConfig,
33    ) -> Result<Vec<Action>, WError> {
34        let tx_out_cbors: Vec<AdditionalUtxo> = additional_txs
35            .iter()
36            .flat_map(|tx| {
37                let tx_hash = calculate_tx_hash(tx).unwrap();
38                let utxos = CSLParser::extract_output_cbors(tx).unwrap();
39                utxos
40                    .into_iter()
41                    .enumerate()
42                    .map(|(index, txout_cbor)| AdditionalUtxo {
43                        tx_hash: tx_hash.clone(),
44                        index: index as u32,
45                        txout_cbor,
46                    })
47                    .collect::<Vec<AdditionalUtxo>>()
48            })
49            .collect();
50
51        let url = "/transactions/evaluate";
52        let body = EvaluateTx {
53            cbor: tx.to_string(),
54            additional_utxos: tx_out_cbors,
55        };
56
57        let resp = self
58            .maestro_client
59            .post(url, &body)
60            .await
61            .map_err(WError::from_err("Maestro - evaluate_tx"))?;
62
63        let result: Vec<Action> = serde_json::from_str::<Vec<RedeemerEvaluation>>(&resp)
64            .map_err(WError::from_err("Maestro - evaluate_tx"))?
65            .iter()
66            .map(|r: &RedeemerEvaluation| Action {
67                index: r.redeemer_index as u32,
68                budget: Budget {
69                    mem: r.ex_units.mem as u64,
70                    steps: r.ex_units.steps as u64,
71                },
72                tag: match r.redeemer_tag.as_str() {
73                    "spend" => RedeemerTag::Spend,
74                    "mint" => RedeemerTag::Mint,
75                    "cert" => RedeemerTag::Cert,
76                    "wdrl" => RedeemerTag::Reward,
77                    _ => panic!("Unknown redeemer tag from maestro service"),
78                },
79            })
80            .collect();
81        Ok(result)
82    }
83}