whisky_csl/tx_parser/
votes.rs

1use whisky_common::{
2    Anchor, Credential, RefTxIn, ScriptSource, ScriptVote, SimpleScriptSource, SimpleScriptVote,
3    Vote, VoteKind, VoteType, Voter, VotingProcedure, WError,
4};
5
6use super::{
7    context::{ParserContext, RedeemerIndex, Script},
8    CSLParser,
9};
10use cardano_serialization_lib as csl;
11
12impl CSLParser {
13    pub fn get_votes(&self) -> &Vec<Vote> {
14        &self.tx_body.votes
15    }
16
17    pub(super) fn extract_votes(&mut self) -> Result<(), WError> {
18        let votes = self.csl_tx_body.voting_procedures();
19        if let Some(votes) = votes {
20            self.tx_body.votes = csl_votes_to_votes(&votes, &self.context)?;
21        }
22        Ok(())
23    }
24}
25
26pub fn csl_votes_to_votes(
27    votes: &csl::VotingProcedures,
28    context: &ParserContext,
29) -> Result<Vec<Vote>, WError> {
30    let mut result = Vec::new();
31    let voters = votes.get_voters();
32    let len = voters.len();
33
34    for i in 0..len {
35        let csl_voter = voters.get(i).ok_or_else(|| {
36            WError::new(
37                "csl_votes_to_votes",
38                &format!("Failed to get voter at index {}", i),
39            )
40        })?;
41        let voter_kind = csl_voter.kind();
42        let governance_action_ids = votes.get_governance_action_ids_by_voter(&csl_voter);
43        let len = governance_action_ids.len();
44
45        let voter_script_hash: Option<csl::ScriptHash>;
46
47        let voter = match voter_kind {
48            csl::VoterKind::ConstitutionalCommitteeHotKeyHash => {
49                let key_hash = csl_voter
50                    .to_constitutional_committee_hot_credential()
51                    .ok_or_else(|| {
52                        WError::new(
53                            "csl_votes_to_votes",
54                            "Failed to get constitutional committee hot credential",
55                        )
56                    })?
57                    .to_keyhash()
58                    .ok_or_else(|| WError::new("csl_votes_to_votes", "Failed to get key hash"))?;
59                voter_script_hash = None;
60                Voter::ConstitutionalCommitteeHotCred(Credential::KeyHash(key_hash.to_hex()))
61            }
62            csl::VoterKind::ConstitutionalCommitteeHotScriptHash => {
63                let script_hash = csl_voter
64                    .to_constitutional_committee_hot_credential()
65                    .ok_or_else(|| {
66                        WError::new(
67                            "csl_votes_to_votes",
68                            "Failed to get constitutional committee hot credential",
69                        )
70                    })?
71                    .to_scripthash()
72                    .ok_or_else(|| {
73                        WError::new("csl_votes_to_votes", "Failed to get script hash")
74                    })?;
75                voter_script_hash = Some(script_hash.clone());
76                Voter::ConstitutionalCommitteeHotCred(Credential::ScriptHash(script_hash.to_hex()))
77            }
78            csl::VoterKind::DRepKeyHash => {
79                let credential = csl_voter.to_drep_credential().ok_or_else(|| {
80                    WError::new("csl_votes_to_votes", "Failed to get drep credential")
81                })?;
82                let csl_drep_credential = csl::DRep::new_from_credential(&credential);
83                voter_script_hash = None;
84                Voter::DRepId(csl_drep_credential.to_bech32(true).map_err(|e| {
85                    WError::new(
86                        "csl_votes_to_votes",
87                        &format!("Failed to convert drep to bech32: {:?}", e),
88                    )
89                })?)
90            }
91            csl::VoterKind::DRepScriptHash => {
92                let credential = csl_voter.to_drep_credential().ok_or_else(|| {
93                    WError::new("csl_votes_to_votes", "Failed to get drep credential")
94                })?;
95                let csl_drep_credential = csl::DRep::new_from_credential(&credential);
96                voter_script_hash = csl_drep_credential.to_script_hash();
97                Voter::DRepId(csl_drep_credential.to_bech32(true).map_err(|e| {
98                    WError::new(
99                        "csl_votes_to_votes",
100                        &format!("Failed to convert drep to bech32: {:?}", e),
101                    )
102                })?)
103            }
104            csl::VoterKind::StakingPoolKeyHash => {
105                let key_hash = csl_voter.to_stake_pool_key_hash().ok_or_else(|| {
106                    WError::new("csl_votes_to_votes", "Failed to get stake pool key hash")
107                })?;
108                voter_script_hash = None;
109                Voter::StakingPoolKeyHash(key_hash.to_hex())
110            }
111        };
112
113        for j in 0..len {
114            let gov_action_id = governance_action_ids.get(j).ok_or_else(|| {
115                WError::new(
116                    "csl_votes_to_votes",
117                    &format!("Failed to get governance action ID at index {}", j),
118                )
119            })?;
120            let voting_procedure = votes.get(&csl_voter, &gov_action_id).ok_or_else(|| {
121                WError::new(
122                    "csl_votes_to_votes",
123                    &format!(
124                        "Failed to get voting procedure for governance action ID: {:?}",
125                        gov_action_id
126                    ),
127                )
128            })?;
129
130            let gov_action_id = RefTxIn {
131                tx_hash: gov_action_id.transaction_id().to_hex(),
132                tx_index: gov_action_id.index(),
133                script_size: None,
134            };
135
136            let vote_kind = match voting_procedure.vote_kind() {
137                csl::VoteKind::No => VoteKind::No,
138                csl::VoteKind::Yes => VoteKind::Yes,
139                csl::VoteKind::Abstain => VoteKind::Abstain,
140            };
141
142            let anchor = if let Some(anchor) = voting_procedure.anchor() {
143                Some(Anchor {
144                    anchor_url: anchor.url().url(),
145                    anchor_data_hash: anchor.anchor_data_hash().to_hex(),
146                })
147            } else {
148                None
149            };
150
151            let voting_procedure = VotingProcedure { vote_kind, anchor };
152
153            let vote_type = VoteType {
154                voter: voter.clone(),
155                gov_action_id,
156                voting_procedure,
157            };
158
159            if let Some(script_hash) = &voter_script_hash {
160                if let Some(script) = context.script_witness.scripts.get(&script_hash) {
161                    match script {
162                        Script::ProvidedNative(native_script) => {
163                            result.push(Vote::SimpleScriptVote(SimpleScriptVote {
164                                vote: vote_type,
165                                simple_script_source: Some(
166                                    SimpleScriptSource::ProvidedSimpleScriptSource(
167                                        native_script.clone(),
168                                    ),
169                                ),
170                            }));
171                        }
172                        Script::ProvidedPlutus(plutus_script) => {
173                            let redeemer = context
174                                .script_witness
175                                .redeemers
176                                .get(&RedeemerIndex::Vote(i))
177                                .cloned();
178                            result.push(Vote::ScriptVote(ScriptVote {
179                                vote: vote_type,
180                                redeemer,
181                                script_source: Some(ScriptSource::ProvidedScriptSource(
182                                    plutus_script.clone(),
183                                )),
184                            }));
185                        }
186                        Script::ReferencedNative(inline_script) => {
187                            result.push(Vote::SimpleScriptVote(SimpleScriptVote {
188                                vote: vote_type,
189                                simple_script_source: Some(
190                                    SimpleScriptSource::InlineSimpleScriptSource(
191                                        inline_script.clone(),
192                                    ),
193                                ),
194                            }));
195                        }
196                        Script::ReferencedPlutus(inline_script) => {
197                            let redeemer = context
198                                .script_witness
199                                .redeemers
200                                .get(&RedeemerIndex::Vote(i))
201                                .cloned();
202                            result.push(Vote::ScriptVote(ScriptVote {
203                                vote: vote_type,
204                                redeemer,
205                                script_source: Some(ScriptSource::InlineScriptSource(
206                                    inline_script.clone(),
207                                )),
208                            }));
209                        }
210                    }
211                } else {
212                    result.push(Vote::BasicVote(vote_type));
213                }
214            } else {
215                result.push(Vote::BasicVote(vote_type));
216            }
217        }
218    }
219    Ok(result)
220}