whisky_csl/tx_parser/
utxo_converter.rs1use whisky_common::{
2 DatumSource, InlineDatumSource, PubKeyTxIn, RefTxIn, ScriptSource, ScriptTxIn,
3 ScriptTxInParameter, SimpleScriptTxIn, SimpleScriptTxInParameter, TxIn, TxInParameter, UTxO,
4 WError,
5};
6
7use cardano_serialization_lib as csl;
8
9use super::context::{ParserContext, RedeemerIndex, Script};
10
11pub fn utxo_to_ref_tx_in(
12 tx_input: &csl::TransactionInput,
13 context: &ParserContext,
14) -> Result<RefTxIn, WError> {
15 let utxo = context.resolved_utxos.get(tx_input).ok_or_else(|| {
16 WError::new(
17 "utxo_to_ref_tx_in",
18 &format!("Failed to find UTxO for input: {:?}", tx_input),
19 )
20 })?;
21 let tx_in_param = RefTxIn {
22 tx_hash: tx_input.transaction_id().to_hex(),
23 tx_index: tx_input.index(),
24 script_size: utxo
25 .output
26 .script_ref
27 .as_ref()
28 .map(|script_ref| script_ref.len() / 2),
29 };
30 Ok(tx_in_param)
31}
32
33pub fn utxo_to_pub_key_tx_in(
34 tx_input: &csl::TransactionInput,
35 context: &ParserContext,
36) -> Result<PubKeyTxIn, WError> {
37 let utxo = context.resolved_utxos.get(tx_input).ok_or_else(|| {
38 WError::new(
39 "utxo_to_pub_key_tx_in",
40 &format!("Failed to find UTxO for input: {:?}", tx_input),
41 )
42 })?;
43 let tx_in_param = PubKeyTxIn {
44 tx_in: TxInParameter {
45 tx_hash: tx_input.transaction_id().to_hex(),
46 tx_index: tx_input.index(),
47 amount: Some(utxo.output.amount.clone()),
48 address: Some(utxo.output.address.clone()),
49 },
50 };
51 Ok(tx_in_param)
52}
53
54pub fn utxo_to_tx_in(
55 tx_input: &csl::TransactionInput,
56 context: &ParserContext,
57 index: usize,
58) -> Result<TxIn, WError> {
59 let utxo = context.resolved_utxos.get(tx_input).ok_or_else(|| {
60 WError::new(
61 "utxo_to_tx_in",
62 &format!("Failed to find UTxO for input: {:?}", tx_input),
63 )
64 })?;
65
66 let tx_in_param = TxInParameter {
67 tx_hash: utxo.input.tx_hash.clone(),
68 tx_index: utxo.input.output_index,
69 amount: Some(utxo.output.amount.clone()),
70 address: Some(utxo.output.address.clone()),
71 };
72
73 let address = csl::Address::from_bech32(&utxo.output.address).map_err(|e| {
74 WError::new(
75 "utxo_to_tx_in",
76 &format!("Failed to parse address: {:?}", e),
77 )
78 })?;
79 let payment_cred = address
80 .payment_cred()
81 .ok_or_else(|| WError::new("utxo_to_tx_in", "Failed to get payment credential"))?;
82
83 if payment_cred.to_keyhash().is_some() {
84 return Ok(TxIn::PubKeyTxIn(PubKeyTxIn { tx_in: tx_in_param }));
85 };
86
87 if let Some(script_hash) = payment_cred.to_scripthash() {
88 if let Some(script) = context.script_witness.scripts.get(&script_hash) {
89 match script {
90 Script::ProvidedNative(native_script) => {
91 return Ok(TxIn::SimpleScriptTxIn(SimpleScriptTxIn {
92 tx_in: tx_in_param,
93 simple_script_tx_in: SimpleScriptTxInParameter::ProvidedSimpleScriptSource(
94 native_script.clone(),
95 ),
96 }));
97 }
98 Script::ProvidedPlutus(plutus_script) => {
99 let datum_source = get_datum_for_output(utxo, context);
100
101 let script_source =
102 Some(ScriptSource::ProvidedScriptSource(plutus_script.clone()));
103
104 let redeemer = context
105 .script_witness
106 .redeemers
107 .get(&RedeemerIndex::Spend(index))
108 .cloned();
109
110 return Ok(TxIn::ScriptTxIn(ScriptTxIn {
111 tx_in: tx_in_param,
112 script_tx_in: ScriptTxInParameter {
113 script_source,
114 datum_source,
115 redeemer,
116 },
117 }));
118 }
119 Script::ReferencedNative(inline_script_source) => {
120 return Ok(TxIn::SimpleScriptTxIn(SimpleScriptTxIn {
121 tx_in: tx_in_param,
122 simple_script_tx_in: SimpleScriptTxInParameter::InlineSimpleScriptSource(
123 inline_script_source.clone(),
124 ),
125 }))
126 }
127 Script::ReferencedPlutus(inline_script_source) => {
128 let datum_source = get_datum_for_output(utxo, context);
129
130 let script_source = Some(ScriptSource::InlineScriptSource(
131 inline_script_source.clone(),
132 ));
133
134 let redeemer = context
135 .script_witness
136 .redeemers
137 .get(&RedeemerIndex::Spend(index))
138 .cloned();
139
140 return Ok(TxIn::ScriptTxIn(ScriptTxIn {
141 tx_in: tx_in_param,
142 script_tx_in: ScriptTxInParameter {
143 script_source,
144 datum_source,
145 redeemer,
146 },
147 }));
148 }
149 }
150 } else {
151 return Ok(TxIn::PubKeyTxIn(PubKeyTxIn { tx_in: tx_in_param }));
152 }
153 } else {
154 return Ok(TxIn::PubKeyTxIn(PubKeyTxIn { tx_in: tx_in_param }));
155 }
156}
157
158fn get_datum_for_output(utxo: &UTxO, context: &ParserContext) -> Option<DatumSource> {
159 if let Some(_) = &utxo.output.plutus_data {
160 Some(DatumSource::InlineDatumSource(InlineDatumSource {
161 tx_hash: utxo.input.tx_hash.clone(),
162 tx_index: utxo.input.output_index,
163 }))
164 } else if let Some(datum_hash) = &utxo.output.data_hash {
165 context.script_witness.datums.get(datum_hash).cloned()
166 } else {
167 None
168 }
169}