cardano_serialization_lib/builders/
voting_proposal_builder.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use crate::*;
use std::collections::BTreeMap;

#[wasm_bindgen]
#[derive(Clone, Debug)]
pub struct VotingProposalBuilder {
    proposals: BTreeMap<VotingProposal, Option<ScriptWitnessType>>,
}

#[wasm_bindgen]
impl VotingProposalBuilder {
    pub fn new() -> Self {
        Self {
            proposals: BTreeMap::new(),
        }
    }

    pub fn add(&mut self, proposal: &VotingProposal) -> Result<(), JsError> {
        if proposal.has_script_hash() {
            return Err(JsError::from_str("Proposal has a script hash. Use add_with_plutus_witness instead."));
        }
        self.proposals.insert(proposal.clone(), None);
        Ok(())
    }

    pub fn add_with_plutus_witness(
        &mut self,
        proposal: &VotingProposal,
        witness: &PlutusWitness,
    ) -> Result<(), JsError> {
        self.proposals.insert(
            proposal.clone(),
            Some(ScriptWitnessType::PlutusScriptWitness(witness.clone())),
        );
        Ok(())
    }

    pub fn get_plutus_witnesses(&self) -> PlutusWitnesses {
        let tag = RedeemerTag::new_voting_proposal();
        let mut scripts = PlutusWitnesses::new();
        for (i, (_, script_wit)) in self.proposals.iter().enumerate() {
            if let Some(ScriptWitnessType::PlutusScriptWitness(s)) = script_wit {
                let index = BigNum::from(i);
                scripts.add(&s.clone_with_redeemer_index_and_tag(&index, &tag));
            }
        }
        scripts
    }

    pub fn get_ref_inputs(&self) -> TransactionInputs {
        let mut inputs = Vec::new();
        for (_, script_wit) in &self.proposals {
            match script_wit {
                Some(script_witness) => {
                    if let Some(input) = script_witness.get_script_ref_input() {
                        inputs.push(input);
                    }
                    if let Some(input) = script_witness.get_datum_ref_input() {
                        inputs.push(input);
                    }
                }
                None => {}
            }
        }
        TransactionInputs::from_vec(inputs)
    }

    pub(crate) fn get_total_deposit(&self) -> Result<Coin, JsError> {
        self.proposals.iter().fold(
            Ok(Coin::zero()),
            |acc: Result<Coin, JsError>, (proposal, _)| {
                acc.and_then(|acc| {
                    acc.checked_add(&proposal.deposit)
                        .or_else(|_| Err(JsError::from_str("Overflow when calculating total deposit")))
                })
            },
        )
    }

    pub(crate) fn get_used_plutus_lang_versions(&self) -> BTreeSet<Language> {
        let mut used_langs = BTreeSet::new();
        for (_, script_wit) in &self.proposals {
            if let Some(ScriptWitnessType::PlutusScriptWitness(s)) = script_wit {
                used_langs.insert(s.script.language());
            }
        }
        used_langs
    }

    //return only ref inputs that are script refs with added size
    //used for calculating the fee for the transaction
    //another ref input and also script ref input without size are filtered out
    pub(crate) fn get_script_ref_inputs_with_size(
        &self,
    ) -> impl Iterator<Item = (&TransactionInput, usize)> {
        self.proposals.iter()
            .filter_map(|(_, script_wit)| script_wit.as_ref())
            .filter_map(|script_wit| script_wit.get_script_ref_input_with_size())
    }

    pub fn has_plutus_scripts(&self) -> bool {
        for (_, script_wit) in &self.proposals {
            if let Some(ScriptWitnessType::PlutusScriptWitness(_)) = script_wit {
                return true;
            }
        }
        false
    }

    pub fn build(&self) -> VotingProposals {
        let mut proposals = Vec::new();
        for (voter, _) in &self.proposals {
            proposals.push(voter.clone());
        }
        VotingProposals::from_vec(proposals)
    }
}