whisky_csl/tx_parser/
withdrawals.rs

1use super::context::ParserContext;
2use super::context::RedeemerIndex;
3use super::context::Script;
4use super::CSLParser;
5use cardano_serialization_lib as csl;
6use whisky_common::{
7    PlutusScriptWithdrawal, PubKeyWithdrawal, ScriptSource, SimpleScriptSource,
8    SimpleScriptWithdrawal, WError, Withdrawal,
9};
10
11impl CSLParser {
12    pub fn get_withdrawals(&self) -> &Vec<Withdrawal> {
13        &self.tx_body.withdrawals
14    }
15
16    pub(super) fn extract_withdrawals(&mut self) -> Result<(), WError> {
17        let withdrawals = self.csl_tx_body.withdrawals();
18        if let Some(withdrawals) = withdrawals {
19            self.tx_body.withdrawals = csl_withdrawals_to_withdrawals(&withdrawals, &self.context)?;
20        }
21        Ok(())
22    }
23}
24
25pub fn csl_withdrawals_to_withdrawals(
26    withdrawals: &csl::Withdrawals,
27    context: &ParserContext,
28) -> Result<Vec<Withdrawal>, WError> {
29    let mut result = Vec::new();
30    let withdrawals_keys = withdrawals.keys();
31    let len = withdrawals_keys.len();
32    for i in 0..len {
33        let reward_address = withdrawals_keys.get(i);
34        let reward_address_bech32 = reward_address.to_address().to_bech32(None).map_err(|e| {
35            WError::new(
36                "csl_withdrawals_to_withdrawals",
37                &format!("Failed to convert address to bech32: {:?}", e),
38            )
39        })?;
40        let withdrawal_amount = withdrawals.get(&reward_address);
41        if let Some(withdrawal_amount) = withdrawal_amount {
42            let coin = withdrawal_amount.to_str().parse::<u64>().map_err(|e| {
43                WError::new(
44                    "csl_withdrawals_to_withdrawals",
45                    &format!("Failed to parse withdrawal amount: {:?}", e),
46                )
47            })?;
48
49            let redeemer = context
50                .script_witness
51                .redeemers
52                .get(&RedeemerIndex::Reward(i));
53
54            let script_hash = reward_address.payment_cred().to_scripthash();
55            let script = script_hash
56                .map(|sh| context.script_witness.scripts.get(&sh))
57                .flatten();
58
59            match script {
60                Some(script) => match script {
61                    Script::ProvidedPlutus(plutus_script) => {
62                        result.push(Withdrawal::PlutusScriptWithdrawal(PlutusScriptWithdrawal {
63                            address: reward_address_bech32,
64                            coin,
65                            script_source: Some(ScriptSource::ProvidedScriptSource(
66                                plutus_script.clone(),
67                            )),
68                            redeemer: redeemer.cloned(),
69                        }));
70                    }
71                    Script::ProvidedNative(native_script) => {
72                        result.push(Withdrawal::SimpleScriptWithdrawal(SimpleScriptWithdrawal {
73                            address: reward_address_bech32,
74                            coin,
75                            script_source: Some(SimpleScriptSource::ProvidedSimpleScriptSource(
76                                native_script.clone(),
77                            )),
78                        }));
79                    }
80                    Script::ReferencedNative(inline_simple_script_source) => {
81                        result.push(Withdrawal::SimpleScriptWithdrawal(SimpleScriptWithdrawal {
82                            address: reward_address_bech32,
83                            coin,
84                            script_source: Some(SimpleScriptSource::InlineSimpleScriptSource(
85                                inline_simple_script_source.clone(),
86                            )),
87                        }));
88                    }
89                    Script::ReferencedPlutus(inline_script_source) => {
90                        result.push(Withdrawal::PlutusScriptWithdrawal(PlutusScriptWithdrawal {
91                            address: reward_address_bech32,
92                            coin,
93                            script_source: Some(ScriptSource::InlineScriptSource(
94                                inline_script_source.clone(),
95                            )),
96                            redeemer: redeemer.cloned(),
97                        }));
98                    }
99                },
100                None => {
101                    result.push(Withdrawal::PubKeyWithdrawal(PubKeyWithdrawal {
102                        address: reward_address_bech32,
103                        coin,
104                    }));
105                }
106            }
107        }
108    }
109
110    Ok(result)
111}