diff --git a/crates/tx3-cardano/src/coercion.rs b/crates/tx3-cardano/src/coercion.rs index 599bb186..021af8fa 100644 --- a/crates/tx3-cardano/src/coercion.rs +++ b/crates/tx3-cardano/src/coercion.rs @@ -2,7 +2,7 @@ use std::str::FromStr as _; use pallas::{codec::utils::Int, ledger::primitives::conway as primitives}; use tx3_tir::compile::Error; -use tx3_tir::model::core::UtxoRef; +use tx3_tir::model::core::{UtxoRef, Utxo}; use tx3_tir::model::v1beta0 as tir; use crate::Network; @@ -86,6 +86,18 @@ pub fn expr_into_utxo_refs(expr: &tir::Expression) -> Result, Error } } +pub fn expr_into_utxo(expr: &tir::Expression) -> Result, Error> { + match expr { + tir::Expression::UtxoSet(x) => Ok(Vec::from_iter(x.iter().map(|x| x.clone()))), + tir::Expression::UtxoRefs(_) => Ok(vec![]), + tir::Expression::String(_) => Ok(vec![]), + _ => Err(Error::CoerceError( + format!("{expr:?}"), + "Utxo".to_string(), + )), + } +} + pub fn expr_into_assets(ir: &tir::Expression) -> Result, Error> { match ir { tir::Expression::Assets(x) => Ok(x.clone()), diff --git a/crates/tx3-cardano/src/compile/mod.rs b/crates/tx3-cardano/src/compile/mod.rs index 7b8a86e0..0db3eab0 100644 --- a/crates/tx3-cardano/src/compile/mod.rs +++ b/crates/tx3-cardano/src/compile/mod.rs @@ -459,6 +459,82 @@ fn compile_collateral(tx: &tir::Tx) -> Result, Error> { .collect()) } +fn compile_collateral_return(tx: &tir::Tx) -> Result>, Error> { + if tx.collateral.is_empty() { + return Ok(None); + } + + // Is it okay to sum all collateral UTxOs amounts? + let collateral_amount = tx + .collateral + .iter() + .filter_map(|collateral| collateral.utxos.as_option()) + .flat_map(coercion::expr_into_utxo) + .flatten() + .map(|x| x.assets.naked_amount().unwrap_or(0)) + .reduce(|acc, x| acc + x) + .unwrap_or(0); + + let fees = coercion::expr_into_number(&tx.fees)?; + + // We should substract the min_amount from the collateral block + let return_amount = collateral_amount - fees; + + if return_amount <= 0 { + return Ok(None); + } + + // Is it okay to take the address from the first collateral UTxO? + let address = tx + .collateral + .iter() + .filter_map(|collateral| collateral.utxos.as_option()) + .flat_map(coercion::expr_into_utxo) + .flatten() + .next() + .ok_or(Error::MissingExpression( + "collateral return address".to_string(), + ))?.address.clone(); + + return Ok(Some(primitives::TransactionOutput::PostAlonzo( + primitives::PostAlonzoTransactionOutput { + address: crate::compile::primitives::Bytes::from(address), + value: value!(return_amount as u64), + datum_option: None, + script_ref: None, + } + .into(), + ))); +} + +fn compile_total_collateral(tx: &tir::Tx) -> Result, Error> { + if tx.collateral.is_empty() { + return Ok(None); + } + + // Is it okay to sum all collateral UTxOs amounts? + let collateral_amount = tx + .collateral + .iter() + .filter_map(|collateral| collateral.utxos.as_option()) + .flat_map(coercion::expr_into_utxo) + .flatten() + .map(|x| x.assets.naked_amount().unwrap_or(0)) + .reduce(|acc, x| acc + x) + .unwrap_or(0); + + let fees = coercion::expr_into_number(&tx.fees)?; + + // We should substract the min_amount from the collateral block + let return_amount = collateral_amount - fees; + + if return_amount <= 0 { + return Ok(None); + } + + return Ok(Some(return_amount as u64)); +} + fn compile_required_signers(tx: &tir::Tx) -> Result, Error> { let Some(signers) = &tx.signers else { return Ok(None); @@ -528,8 +604,9 @@ fn compile_tx_body( script_data_hash: None, collateral: primitives::NonEmptySet::from_vec(compile_collateral(tx)?), required_signers: compile_required_signers(tx)?, - collateral_return: None, - total_collateral: None, + // I don't think it's necessary to declare the collateral return, with the total collateral looks like it's enough? + collateral_return: compile_collateral_return(tx)?, + total_collateral: compile_total_collateral(tx)?, voting_procedures: None, proposal_procedures: None, treasury_value: None,