1use crate::*;
2use cardano_serialization_lib as csl;
3use whisky_common::*;
4
5#[derive(Clone, Debug)]
6pub struct CoreCSL {
7 pub tx_hex: String,
8 pub tx_builder: csl::TransactionBuilder,
9 pub tx_inputs_builder: csl::TxInputsBuilder,
10 pub collateral_builder: csl::TxInputsBuilder,
11 pub mint_builder: csl::MintBuilder,
12 pub certificates_builder: csl::CertificatesBuilder,
13 pub vote_builder: csl::VotingBuilder,
14 pub tx_withdrawals_builder: csl::WithdrawalsBuilder,
15 pub protocol_params: Protocol,
16}
17
18impl CoreCSL {
19 pub fn new(params: Option<Protocol>) -> Result<CoreCSL, WError> {
20 Ok(CoreCSL {
21 tx_hex: String::new(),
22 tx_builder: build_tx_builder(params.clone())
23 .map_err(WError::add_err_trace("CoreCSL - new - build_tx_builder"))?,
24 tx_inputs_builder: csl::TxInputsBuilder::new(),
25 collateral_builder: csl::TxInputsBuilder::new(),
26 mint_builder: csl::MintBuilder::new(),
27 certificates_builder: csl::CertificatesBuilder::new(),
28 vote_builder: csl::VotingBuilder::new(),
29 tx_withdrawals_builder: csl::WithdrawalsBuilder::new(),
30 protocol_params: params.unwrap_or_default(),
31 })
32 }
33
34 pub fn reset_after_build(&mut self) {
35 self.tx_builder = build_tx_builder(Some(self.protocol_params.clone())).unwrap();
36 self.tx_inputs_builder = csl::TxInputsBuilder::new();
37 self.collateral_builder = csl::TxInputsBuilder::new();
38 self.mint_builder = csl::MintBuilder::new();
39 self.certificates_builder = csl::CertificatesBuilder::new();
40 self.vote_builder = csl::VotingBuilder::new();
41 self.tx_withdrawals_builder = csl::WithdrawalsBuilder::new();
42 }
43}
44
45impl CoreCSL {
46 pub fn add_tx_in(&mut self, input: PubKeyTxIn) -> Result<(), WError> {
47 self.tx_inputs_builder
48 .add_regular_input(
49 &csl::Address::from_bech32(&input.tx_in.address.unwrap())
50 .map_err(WError::from_err("CoreCSL - add_tx_in - invalid address"))?,
51 &csl::TransactionInput::new(
52 &csl::TransactionHash::from_hex(&input.tx_in.tx_hash)
53 .map_err(WError::from_err("CoreCSL - add_tx_in - invalid tx_hash"))?,
54 input.tx_in.tx_index,
55 ),
56 &to_value(&input.tx_in.amount.unwrap())?,
57 )
58 .map_err(WError::from_err(
59 "CoreCSL - add_tx_in - invalid regular input",
60 ))?;
61 Ok(())
62 }
63
64 pub fn add_simple_script_tx_in(&mut self, input: SimpleScriptTxIn) -> Result<(), WError> {
65 match input.simple_script_tx_in {
66 SimpleScriptTxInParameter::ProvidedSimpleScriptSource(script) => {
67 self.tx_inputs_builder.add_native_script_input(
68 &csl::NativeScriptSource::new(
69 &csl::NativeScript::from_hex(&script.script_cbor).map_err(
70 WError::from_err(
71 "CoreCSL - add_simple_script_tx_in - invalid script_cbor",
72 ),
73 )?,
74 ),
75 &csl::TransactionInput::new(
76 &csl::TransactionHash::from_hex(&input.tx_in.tx_hash).map_err(
77 WError::from_err(
78 "CoreCSL - add_simple_script_tx_in - invalid tx_hash (1)",
79 ),
80 )?,
81 input.tx_in.tx_index,
82 ),
83 &to_value(&input.tx_in.amount.unwrap())?,
84 );
85 Ok(())
86 }
87 SimpleScriptTxInParameter::InlineSimpleScriptSource(script) => {
88 self.tx_inputs_builder.add_native_script_input(
89 &csl::NativeScriptSource::new_ref_input(
90 &csl::ScriptHash::from_hex(&script.simple_script_hash).map_err(
91 WError::from_err(
92 "CoreCSL - add_simple_script_tx_in - invalid simple_script_hash",
93 ),
94 )?,
95 &csl::TransactionInput::new(
96 &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash).map_err(
97 WError::from_err(
98 "CoreCSL - add_simple_script_tx_in - invalid tx_hash (2)",
99 ),
100 )?,
101 script.ref_tx_in.tx_index,
102 ),
103 script.script_size,
104 ),
105 &csl::TransactionInput::new(
106 &csl::TransactionHash::from_hex(&input.tx_in.tx_hash).map_err(
107 WError::from_err(
108 "CoreCSL - add_simple_script_tx_in - invalid tx_hash (3)",
109 ),
110 )?,
111 input.tx_in.tx_index,
112 ),
113 &to_value(&input.tx_in.amount.unwrap())?,
114 );
115 Ok(())
116 }
117 }
118 }
119
120 pub fn add_script_tx_in(&mut self, input: ScriptTxIn) -> Result<(), WError> {
121 let datum_source = input.script_tx_in.datum_source.unwrap();
122 let script_source = input.script_tx_in.script_source.unwrap();
123 let redeemer = input.script_tx_in.redeemer.unwrap();
124 let csl_datum: Option<csl::DatumSource> = match datum_source {
125 DatumSource::ProvidedDatumSource(datum) => Some(csl::DatumSource::new(
126 &csl::PlutusData::from_hex(&datum.data).map_err(WError::from_err(
127 "CoreCSL - add_script_tx_in - invalid datum.data",
128 ))?,
129 )),
130 DatumSource::InlineDatumSource(datum) => {
131 let ref_input = csl::TransactionInput::new(
132 &csl::TransactionHash::from_hex(&datum.tx_hash).map_err(WError::from_err(
133 "CoreCSL - add_script_tx_in - invalid tx_hash",
134 ))?,
135 datum.tx_index,
136 );
137 if input.tx_in.tx_hash == datum.tx_hash && input.tx_in.tx_index == datum.tx_index {
138 None
139 } else {
140 Some(csl::DatumSource::new_ref_input(&ref_input))
141 }
142 }
143 };
144
145 let csl_script: csl::PlutusScriptSource = to_csl_script_source(script_source)?;
146
147 let csl_redeemer: csl::Redeemer = csl::Redeemer::new(
148 &csl::RedeemerTag::new_spend(),
149 &to_bignum(0).unwrap(),
150 &csl::PlutusData::from_hex(&redeemer.data).map_err(WError::from_err(
151 "CoreCSL - add_script_tx_in - invalid redeemer.data",
152 ))?,
153 &csl::ExUnits::new(
154 &to_bignum(redeemer.ex_units.mem).map_err(WError::add_err_trace(
155 "CoreCSL - add_script_tx_in - invalid redeemer memory",
156 ))?,
157 &to_bignum(redeemer.ex_units.steps).map_err(WError::add_err_trace(
158 "CoreCSL - add_script_tx_in - invalid redeemer steps",
159 ))?,
160 ),
161 );
162
163 let csl_plutus_witness = match csl_datum {
164 Some(datum) => csl::PlutusWitness::new_with_ref(&csl_script, &datum, &csl_redeemer),
165 None => csl::PlutusWitness::new_with_ref_without_datum(&csl_script, &csl_redeemer),
166 };
167
168 self.tx_inputs_builder.add_plutus_script_input(
169 &csl_plutus_witness,
170 &csl::TransactionInput::new(
171 &csl::TransactionHash::from_hex(&input.tx_in.tx_hash).map_err(WError::from_err(
172 "CoreCSL - add_script_tx_in - invalid tx_hash (2)",
173 ))?,
174 input.tx_in.tx_index,
175 ),
176 &to_value(&input.tx_in.amount.unwrap())?,
177 );
178 Ok(())
179 }
180
181 pub fn add_output(&mut self, output: Output) -> Result<(), WError> {
182 let mut output_address = csl::Address::from_bech32(&output.address);
183 match output_address {
185 Ok(_) => {}
186 Err(_) => {
187 output_address = csl::ByronAddress::from_base58(&output.address)
188 .map(|byron_addr| byron_addr.to_address());
189 }
190 };
191 let mut output_builder =
192 csl::TransactionOutputBuilder::new().with_address(&output_address.map_err(
193 WError::from_err("CoreCSL - add_output - invalid output_address"),
194 )?);
195 if output.datum.is_some() {
196 let datum = output.datum.unwrap();
197
198 match datum {
199 Datum::Hash(data) => {
200 output_builder = output_builder.with_data_hash(&csl::hash_plutus_data(
201 &csl::PlutusData::from_hex(&data).map_err(WError::from_err(
202 "CoreCSL - add_output - invalid datum hash",
203 ))?,
204 ));
205 }
206 Datum::Inline(data) => {
207 output_builder = output_builder.with_plutus_data(
208 &csl::PlutusData::from_hex(&data).map_err(WError::from_err(
209 "CoreCSL - add_output - invalid inline datum",
210 ))?,
211 );
212 }
213 Datum::Embedded(data) => {
214 let datum = &csl::PlutusData::from_hex(&data).map_err(WError::from_err(
215 "CoreCSL - add_output - invalid embedded datum",
216 ))?;
217 output_builder = output_builder.with_data_hash(&csl::hash_plutus_data(datum));
218 self.tx_builder.add_extra_witness_datum(datum);
219 }
220 };
221 }
222
223 if output.reference_script.is_some() {
224 let output_script = output.reference_script.unwrap();
225 match output_script {
226 OutputScriptSource::ProvidedScriptSource(script) => {
227 let language_version: csl::Language = match script.language_version {
228 LanguageVersion::V1 => csl::Language::new_plutus_v1(),
229 LanguageVersion::V2 => csl::Language::new_plutus_v2(),
230 LanguageVersion::V3 => csl::Language::new_plutus_v3(),
231 };
232 output_builder =
233 output_builder.with_script_ref(&csl::ScriptRef::new_plutus_script(
234 &csl::PlutusScript::from_hex_with_version(
235 &script.script_cbor,
236 &language_version,
237 )
238 .map_err(WError::from_err(
239 "CoreCSL - add_output - invalid script_cbor",
240 ))?,
241 ))
242 }
243 OutputScriptSource::ProvidedSimpleScriptSource(script) => {
244 output_builder =
245 output_builder.with_script_ref(&csl::ScriptRef::new_native_script(
246 &csl::NativeScript::from_hex(&script.script_cbor).map_err(
247 WError::from_err(
248 "CoreCSL - add_output - invalid simple script_cbor",
249 ),
250 )?,
251 ))
252 }
253 }
254 }
255
256 let tx_value = to_value(&output.amount)?;
257 let amount_builder = output_builder
258 .next()
259 .map_err(WError::from_err("CoreCSL - add_output - next output"))?;
260 let built_output: csl::TransactionOutput = if tx_value.multiasset().is_some() {
261 if tx_value.coin().is_zero() {
262 amount_builder
263 .with_asset_and_min_required_coin_by_utxo_cost(
264 &tx_value.multiasset().unwrap(),
265 &csl::DataCost::new_coins_per_byte(
266 &to_bignum(self.protocol_params.coins_per_utxo_size).map_err(
267 WError::add_err_trace(
268 "CoreCSL - add_output - invalid coins_per_utxo_size",
269 ),
270 )?,
271 ),
272 )
273 .map_err(WError::from_err(
274 "CoreCSL - add_output - with_asset_and_min_required_coin_by_utxo_cost",
275 ))?
276 .build()
277 .map_err(WError::from_err("CoreCSL - add_output - build() (1)"))?
278 } else {
279 amount_builder
280 .with_coin_and_asset(&tx_value.coin(), &tx_value.multiasset().unwrap())
281 .build()
282 .map_err(WError::from_err("CoreCSL - add_output - build() (2)"))?
283 }
284 } else {
285 amount_builder
286 .with_coin(&tx_value.coin())
287 .build()
288 .map_err(WError::from_err("CoreCSL - add_output - build() (3)"))?
289 };
290 self.tx_builder
291 .add_output(&built_output)
292 .map_err(WError::from_err("CoreCSL - add_output - add_output"))?;
293 Ok(())
294 }
295
296 pub fn add_collateral(&mut self, collateral: PubKeyTxIn) -> Result<(), WError> {
297 self.collateral_builder
298 .add_regular_input(
299 &csl::Address::from_bech32(&collateral.tx_in.address.unwrap()).map_err(
300 WError::from_err("CoreCSL - add_collateral - invalid address"),
301 )?,
302 &csl::TransactionInput::new(
303 &csl::TransactionHash::from_hex(&collateral.tx_in.tx_hash).map_err(
304 WError::from_err("CoreCSL - add_collateral - invalid tx_hash"),
305 )?,
306 collateral.tx_in.tx_index,
307 ),
308 &to_value(&collateral.tx_in.amount.unwrap())?,
309 )
310 .map_err(WError::from_err(
311 "CoreCSL - add_collateral - add_regular_input",
312 ))?;
313 Ok(())
314 }
315
316 pub fn add_reference_input(&mut self, ref_input: RefTxIn) -> Result<(), WError> {
317 let csl_ref_input = csl::TransactionInput::new(
318 &csl::TransactionHash::from_hex(&ref_input.tx_hash).map_err(WError::from_err(
319 "CoreCSL - add_reference_input - invalid_tx_hash",
320 ))?,
321 ref_input.tx_index,
322 );
323 if ref_input.script_size.is_some() {
324 self.tx_builder
325 .add_script_reference_input(&csl_ref_input, ref_input.script_size.unwrap());
326 } else {
327 self.tx_builder.add_reference_input(&csl_ref_input);
328 }
329 Ok(())
330 }
331
332 pub fn add_pub_key_withdrawal(&mut self, withdrawal: PubKeyWithdrawal) -> Result<(), WError> {
333 self.tx_withdrawals_builder
334 .add(
335 &csl::RewardAddress::from_address(
336 &csl::Address::from_bech32(&withdrawal.address).map_err(WError::from_err(
337 "CoreCSL - add_pub_key_withdrawal - invalid address",
338 ))?,
339 )
340 .unwrap(),
341 &csl::BigNum::from_str(&withdrawal.coin.to_string()).map_err(WError::from_err(
342 "CoreCSL - add_collateral - invalid coin as BigNum",
343 ))?,
344 )
345 .map_err(WError::from_err("CoreCSL - add_pub_key_withdrawal - add()"))?;
346 Ok(())
347 }
348
349 pub fn add_plutus_withdrawal(
350 &mut self,
351 withdrawal: PlutusScriptWithdrawal,
352 ) -> Result<(), WError> {
353 let script_source = withdrawal.script_source.unwrap();
354 let redeemer = withdrawal.redeemer.unwrap();
355
356 let csl_script: csl::PlutusScriptSource = to_csl_script_source(script_source)?;
357
358 let csl_redeemer: csl::Redeemer = csl::Redeemer::new(
359 &csl::RedeemerTag::new_spend(),
360 &to_bignum(0).unwrap(),
361 &csl::PlutusData::from_hex(&redeemer.data).map_err(WError::from_err(
362 "CoreCSL - add_plutus_withdrawal - invalid redeemer.data",
363 ))?,
364 &csl::ExUnits::new(
365 &to_bignum(redeemer.ex_units.mem).map_err(WError::add_err_trace(
366 "CoreCSL - add_plutus_withdrawal - invalid redeemer memory",
367 ))?,
368 &to_bignum(redeemer.ex_units.steps).map_err(WError::add_err_trace(
369 "CoreCSL - add_plutus_withdrawal - invalid redeemer steps",
370 ))?,
371 ),
372 );
373
374 self.tx_withdrawals_builder
375 .add_with_plutus_witness(
376 &csl::RewardAddress::from_address(
377 &csl::Address::from_bech32(&withdrawal.address).map_err(WError::from_err(
378 "CoreCSL - add_plutus_withdrawal - invalid address",
379 ))?,
380 )
381 .unwrap(),
382 &csl::BigNum::from_str(&withdrawal.coin.to_string()).map_err(WError::from_err(
383 "CoreCSL - add_plutus_withdrawal - invalid coin as BigNum",
384 ))?,
385 &csl::PlutusWitness::new_with_ref_without_datum(&csl_script, &csl_redeemer),
386 )
387 .map_err(WError::from_err(
388 "CoreCSL - add_plutus_withdrawal - add_with_plutus_witness",
389 ))?;
390 Ok(())
391 }
392
393 pub fn add_simple_script_withdrawal(
394 &mut self,
395 withdrawal: SimpleScriptWithdrawal,
396 ) -> Result<(), WError> {
397 let csl_native_script_source = match withdrawal.script_source {
398 Some(script_source) => match script_source {
399 SimpleScriptSource::ProvidedSimpleScriptSource(ProvidedSimpleScriptSource {
400 script_cbor: provided_script,
401 }) => csl::NativeScriptSource::new(
402 &csl::NativeScript::from_hex(&provided_script).unwrap(),
403 ),
404 SimpleScriptSource::InlineSimpleScriptSource(InlineSimpleScriptSource {
405 ref_tx_in,
406 simple_script_hash,
407 script_size,
408 }) => csl::NativeScriptSource::new_ref_input(
409 &csl::ScriptHash::from_hex(&simple_script_hash).unwrap(),
410 &csl::TransactionInput::new(
411 &csl::TransactionHash::from_hex(&ref_tx_in.tx_hash).unwrap(),
412 ref_tx_in.tx_index,
413 ),
414 script_size,
415 ),
416 },
417 None => {
418 return Err(WError::new(
419 "add_simple_script_withdrawal",
420 "Missing script source for native script withdrawal",
421 ))
422 }
423 };
424
425 self.tx_withdrawals_builder
426 .add_with_native_script(
427 &csl::RewardAddress::from_address(
428 &csl::Address::from_bech32(&withdrawal.address).map_err(WError::from_err(
429 "CoreCSL - add_simple_script_withdrawal - invalid reward address",
430 ))?,
431 )
432 .unwrap(),
433 &csl::BigNum::from_str(&withdrawal.coin.to_string()).map_err(WError::from_err(
434 "CoreCSL - add_simple_script_withdrawal - invalid coin as BigNum",
435 ))?,
436 &csl_native_script_source,
437 )
438 .map_err(WError::from_err(
439 "CoreCSL - add_simple_script_withdrawal - add_with_native_script",
440 ))
441 }
442
443 pub fn add_plutus_mint(&mut self, script_mint: ScriptMint, index: u64) -> Result<(), WError> {
444 let redeemer_info = script_mint.redeemer.unwrap();
445 let mint_redeemer = csl::Redeemer::new(
446 &csl::RedeemerTag::new_mint(),
447 &to_bignum(index).map_err(WError::from_err(
448 "CoreCSL - add_plutus_mint - invalid redeemer index",
449 ))?,
450 &csl::PlutusData::from_hex(&redeemer_info.data).map_err(WError::from_err(
451 "CoreCSL - add_plutus_mint - invalid redeemer_info.data",
452 ))?,
453 &csl::ExUnits::new(
454 &to_bignum(redeemer_info.ex_units.mem).map_err(WError::from_err(
455 "CoreCSL - add_plutus_mint - invalid redeemer_info memory",
456 ))?,
457 &to_bignum(redeemer_info.ex_units.steps).map_err(WError::from_err(
458 "CoreCSL - add_plutus_mint - invalid redeemer_info steps",
459 ))?,
460 ),
461 );
462 let script_source_info = script_mint.script_source.unwrap();
463 let mint_script = to_csl_script_source(script_source_info)?;
464 self.mint_builder
465 .add_asset(
466 &csl::MintWitness::new_plutus_script(&mint_script, &mint_redeemer),
467 &csl::AssetName::new(hex::decode(script_mint.mint.asset_name).map_err(
468 WError::from_err("CoreCSL - add_plutus_mint - Invalid asset name found"),
469 )?)
470 .map_err(WError::from_err(
471 "CoreCSL - add_plutus_mint - invalid asset name",
472 ))?,
473 &csl::Int::from_str(&script_mint.mint.amount.to_string()).map_err(
474 WError::from_err("CoreCSL - add_plutus_mint - invalid mint amount "),
475 )?,
476 )
477 .map_err(WError::from_err("CoreCSL - add_plutus_mint - add_asset"))?;
478 Ok(())
479 }
480
481 pub fn add_native_mint(&mut self, native_mint: SimpleScriptMint) -> Result<(), WError> {
482 let script_info = native_mint.script_source.unwrap();
483 match script_info {
484 SimpleScriptSource::ProvidedSimpleScriptSource(script) => self
485 .mint_builder
486 .add_asset(
487 &csl::MintWitness::new_native_script(&csl::NativeScriptSource::new(
488 &csl::NativeScript::from_hex(&script.script_cbor).map_err(
489 WError::from_err("CoreCSL - add_native_mint - invalid script_cbor"),
490 )?,
491 )),
492 &csl::AssetName::new(hex::decode(native_mint.mint.asset_name).map_err(
493 WError::from_err(
494 "CoreCSL - add_native_mint - Invalid asset name found (1)",
495 ),
496 )?)
497 .map_err(WError::from_err(
498 "CoreCSL - add_native_mint - invalid asset name (1)",
499 ))?,
500 &csl::Int::from_str(&native_mint.mint.amount.to_string()).unwrap(),
501 )
502 .map_err(WError::from_err(
503 "CoreCSL - add_native_mint - add_asset (1)",
504 ))?,
505 SimpleScriptSource::InlineSimpleScriptSource(script) => self
506 .mint_builder
507 .add_asset(
508 &csl::MintWitness::new_native_script(&csl::NativeScriptSource::new_ref_input(
509 &csl::ScriptHash::from_hex(&script.simple_script_hash).map_err(
510 WError::from_err(
511 "CoreCSL - add_native_mint - invalid simple_script_hash",
512 ),
513 )?,
514 &csl::TransactionInput::new(
515 &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash).map_err(
516 WError::from_err("CoreCSL - add_native_mint - invalid tx_hash"),
517 )?,
518 script.ref_tx_in.tx_index,
519 ),
520 script.script_size,
521 )),
522 &csl::AssetName::new(hex::decode(native_mint.mint.asset_name).map_err(
523 WError::from_err(
524 "CoreCSL - add_native_mint - Invalid asset name found (2)",
525 ),
526 )?)
527 .map_err(WError::from_err(
528 "CoreCSL - add_native_mint - invalid asset name (2)",
529 ))?,
530 &csl::Int::from_str(&native_mint.mint.amount.to_string()).unwrap(),
531 )
532 .map_err(WError::from_err(
533 "CoreCSL - add_native_mint - add_asset (2)",
534 ))?,
535 };
536 Ok(())
537 }
538
539 pub fn add_cert(&mut self, cert: Certificate, index: u64) -> Result<(), WError> {
540 match cert {
541 Certificate::BasicCertificate(basic_cert) => self
542 .certificates_builder
543 .add(&to_csl_cert(basic_cert)?)
544 .map_err(WError::from_err("CoreCSL - add_cert - add (1)"))?,
545 Certificate::ScriptCertificate(script_cert) => {
546 let cert_script_source: csl::PlutusScriptSource = match script_cert.script_source {
547 Some(script_source) => to_csl_script_source(script_source)?,
548 None => {
549 return Err(WError::new(
550 "CoreCSL - add_cert",
551 "Missing Plutus Script Source in Plutus Cert",
552 ))
553 }
554 };
555 let cert_redeemer = match script_cert.redeemer {
556 Some(redeemer) => to_csl_redeemer(RedeemerTag::Cert, redeemer, index)?,
557 None => {
558 return Err(WError::new(
559 "CoreCSL - add_cert",
560 "Missing Redeemer in Plutus Cert",
561 ))
562 }
563 };
564 let csl_plutus_witness: csl::PlutusWitness =
565 csl::PlutusWitness::new_with_ref_without_datum(
566 &cert_script_source,
567 &cert_redeemer,
568 );
569 self.certificates_builder
570 .add_with_plutus_witness(&to_csl_cert(script_cert.cert)?, &csl_plutus_witness)
571 .map_err(WError::from_err(
572 "CoreCSL - add_cert - add_with_plutus_witness",
573 ))?
574 }
575 Certificate::SimpleScriptCertificate(simple_script_cert) => {
576 let script_info = simple_script_cert.simple_script_source;
577 let script_source: csl::NativeScriptSource = match script_info {
578 Some(simple_script_source) => {
579 to_csl_simple_script_source(simple_script_source)?
580 }
581 None => {
582 return Err(WError::new(
583 "CoreCSL - add_cert",
584 "Missing Native Script Source in Native Cert",
585 ))
586 }
587 };
588 self.certificates_builder
589 .add_with_native_script(&to_csl_cert(simple_script_cert.cert)?, &script_source)
590 .map_err(WError::from_err(
591 "CoreCSL - add_cert - add_with_native_script",
592 ))?
593 }
594 };
595 Ok(())
596 }
597
598 pub fn add_vote(&mut self, vote: Vote, index: u64) -> Result<(), WError> {
599 match vote {
600 Vote::BasicVote(vote_type) => {
601 let voter = to_csl_voter(vote_type.voter)
602 .map_err(WError::from_err("CoreCSL - add_vote - invalid voter"))?;
603 let vote_kind = to_csl_vote_kind(vote_type.voting_procedure.vote_kind);
604 let voting_procedure = match vote_type.voting_procedure.anchor {
605 Some(anchor) => {
606 csl::VotingProcedure::new_with_anchor(vote_kind, &to_csl_anchor(&anchor)?)
607 }
608 None => csl::VotingProcedure::new(vote_kind),
609 };
610 self.vote_builder
611 .add(
612 &voter,
613 &csl::GovernanceActionId::new(
614 &csl::TransactionHash::from_hex(&vote_type.gov_action_id.tx_hash)
615 .map_err(WError::from_err(
616 "CoreCSL - add_vote - invalid tx_hash (1)",
617 ))?,
618 vote_type.gov_action_id.tx_index,
619 ),
620 &voting_procedure,
621 )
622 .map_err(WError::from_err("CoreCSL - add_vote - add"))?;
623 }
624 Vote::ScriptVote(script_vote) => {
625 let voter = to_csl_voter(script_vote.vote.voter)?;
626 let vote_kind = to_csl_vote_kind(script_vote.vote.voting_procedure.vote_kind);
627 let voting_procedure = match script_vote.vote.voting_procedure.anchor {
628 Some(anchor) => {
629 csl::VotingProcedure::new_with_anchor(vote_kind, &to_csl_anchor(&anchor)?)
630 }
631 None => csl::VotingProcedure::new(vote_kind),
632 };
633 let vote_script_source: csl::PlutusScriptSource = match script_vote.script_source {
634 Some(script_source) => to_csl_script_source(script_source)?,
635 None => {
636 return Err(WError::new(
637 "CoreCSL - add_vote",
638 "Missing Plutus Script Source in Plutus Vote",
639 ))
640 }
641 };
642 let vote_redeemer = match script_vote.redeemer {
643 Some(redeemer) => to_csl_redeemer(RedeemerTag::Vote, redeemer, index)?,
644 None => {
645 return Err(WError::new(
646 "CoreCSL - add_vote",
647 "Missing Redeemer in Plutus Vote",
648 ))
649 }
650 };
651 let csl_plutus_witness: csl::PlutusWitness =
652 csl::PlutusWitness::new_with_ref_without_datum(
653 &vote_script_source,
654 &vote_redeemer,
655 );
656 self.vote_builder
657 .add_with_plutus_witness(
658 &voter,
659 &csl::GovernanceActionId::new(
660 &csl::TransactionHash::from_hex(
661 &script_vote.vote.gov_action_id.tx_hash,
662 )
663 .map_err(WError::from_err(
664 "CoreCSL - add_vote - invalid tx_hash (2)",
665 ))?,
666 script_vote.vote.gov_action_id.tx_index,
667 ),
668 &voting_procedure,
669 &csl_plutus_witness,
670 )
671 .map_err(WError::from_err(
672 "CoreCSL - add_vote - add_with_plutus_witness",
673 ))?;
674 }
675 Vote::SimpleScriptVote(simple_script_vote) => {
676 let voter = to_csl_voter(simple_script_vote.vote.voter)?;
677 let vote_kind =
678 to_csl_vote_kind(simple_script_vote.vote.voting_procedure.vote_kind);
679 let voting_procedure = match simple_script_vote.vote.voting_procedure.anchor {
680 Some(anchor) => {
681 csl::VotingProcedure::new_with_anchor(vote_kind, &to_csl_anchor(&anchor)?)
682 }
683 None => csl::VotingProcedure::new(vote_kind),
684 };
685 let csl_simple_script_source = match simple_script_vote.simple_script_source {
686 Some(simple_script_source) => {
687 to_csl_simple_script_source(simple_script_source)?
688 }
689 None => {
690 return Err(WError::new(
691 "CoreCSL - add_vote",
692 "Missing Native Script Source in Native Vote",
693 ))
694 }
695 };
696 self.vote_builder
697 .add_with_native_script(
698 &voter,
699 &csl::GovernanceActionId::new(
700 &csl::TransactionHash::from_hex(
701 &simple_script_vote.vote.gov_action_id.tx_hash,
702 )
703 .map_err(WError::from_err(
704 "CoreCSL - add_vote - invalid tx_hash (3)",
705 ))?,
706 simple_script_vote.vote.gov_action_id.tx_index,
707 ),
708 &voting_procedure,
709 &csl_simple_script_source,
710 )
711 .map_err(WError::from_err(
712 "CoreCSL - add_vote - add_with_native_script",
713 ))?;
714 }
715 };
716 Ok(())
717 }
718
719 pub fn add_invalid_before(&mut self, invalid_before: u64) -> Result<(), WError> {
720 self.tx_builder
721 .set_validity_start_interval_bignum(to_bignum(invalid_before).map_err(
722 WError::from_err("CoreCSL - add_invalid_before - invalid invalid_before"),
723 )?);
724 Ok(())
725 }
726
727 pub fn add_invalid_hereafter(&mut self, invalid_hereafter: u64) -> Result<(), WError> {
728 self.tx_builder
729 .set_ttl_bignum(&to_bignum(invalid_hereafter).map_err(WError::from_err(
730 "CoreCSL - add_invalid_hereafter - invalid invalid_hereafter",
731 ))?);
732 Ok(())
733 }
734
735 pub fn set_fee(&mut self, fee: String) {
736 self.tx_builder
737 .set_fee(&csl::BigNum::from_str(&fee).expect("Error parsing fee amount"));
738 }
739
740 pub fn add_change(
741 &mut self,
742 change_address: String,
743 change_datum: Option<Datum>,
744 ) -> Result<(), WError> {
745 let mut output_address = csl::Address::from_bech32(&change_address);
746 match output_address {
748 Ok(_) => {}
749 Err(_) => {
750 output_address = csl::ByronAddress::from_base58(&change_address)
751 .map(|byron_addr| byron_addr.to_address());
752 }
753 };
754 if let Some(change_datum) = change_datum {
755 self.tx_builder
756 .add_change_if_needed_with_datum(
757 &output_address.map_err(WError::from_err(
758 "CoreCSL - add_change - invalid change_address (1)",
759 ))?,
760 &csl::OutputDatum::new_data(
761 &csl::PlutusData::from_hex(change_datum.get_inner()).map_err(
762 WError::from_err("CoreCSL - add_change - invalid change_datum"),
763 )?,
764 ),
765 )
766 .map_err(WError::from_err(
767 "CoreCSL - add_change - add_change_if_needed_with_datum",
768 ))?;
769 } else {
770 self.tx_builder
771 .add_change_if_needed(&output_address.map_err(WError::from_err(
772 "CoreCSL - add_change - invalid change_address (2)",
773 ))?)
774 .map_err(WError::from_err(
775 "CoreCSL - add_change - add_change_if_needed",
776 ))?;
777 }
778 Ok(())
779 }
780
781 pub fn add_signing_keys(&mut self, signing_keys: &[&str]) -> Result<(), WError> {
782 self.tx_hex = sign_transaction(&self.tx_hex, signing_keys)?;
783 Ok(())
784 }
785
786 pub fn add_required_signature(&mut self, pub_key_hash: &str) -> Result<(), WError> {
787 self.tx_builder
788 .add_required_signer(&csl::Ed25519KeyHash::from_hex(pub_key_hash).map_err(
789 WError::from_err("CoreCSL - add_required_signature - invalid pub_key_hash"),
790 )?);
791 Ok(())
792 }
793
794 pub fn add_metadata(&mut self, metadata: Metadata) -> Result<(), WError> {
795 self.tx_builder
796 .add_json_metadatum(
797 &csl::BigNum::from_str(&metadata.tag).map_err(WError::from_err(
798 "CoreCSL - add_metadata - invalid metadata tag",
799 ))?,
800 metadata.metadata,
801 )
802 .map_err(WError::from_err(
803 "CoreCSL - add_metadata - add_json_metadatum",
804 ))?;
805 Ok(())
806 }
807
808 pub fn add_script_hash(&mut self, network: Network) -> Result<(), WError> {
809 self.tx_builder
810 .calc_script_data_hash(&build_csl_cost_models(&network))
811 .map_err(WError::from_err(
812 "CoreCSL - add_script_hash - calc_script_data_hash",
813 ))?;
814 Ok(())
815 }
816
817 pub fn build_tx(&mut self, safe_build: bool) -> Result<String, WError> {
818 let tx = if safe_build {
819 self.tx_builder.build_tx()
820 } else {
821 self.tx_builder.build_tx_unsafe()
822 }
823 .map_err(WError::from_err("CoreCSL - build_tx - build_tx"))?;
824
825 self.tx_hex = tx.to_hex();
826 Ok(self.tx_hex.to_string())
827 }
828}
829
830