1use std::collections::{BTreeMap, HashMap};
2
3use crate::model::assets::CanonicalAssets;
4use crate::model::core::*;
5use crate::model::v1beta0::*;
6
7#[derive(Debug, thiserror::Error)]
8pub enum Error {
9 #[error("invalid built-in operation {0:?}")]
10 InvalidBuiltInOp(Box<BuiltInOp>),
11
12 #[error("invalid argument {0:?} for {1}")]
13 InvalidArgument(ArgValue, String),
14
15 #[error("property {0} not found in {1}")]
16 PropertyNotFound(String, String),
17
18 #[error("property index {0} not found in {1}")]
19 PropertyIndexNotFound(usize, String),
20
21 #[error("invalid {0} operation over {1:?} and {2:?}")]
22 InvalidBinaryOp(String, String, String),
23
24 #[error("invalid {0} operation over {1:?}")]
25 InvalidUnaryOp(String, String),
26
27 #[error("cannot coerce {0:?} into assets")]
28 CannotCoerceIntoAssets(Expression),
29
30 #[error("cannot coerce {0:?} into datum")]
31 CannotCoerceIntoDatum(Expression),
32
33 #[error("compiler op failed: {0}")]
34 CompilerOpFailed(Box<crate::compile::Error>),
35}
36
37impl From<crate::compile::Error> for Error {
38 fn from(error: crate::compile::Error) -> Self {
39 Error::CompilerOpFailed(Box::new(error))
40 }
41}
42
43pub trait Indexable: std::fmt::Debug {
44 fn index(&self, index: Expression) -> Option<Expression>;
45
46 fn index_or_err(&self, index: Expression) -> Result<Expression, Error> {
47 let index_value = index.as_number().unwrap_or(0) as usize;
48 self.index(index).ok_or(Error::PropertyIndexNotFound(
49 index_value,
50 format!("{self:?}"),
51 ))
52 }
53}
54
55impl Indexable for StructExpr {
56 fn index(&self, index: Expression) -> Option<Expression> {
57 match index {
59 Expression::Number(n) => self.fields.get(n as usize).cloned(),
60 _ => return None,
61 }
62 }
63}
64
65impl Indexable for Expression {
66 fn index(&self, index: Expression) -> Option<Expression> {
67 match self {
68 Expression::None => None,
69 Expression::Map(x) => x
70 .iter()
71 .find(|(k, _)| *k == index)
72 .map(|(k, v)| Expression::Tuple(vec![k.clone(), v.clone()])),
73 Expression::List(x) => x.get(index.as_number()? as usize).cloned(),
74 Expression::Tuple(x) => x.get(index.as_number()? as usize).cloned(),
75 Expression::Struct(x) => x.index(index.clone()),
76 _ => None,
77 }
78 }
79}
80
81pub trait Concatenable {
82 fn concat(self, other: Expression) -> Result<Expression, Error>;
83}
84
85pub trait Arithmetic {
86 fn add(self, other: Expression) -> Result<Expression, Error>;
87 fn sub(self, other: Expression) -> Result<Expression, Error>;
88 fn mul(self, other: Expression) -> Result<Expression, Error>;
89 fn div(self, other: Expression) -> Result<Expression, Error>;
90 fn neg(self) -> Result<Expression, Error>;
91}
92
93impl<T> Arithmetic for T
94where
95 T: Into<CanonicalAssets> + std::fmt::Debug,
96{
97 fn add(self, other: Expression) -> Result<Expression, Error> {
98 let y = match other {
99 Expression::Assets(x) => CanonicalAssets::from(x),
100 Expression::None => CanonicalAssets::empty(),
101 other => {
102 return Err(Error::InvalidBinaryOp(
103 "add".to_string(),
104 format!("{self:?}"),
105 format!("{other:?}"),
106 ))
107 }
108 };
109
110 let x = self.into();
111 let total = x + y;
112 Ok(Expression::Assets(total.into()))
113 }
114
115 fn sub(self, other: Expression) -> Result<Expression, Error> {
116 let other_neg = other.neg()?;
117 self.add(other_neg)
118 }
119
120 fn mul(self, other: Expression) -> Result<Expression, Error> {
121 match other {
124 Expression::Number(factor) => {
125 let scaled = self.into() * factor;
126 Ok(Expression::Assets(scaled.into()))
127 }
128 Expression::None => Ok(Expression::None),
129 other => Err(Error::InvalidBinaryOp(
130 "mul".to_string(),
131 format!("{self:?}"),
132 format!("{other:?}"),
133 )),
134 }
135 }
136
137 fn div(self, other: Expression) -> Result<Expression, Error> {
138 match other {
142 Expression::Number(0) => Err(Error::InvalidBinaryOp(
143 "div".to_string(),
144 format!("{self:?}"),
145 "zero".to_string(),
146 )),
147 Expression::Number(divisor) => {
148 let scaled = self.into() / divisor;
149 Ok(Expression::Assets(scaled.into()))
150 }
151 Expression::None => Ok(Expression::None),
152 other => Err(Error::InvalidBinaryOp(
153 "div".to_string(),
154 format!("{self:?}"),
155 format!("{other:?}"),
156 )),
157 }
158 }
159
160 fn neg(self) -> Result<Expression, Error> {
161 let negated = std::ops::Neg::neg(self.into());
162 Ok(Expression::Assets(negated.into()))
163 }
164}
165
166impl Arithmetic for i128 {
167 fn add(self, other: Expression) -> Result<Expression, Error> {
168 match other {
169 Expression::Number(y) => Ok(Expression::Number(self + y)),
170 Expression::None => Ok(Expression::Number(self)),
171 _ => Err(Error::InvalidBinaryOp(
172 "add".to_string(),
173 format!("{self:?}"),
174 format!("{other:?}"),
175 )),
176 }
177 }
178
179 fn sub(self, other: Expression) -> Result<Expression, Error> {
180 let other_neg = other.neg()?;
181 self.add(other_neg)
182 }
183
184 fn mul(self, other: Expression) -> Result<Expression, Error> {
185 match other {
186 Expression::Number(y) => Ok(Expression::Number(self * y)),
187 Expression::Assets(y) => {
190 let scaled = CanonicalAssets::from(y) * self;
191 Ok(Expression::Assets(scaled.into()))
192 }
193 Expression::None => Ok(Expression::None),
194 _ => Err(Error::InvalidBinaryOp(
195 "mul".to_string(),
196 format!("{self:?}"),
197 format!("{other:?}"),
198 )),
199 }
200 }
201
202 fn div(self, other: Expression) -> Result<Expression, Error> {
203 match other {
204 Expression::Number(0) => Err(Error::InvalidBinaryOp(
205 "div".to_string(),
206 format!("{self:?}"),
207 "zero".to_string(),
208 )),
209 Expression::Number(y) => Ok(Expression::Number(self / y)),
210 Expression::None => Ok(Expression::None),
213 _ => Err(Error::InvalidBinaryOp(
214 "div".to_string(),
215 format!("{self:?}"),
216 format!("{other:?}"),
217 )),
218 }
219 }
220
221 fn neg(self) -> Result<Expression, Error> {
222 Ok(Expression::Number(-self))
223 }
224}
225
226impl Arithmetic for Expression {
227 fn add(self, other: Expression) -> Result<Expression, Error> {
228 match self {
229 Expression::None => Ok(other),
230 Expression::Number(x) => Arithmetic::add(x, other),
231 Expression::Assets(x) => Arithmetic::add(x, other),
232 x => Err(Error::InvalidBinaryOp(
233 "add".to_string(),
234 format!("{x:?}"),
235 format!("{other:?}"),
236 )),
237 }
238 }
239
240 fn sub(self, other: Expression) -> Result<Expression, Error> {
241 match self {
242 Expression::None => Ok(other),
243 Expression::Number(x) => Arithmetic::sub(x, other),
244 Expression::Assets(x) => Arithmetic::sub(x, other),
245 x => Err(Error::InvalidBinaryOp(
246 "sub".to_string(),
247 format!("{x:?}"),
248 format!("{other:?}"),
249 )),
250 }
251 }
252
253 fn mul(self, other: Expression) -> Result<Expression, Error> {
254 match self {
255 Expression::None => Ok(Expression::None),
258 Expression::Number(x) => Arithmetic::mul(x, other),
259 Expression::Assets(x) => Arithmetic::mul(x, other),
260 x => Err(Error::InvalidBinaryOp(
261 "mul".to_string(),
262 format!("{x:?}"),
263 format!("{other:?}"),
264 )),
265 }
266 }
267
268 fn div(self, other: Expression) -> Result<Expression, Error> {
269 match self {
270 Expression::None => Ok(Expression::None),
273 Expression::Number(x) => Arithmetic::div(x, other),
274 Expression::Assets(x) => Arithmetic::div(x, other),
275 x => Err(Error::InvalidBinaryOp(
276 "div".to_string(),
277 format!("{x:?}"),
278 format!("{other:?}"),
279 )),
280 }
281 }
282
283 fn neg(self) -> Result<Expression, Error> {
284 match self {
285 Expression::None => Ok(Expression::None),
286 Expression::Number(x) => Arithmetic::neg(x),
287 Expression::Assets(x) => Arithmetic::neg(x),
288 x => Err(Error::InvalidUnaryOp("neg".to_string(), format!("{x:?}"))),
289 }
290 }
291}
292
293impl Concatenable for String {
294 fn concat(self, other: Expression) -> Result<Expression, Error> {
295 match other {
296 Expression::String(y) => Ok(Expression::String(self + &y)),
297 Expression::Number(y) => Ok(Expression::String(self + &y.to_string())),
298 Expression::None => Ok(Expression::String(self)),
299 _ => Err(Error::InvalidBinaryOp(
300 "concat".to_string(),
301 format!("String({self:?})"),
302 format!("{other:?}"),
303 )),
304 }
305 }
306}
307
308impl Concatenable for Vec<Expression> {
309 fn concat(self, other: Expression) -> Result<Expression, Error> {
310 match other {
311 Expression::List(expressions) => {
312 Ok(Expression::List([&self[..], &expressions[..]].concat()))
313 }
314 _ => Err(Error::InvalidBinaryOp(
315 "concat".to_string(),
316 format!("List({:?})", self),
317 format!("{:?}", other),
318 )),
319 }
320 }
321}
322
323impl Concatenable for Vec<u8> {
324 fn concat(self, other: Expression) -> Result<Expression, Error> {
325 match other {
326 Expression::Bytes(y) => {
327 let mut result = self;
328 result.extend(y);
329 Ok(Expression::Bytes(result))
330 }
331 Expression::None => Ok(Expression::Bytes(self)),
332 _ => Err(Error::InvalidBinaryOp(
333 "concat".to_string(),
334 format!("Bytes({self:?})"),
335 format!("{other:?}"),
336 )),
337 }
338 }
339}
340
341impl Concatenable for Expression {
342 fn concat(self, other: Expression) -> Result<Expression, Error> {
343 match self {
344 Expression::None => Ok(other),
345 Expression::String(x) => Concatenable::concat(x, other),
346 Expression::Bytes(x) => Concatenable::concat(x, other),
347 Expression::List(x) => Concatenable::concat(x, other),
348 x => Err(Error::InvalidBinaryOp(
349 "concat".to_string(),
350 format!("{x:?}"),
351 format!("{other:?}"),
352 )),
353 }
354 }
355}
356
357pub trait Coerceable {
358 fn into_assets(self) -> Result<Expression, Error>;
359 fn into_datum(self) -> Result<Expression, Error>;
360}
361
362impl Coerceable for Expression {
363 fn into_assets(self) -> Result<Expression, Error> {
364 match self {
365 Expression::None => Ok(Expression::None),
366 Expression::Assets(x) => Ok(Expression::Assets(x)),
367 Expression::UtxoSet(x) => Ok(Expression::Assets(x.total_assets().into())),
368 _ => Err(Error::CannotCoerceIntoAssets(self)),
369 }
370 }
371
372 fn into_datum(self) -> Result<Expression, Error> {
373 match self {
374 Expression::None => Ok(Expression::None),
375 Expression::UtxoSet(x) => Ok(x
376 .first_by_ref()
377 .and_then(|utxo| utxo.datum.clone())
378 .unwrap_or(Expression::None)),
379 Expression::List(x) => Ok(Expression::List(x)),
380 Expression::Map(x) => Ok(Expression::Map(x)),
381 Expression::Tuple(x) => Ok(Expression::Tuple(x)),
382 Expression::Struct(x) => Ok(Expression::Struct(x)),
383 Expression::Bytes(x) => Ok(Expression::Bytes(x)),
384 Expression::Number(x) => Ok(Expression::Number(x)),
385 Expression::String(x) => Ok(Expression::String(x)),
386 Expression::Address(x) => Ok(Expression::Bytes(x)),
387 Expression::Hash(x) => Ok(Expression::Bytes(x)),
388 _ => Err(Error::CannotCoerceIntoDatum(self)),
389 }
390 }
391}
392
393fn arg_value_into_expr(arg: ArgValue) -> Expression {
394 match arg {
395 ArgValue::Address(x) => Expression::Address(x),
396 ArgValue::Int(x) => Expression::Number(x),
397 ArgValue::Bool(x) => Expression::Bool(x),
398 ArgValue::String(x) => Expression::String(x),
399 ArgValue::Bytes(x) => Expression::Bytes(x),
400 ArgValue::UtxoSet(x) => Expression::UtxoSet(x),
401 ArgValue::UtxoRef(x) => Expression::UtxoRefs(vec![x]),
402 ArgValue::List(xs) => {
403 Expression::List(xs.into_iter().map(arg_value_into_expr).collect())
404 }
405 ArgValue::Tuple(xs) => {
406 Expression::Tuple(xs.into_iter().map(arg_value_into_expr).collect())
407 }
408 ArgValue::Map(pairs) => Expression::Map(
409 pairs
410 .into_iter()
411 .map(|(k, v)| (arg_value_into_expr(k), arg_value_into_expr(v)))
412 .collect(),
413 ),
414 ArgValue::Struct {
415 constructor,
416 fields,
417 } => Expression::Struct(StructExpr {
418 constructor,
419 fields: fields.into_iter().map(arg_value_into_expr).collect(),
420 }),
421 }
422}
423
424pub trait Apply: Sized + std::fmt::Debug {
425 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error>;
426 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error>;
427 fn apply_fees(self, fees: u64) -> Result<Self, Error>;
428
429 fn is_constant(&self) -> bool;
430
431 fn params(&self) -> BTreeMap<String, Type>;
432 fn queries(&self) -> BTreeMap<String, InputQuery>;
433
434 fn reduce(self) -> Result<Self, Error>;
435}
436
437pub trait Composite: Sized {
438 fn reduce_self(self) -> Result<Self, Error> {
439 Ok(self)
440 }
441
442 fn components(&self) -> Vec<&Expression>;
443
444 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
445 where
446 F: Fn(Expression) -> Result<Expression, Error> + Clone;
447
448 fn reduce_nested(self) -> Result<Self, Error> {
449 self.try_map_components(|x| x.reduce())
450 }
451}
452
453impl<T> Apply for T
454where
455 T: Composite + std::fmt::Debug,
456{
457 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
458 self.try_map_components(|x| x.apply_args(args))
459 }
460
461 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
462 self.try_map_components(|x| x.apply_inputs(args))
463 }
464
465 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
466 self.try_map_components(|x| x.apply_fees(fees))
467 }
468
469 fn is_constant(&self) -> bool {
470 self.components().iter().all(|x| x.is_constant())
471 }
472
473 fn params(&self) -> BTreeMap<String, Type> {
474 self.components().iter().flat_map(|x| x.params()).collect()
475 }
476
477 fn queries(&self) -> BTreeMap<String, InputQuery> {
478 self.components().iter().flat_map(|x| x.queries()).collect()
479 }
480
481 fn reduce(self) -> Result<Self, Error> {
482 let x = self.reduce_nested()?;
483
484 if x.is_constant() {
485 x.reduce_self()
486 } else {
487 Ok(x)
488 }
489 }
490}
491
492impl<T> Apply for Option<T>
493where
494 T: Apply,
495{
496 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
497 self.map(|x| x.apply_args(args)).transpose()
498 }
499
500 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
501 self.map(|x| x.apply_inputs(args)).transpose()
502 }
503
504 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
505 self.map(|x| x.apply_fees(fees)).transpose()
506 }
507
508 fn is_constant(&self) -> bool {
509 match self {
510 Some(x) => x.is_constant(),
511 None => true,
512 }
513 }
514
515 fn params(&self) -> BTreeMap<String, Type> {
516 match self {
517 Some(x) => x.params(),
518 None => BTreeMap::new(),
519 }
520 }
521
522 fn queries(&self) -> BTreeMap<String, InputQuery> {
523 match self {
524 Some(x) => x.queries(),
525 None => BTreeMap::new(),
526 }
527 }
528
529 fn reduce(self) -> Result<Self, Error> {
530 self.map(|x| x.reduce()).transpose()
531 }
532}
533
534impl<T> Apply for Vec<T>
535where
536 T: Apply,
537{
538 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
539 self.into_iter().map(|x| x.apply_args(args)).collect()
540 }
541
542 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
543 self.into_iter().map(|x| x.apply_inputs(args)).collect()
544 }
545
546 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
547 self.into_iter().map(|x| x.apply_fees(fees)).collect()
548 }
549
550 fn is_constant(&self) -> bool {
551 self.iter().all(|x| x.is_constant())
552 }
553
554 fn params(&self) -> BTreeMap<String, Type> {
555 self.iter().flat_map(|x| x.params()).collect()
556 }
557
558 fn queries(&self) -> BTreeMap<String, InputQuery> {
559 self.iter().flat_map(|x| x.queries()).collect()
560 }
561
562 fn reduce(self) -> Result<Self, Error> {
563 self.into_iter().map(|x| x.reduce()).collect()
564 }
565}
566
567impl<T> Apply for HashMap<String, T>
568where
569 T: Apply,
570{
571 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
572 self.into_iter()
573 .map(|(k, v)| v.apply_args(args).map(|v| (k, v)))
574 .collect()
575 }
576
577 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
578 self.into_iter()
579 .map(|(k, v)| v.apply_inputs(args).map(|v| (k, v)))
580 .collect()
581 }
582
583 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
584 self.into_iter()
585 .map(|(k, v)| v.apply_fees(fees).map(|v| (k, v)))
586 .collect()
587 }
588
589 fn is_constant(&self) -> bool {
590 self.values().all(|x| x.is_constant())
591 }
592
593 fn params(&self) -> BTreeMap<String, Type> {
594 self.values().flat_map(|x| x.params()).collect()
595 }
596
597 fn queries(&self) -> BTreeMap<String, InputQuery> {
598 self.values().flat_map(|x| x.queries()).collect()
599 }
600
601 fn reduce(self) -> Result<Self, Error> {
602 self.into_iter()
603 .map(|(k, v)| v.reduce().map(|v| (k, v)))
604 .collect()
605 }
606}
607
608impl Composite for ScriptSource {
609 fn reduce_self(self) -> Result<Self, Error> {
610 Ok(self)
611 }
612
613 fn components(&self) -> Vec<&Expression> {
614 match self {
615 ScriptSource::Embedded(x) => vec![x],
616 ScriptSource::UtxoRef { r#ref, source } => {
617 std::iter::once(r#ref).chain(source.as_ref()).collect()
618 }
619 }
620 }
621
622 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
623 where
624 F: Fn(Expression) -> Result<Expression, Error> + Clone,
625 {
626 match self {
627 ScriptSource::Embedded(x) => Ok(ScriptSource::Embedded(f(x)?)),
628 ScriptSource::UtxoRef { r#ref, source } => Ok(ScriptSource::UtxoRef {
629 r#ref: f(r#ref)?,
630 source: source.map(&f).transpose()?,
631 }),
632 }
633 }
634}
635
636impl TryFrom<&ArgValue> for ScriptSource {
637 type Error = Error;
638
639 fn try_from(value: &ArgValue) -> Result<Self, Self::Error> {
640 match value {
641 ArgValue::Bytes(x) => Ok(ScriptSource::Embedded(Expression::Bytes(x.clone()))),
642 ArgValue::UtxoRef(x) => Ok(ScriptSource::UtxoRef {
643 r#ref: Expression::UtxoRefs(vec![x.clone()]),
644 source: None,
645 }),
646 _ => Err(Error::InvalidArgument(value.clone(), "script".to_string())),
647 }
648 }
649}
650
651impl Composite for PolicyExpr {
652 fn components(&self) -> Vec<&Expression> {
653 let script = self.script.components();
654 std::iter::once(&self.hash).chain(script).collect()
655 }
656
657 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
658 where
659 F: Fn(Expression) -> Result<Expression, Error> + Clone,
660 {
661 Ok(Self {
662 name: self.name,
663 hash: f(self.hash)?,
664 script: self.script.try_map_components(f)?,
665 })
666 }
667}
668
669impl Composite for StructExpr {
670 fn components(&self) -> Vec<&Expression> {
671 self.fields.iter().collect()
672 }
673
674 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
675 where
676 F: Fn(Expression) -> Result<Expression, Error> + Clone,
677 {
678 Ok(Self {
679 constructor: self.constructor,
680 fields: self
681 .fields
682 .into_iter()
683 .map(&f)
684 .collect::<Result<Vec<_>, _>>()?,
685 })
686 }
687}
688
689impl Composite for AssetExpr {
690 fn components(&self) -> Vec<&Expression> {
691 vec![&self.policy, &self.asset_name, &self.amount]
692 }
693
694 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
695 where
696 F: Fn(Expression) -> Result<Expression, Error> + Clone,
697 {
698 Ok(Self {
699 policy: f(self.policy)?,
700 asset_name: f(self.asset_name)?,
701 amount: f(self.amount)?,
702 })
703 }
704}
705
706impl Composite for Coerce {
707 fn components(&self) -> Vec<&Expression> {
708 match self {
709 Self::IntoAssets(x) => vec![x],
710 Self::IntoDatum(x) => vec![x],
711 Self::IntoScript(x) => vec![x],
712 Self::NoOp(x) => vec![x],
713 }
714 }
715
716 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
717 where
718 F: Fn(Expression) -> Result<Expression, Error> + Clone,
719 {
720 match self {
721 Self::IntoAssets(x) => Ok(Self::IntoAssets(f(x)?)),
722 Self::IntoDatum(x) => Ok(Self::IntoDatum(f(x)?)),
723 Self::IntoScript(x) => Ok(Self::IntoScript(f(x)?)),
724 Self::NoOp(x) => Ok(Self::NoOp(f(x)?)),
725 }
726 }
727
728 fn reduce_self(self) -> Result<Self, Error> {
729 match self {
730 Self::NoOp(x) => Ok(Self::NoOp(x)),
731 Self::IntoAssets(x) => Ok(Self::NoOp(x.into_assets()?)),
732 Self::IntoDatum(x) => Ok(Self::NoOp(x.into_datum()?)),
733 Self::IntoScript(x) => todo!(),
734 }
735 }
736}
737
738impl Composite for BuiltInOp {
739 fn components(&self) -> Vec<&Expression> {
740 match self {
741 Self::NoOp(x) => vec![x],
742 Self::Add(x, y) => vec![x, y],
743 Self::Sub(x, y) => vec![x, y],
744 Self::Mul(x, y) => vec![x, y],
745 Self::Div(x, y) => vec![x, y],
746 Self::Concat(x, y) => vec![x, y],
747 Self::Negate(x) => vec![x],
748 Self::Property(x, _) => vec![x],
749 }
750 }
751
752 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
753 where
754 F: Fn(Expression) -> Result<Expression, Error> + Clone,
755 {
756 match self {
757 Self::NoOp(x) => Ok(Self::NoOp(f(x)?)),
758 Self::Add(x, y) => Ok(Self::Add(f(x)?, f(y)?)),
759 Self::Sub(x, y) => Ok(Self::Sub(f(x)?, f(y)?)),
760 Self::Mul(x, y) => Ok(Self::Mul(f(x)?, f(y)?)),
761 Self::Div(x, y) => Ok(Self::Div(f(x)?, f(y)?)),
762 Self::Concat(x, y) => Ok(Self::Concat(f(x)?, f(y)?)),
763 Self::Negate(x) => Ok(Self::Negate(f(x)?)),
764 Self::Property(x, prop) => Ok(Self::Property(f(x)?, prop)),
765 }
766 }
767
768 fn reduce_self(self) -> Result<Self, Error> {
769 match self {
770 Self::Add(x, y) => Ok(Self::NoOp(x.add(y)?)),
771 Self::Sub(x, y) => Ok(Self::NoOp(x.sub(y)?)),
772 Self::Mul(x, y) => Ok(Self::NoOp(x.mul(y)?)),
773 Self::Div(x, y) => Ok(Self::NoOp(x.div(y)?)),
774 Self::Concat(x, y) => Ok(Self::NoOp(x.concat(y)?)),
775 Self::Negate(x) => Ok(Self::NoOp(x.neg()?)),
776 Self::Property(x, prop) => Ok(Self::NoOp(x.index_or_err(prop)?)),
777 Self::NoOp(x) => Ok(Self::NoOp(x)),
778 }
779 }
780
781 fn reduce_nested(self) -> Result<Self, Error> {
782 match self {
783 Self::Add(x, y) => Ok(Self::Add(x.reduce()?, y.reduce()?)),
784 Self::Sub(x, y) => Ok(Self::Sub(x.reduce()?, y.reduce()?)),
785 Self::Mul(x, y) => Ok(Self::Mul(x.reduce()?, y.reduce()?)),
786 Self::Div(x, y) => Ok(Self::Div(x.reduce()?, y.reduce()?)),
787 Self::Concat(x, y) => Ok(Self::Concat(x.reduce()?, y.reduce()?)),
788 Self::Negate(x) => Ok(Self::Negate(x.reduce()?)),
789 Self::Property(x, y) => Ok(Self::Property(x.reduce()?, y.reduce()?)),
790 Self::NoOp(x) => Ok(Self::NoOp(x.reduce()?)),
791 }
792 }
793}
794
795impl From<AssetExpr> for CanonicalAssets {
796 fn from(asset: AssetExpr) -> Self {
797 let policy = asset.expect_constant_policy();
798 let name = asset.expect_constant_name();
799 let amount = asset.expect_constant_amount();
800
801 Self::from_asset(policy, name, amount)
802 }
803}
804
805impl From<Vec<AssetExpr>> for CanonicalAssets {
806 fn from(assets: Vec<AssetExpr>) -> Self {
807 let mut result = CanonicalAssets::empty();
808
809 for asset in assets {
810 let asset = asset.into();
811 result = result + asset;
812 }
813
814 result
815 }
816}
817
818impl From<CanonicalAssets> for Vec<AssetExpr> {
819 fn from(assets: CanonicalAssets) -> Self {
820 let mut result = Vec::new();
821
822 for (class, amount) in assets.into_iter() {
823 result.push(AssetExpr {
824 policy: class
825 .policy()
826 .map(|x| Expression::Bytes(x.to_vec()))
827 .unwrap_or(Expression::None),
828 asset_name: class
829 .name()
830 .map(|x| Expression::Bytes(x.to_vec()))
831 .unwrap_or(Expression::None),
832 amount: Expression::Number(amount),
833 });
834 }
835
836 result
837 }
838}
839
840impl AssetExpr {
841 fn expect_constant_policy(&self) -> Option<&[u8]> {
842 match &self.policy {
843 Expression::None => None,
844 Expression::Bytes(x) => Some(x.as_slice()),
845 _ => None,
846 }
847 }
848
849 fn expect_constant_name(&self) -> Option<&[u8]> {
850 match &self.asset_name {
851 Expression::None => None,
852 Expression::Bytes(x) => Some(x.as_slice()),
853 Expression::String(x) => Some(x.as_bytes()),
854 _ => None,
855 }
856 }
857
858 fn expect_constant_amount(&self) -> i128 {
859 match &self.amount {
860 Expression::Number(x) => *x,
861 _ => unreachable!("amount expected to be Number"),
862 }
863 }
864}
865
866impl Composite for Input {
867 fn components(&self) -> Vec<&Expression> {
868 vec![&self.utxos, &self.redeemer]
869 }
870
871 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
872 where
873 F: Fn(Expression) -> Result<Expression, Error> + Clone,
874 {
875 Ok(Self {
876 name: self.name,
877 utxos: f(self.utxos)?,
878 redeemer: f(self.redeemer)?,
879 })
880 }
881}
882
883impl Composite for InputQuery {
884 fn components(&self) -> Vec<&Expression> {
885 vec![&self.address, &self.min_amount, &self.r#ref]
886 }
887
888 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
889 where
890 F: Fn(Expression) -> Result<Expression, Error> + Clone,
891 {
892 Ok(Self {
893 address: f(self.address)?,
894 min_amount: f(self.min_amount)?,
895 r#ref: f(self.r#ref)?,
896 ..self
897 })
898 }
899}
900
901impl Apply for Param {
902 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
903 match self {
904 Param::ExpectValue(name, ty) => {
905 let defined = args.get(&name).cloned();
906
907 match defined {
908 Some(x) => Ok(Param::Set(arg_value_into_expr(x))),
909 None => Ok(Self::ExpectValue(name, ty)),
910 }
911 }
912 Param::ExpectInput(name, query) => {
914 Ok(Param::ExpectInput(name, query.apply_args(args)?))
915 }
916 x => Ok(x),
917 }
918 }
919
920 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
921 match self {
922 Param::ExpectInput(name, query) => {
923 let defined = args.get(&name).cloned();
924
925 match defined {
926 Some(x) => Ok(Param::Set(Expression::UtxoSet(x))),
927 None => Ok(Self::ExpectInput(name, query)),
928 }
929 }
930 x => Ok(x),
931 }
932 }
933
934 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
935 match self {
936 Param::ExpectFees => Ok(Param::Set(Expression::Assets(vec![AssetExpr {
937 policy: Expression::None,
938 asset_name: Expression::None,
939 amount: Expression::Number(fees as i128),
940 }]))),
941 Param::ExpectInput(name, query) => {
943 Ok(Param::ExpectInput(name, query.apply_fees(fees)?))
944 }
945 x => Ok(x),
946 }
947 }
948
949 fn is_constant(&self) -> bool {
950 match self {
951 Param::Set(x) => x.is_constant(),
952 _ => false,
953 }
954 }
955
956 fn params(&self) -> BTreeMap<String, Type> {
957 match self {
958 Param::ExpectValue(name, ty) => BTreeMap::from([(name.clone(), ty.clone())]),
959 Param::ExpectInput(_, x) => x.params(),
961 _ => BTreeMap::new(),
962 }
963 }
964
965 fn queries(&self) -> BTreeMap<String, InputQuery> {
966 match self {
967 Param::ExpectInput(name, query) => BTreeMap::from([(name.clone(), query.clone())]),
968 _ => BTreeMap::new(),
969 }
970 }
971
972 fn reduce(self) -> Result<Self, Error> {
973 match self {
974 Param::ExpectInput(name, query) => Ok(Param::ExpectInput(name, query.reduce()?)),
976 x => Ok(x),
977 }
978 }
979}
980
981impl Apply for Expression {
982 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
983 match self {
984 Self::List(x) => Ok(Self::List(
985 x.into_iter()
986 .map(|x| x.apply_args(args))
987 .collect::<Result<_, _>>()?,
988 )),
989 Self::Tuple(x) => Ok(Self::Tuple(
990 x.into_iter()
991 .map(|x| x.apply_args(args))
992 .collect::<Result<_, _>>()?,
993 )),
994 Self::Map(x) => Ok(Self::Map(
995 x.into_iter()
996 .map(|(k, v)| {
997 Ok::<(Expression, Expression), Error>((
998 k.apply_args(args)?,
999 v.apply_args(args)?,
1000 ))
1001 })
1002 .collect::<Result<_, _>>()?,
1003 )),
1004 Self::Struct(x) => Ok(Self::Struct(x.apply_args(args)?)),
1005 Self::Assets(x) => Ok(Self::Assets(
1006 x.into_iter()
1007 .map(|x| x.apply_args(args))
1008 .collect::<Result<_, _>>()?,
1009 )),
1010 Self::EvalParam(x) => Ok(Self::EvalParam(Box::new(x.apply_args(args)?))),
1011 Self::EvalBuiltIn(x) => Ok(Self::EvalBuiltIn(Box::new(x.apply_args(args)?))),
1012 Self::EvalCoerce(x) => Ok(Self::EvalCoerce(Box::new(x.apply_args(args)?))),
1013 Self::EvalCompiler(x) => Ok(Self::EvalCompiler(Box::new(x.apply_args(args)?))),
1014 Self::AdHocDirective(x) => Ok(Self::AdHocDirective(Box::new(x.apply_args(args)?))),
1015
1016 Self::None => Ok(self),
1020 Self::Bytes(_) => Ok(self),
1021 Self::Number(_) => Ok(self),
1022 Self::Bool(_) => Ok(self),
1023 Self::String(_) => Ok(self),
1024 Self::Address(_) => Ok(self),
1025 Self::Hash(_) => Ok(self),
1026 Self::UtxoRefs(_) => Ok(self),
1027 Self::UtxoSet(_) => Ok(self),
1028 }
1029 }
1030
1031 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
1032 match self {
1033 Self::List(x) => Ok(Self::List(
1034 x.into_iter()
1035 .map(|x| x.apply_inputs(args))
1036 .collect::<Result<_, _>>()?,
1037 )),
1038 Self::Map(x) => Ok(Self::Map(
1039 x.into_iter()
1040 .map(|(k, v)| {
1041 Ok::<(Expression, Expression), Error>((
1042 k.apply_inputs(args)?,
1043 v.apply_inputs(args)?,
1044 ))
1045 })
1046 .collect::<Result<_, _>>()?,
1047 )),
1048 Self::Tuple(x) => Ok(Self::Tuple(
1049 x.into_iter()
1050 .map(|x| x.apply_inputs(args))
1051 .collect::<Result<_, _>>()?,
1052 )),
1053 Self::Struct(x) => Ok(Self::Struct(x.apply_inputs(args)?)),
1054 Self::Assets(x) => Ok(Self::Assets(
1055 x.into_iter()
1056 .map(|x| x.apply_inputs(args))
1057 .collect::<Result<_, _>>()?,
1058 )),
1059 Self::EvalParam(x) => Ok(Self::EvalParam(Box::new(x.apply_inputs(args)?))),
1060 Self::EvalBuiltIn(x) => Ok(Self::EvalBuiltIn(Box::new(x.apply_inputs(args)?))),
1061 Self::EvalCoerce(x) => Ok(Self::EvalCoerce(Box::new(x.apply_inputs(args)?))),
1062 Self::EvalCompiler(x) => Ok(Self::EvalCompiler(Box::new(x.apply_inputs(args)?))),
1063 Self::AdHocDirective(x) => Ok(Self::AdHocDirective(Box::new(x.apply_inputs(args)?))),
1064
1065 Self::None => Ok(self),
1069 Self::Bytes(_) => Ok(self),
1070 Self::Number(_) => Ok(self),
1071 Self::Bool(_) => Ok(self),
1072 Self::String(_) => Ok(self),
1073 Self::Address(_) => Ok(self),
1074 Self::Hash(_) => Ok(self),
1075 Self::UtxoRefs(_) => Ok(self),
1076 Self::UtxoSet(_) => Ok(self),
1077 }
1078 }
1079
1080 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
1081 match self {
1082 Self::List(x) => Ok(Self::List(
1083 x.into_iter()
1084 .map(|x| x.apply_fees(fees))
1085 .collect::<Result<_, _>>()?,
1086 )),
1087 Self::Map(x) => Ok(Self::Map(
1088 x.into_iter()
1089 .map(|(k, v)| {
1090 Ok::<(Expression, Expression), Error>((
1091 k.apply_fees(fees)?,
1092 v.apply_fees(fees)?,
1093 ))
1094 })
1095 .collect::<Result<_, _>>()?,
1096 )),
1097 Self::Tuple(x) => Ok(Self::Tuple(
1098 x.into_iter()
1099 .map(|x| x.apply_fees(fees))
1100 .collect::<Result<_, _>>()?,
1101 )),
1102 Self::Struct(x) => Ok(Self::Struct(x.apply_fees(fees)?)),
1103 Self::Assets(x) => Ok(Self::Assets(
1104 x.into_iter()
1105 .map(|x| x.apply_fees(fees))
1106 .collect::<Result<_, _>>()?,
1107 )),
1108 Self::EvalParam(x) => Ok(Self::EvalParam(Box::new(x.apply_fees(fees)?))),
1109 Self::EvalBuiltIn(x) => Ok(Self::EvalBuiltIn(Box::new(x.apply_fees(fees)?))),
1110 Self::EvalCoerce(x) => Ok(Self::EvalCoerce(Box::new(x.apply_fees(fees)?))),
1111 Self::EvalCompiler(x) => Ok(Self::EvalCompiler(Box::new(x.apply_fees(fees)?))),
1112 Self::AdHocDirective(x) => Ok(Self::AdHocDirective(Box::new(x.apply_fees(fees)?))),
1113
1114 Self::None => Ok(self),
1118 Self::Bytes(_) => Ok(self),
1119 Self::Number(_) => Ok(self),
1120 Self::Bool(_) => Ok(self),
1121 Self::String(_) => Ok(self),
1122 Self::Address(_) => Ok(self),
1123 Self::Hash(_) => Ok(self),
1124 Self::UtxoRefs(_) => Ok(self),
1125 Self::UtxoSet(_) => Ok(self),
1126 }
1127 }
1128
1129 fn is_constant(&self) -> bool {
1130 match self {
1131 Self::List(x) => x.iter().all(|x| x.is_constant()),
1132 Self::Map(x) => x.iter().all(|(k, v)| k.is_constant() && v.is_constant()),
1133 Self::Tuple(x) => x.iter().all(|x| x.is_constant()),
1134 Self::Struct(x) => x.is_constant(),
1135 Self::Assets(x) => x.iter().all(|x| x.is_constant()),
1136 Self::EvalParam(x) => x.is_constant(),
1137 Self::EvalBuiltIn(x) => x.is_constant(),
1138 Self::EvalCoerce(x) => x.is_constant(),
1139 Self::EvalCompiler(_) => false,
1140 Self::AdHocDirective(x) => x.is_constant(),
1141
1142 Self::None => true,
1146 Self::Bytes(_) => true,
1147 Self::Number(_) => true,
1148 Self::Bool(_) => true,
1149 Self::String(_) => true,
1150 Self::Address(_) => true,
1151 Self::Hash(_) => true,
1152 Self::UtxoRefs(_) => true,
1153 Self::UtxoSet(_) => true,
1154 }
1155 }
1156
1157 fn params(&self) -> BTreeMap<String, Type> {
1158 match self {
1159 Self::List(x) => x.iter().flat_map(|x| x.params()).collect(),
1160 Self::Map(x) => x
1161 .iter()
1162 .flat_map(|(k, v)| [k.params(), v.params()].into_iter().flatten())
1163 .collect(),
1164 Self::Tuple(x) => x.iter().flat_map(|x| x.params()).collect(),
1165 Self::Struct(x) => x.params(),
1166 Self::Assets(x) => x.iter().flat_map(|x| x.params()).collect(),
1167 Self::EvalParam(x) => x.params(),
1168 Self::EvalBuiltIn(x) => x.params(),
1169 Self::EvalCoerce(x) => x.params(),
1170 Self::EvalCompiler(x) => x.params(),
1171 Self::AdHocDirective(x) => x.params(),
1172
1173 Self::None => BTreeMap::new(),
1177 Self::Bytes(_) => BTreeMap::new(),
1178 Self::Number(_) => BTreeMap::new(),
1179 Self::Bool(_) => BTreeMap::new(),
1180 Self::String(_) => BTreeMap::new(),
1181 Self::Address(_) => BTreeMap::new(),
1182 Self::Hash(_) => BTreeMap::new(),
1183 Self::UtxoRefs(_) => BTreeMap::new(),
1184 Self::UtxoSet(_) => BTreeMap::new(),
1185 }
1186 }
1187
1188 fn queries(&self) -> BTreeMap<String, InputQuery> {
1189 match self {
1190 Self::List(x) => x.iter().flat_map(|x| x.queries()).collect(),
1191 Self::Map(x) => x
1192 .iter()
1193 .flat_map(|(k, v)| [k.queries(), v.queries()].into_iter().flatten())
1194 .collect(),
1195 Self::Tuple(x) => x.iter().flat_map(|x| x.queries()).collect(),
1196 Self::Struct(x) => x.queries(),
1197 Self::Assets(x) => x.iter().flat_map(|x| x.queries()).collect(),
1198 Self::EvalParam(x) => x.queries(),
1199 Self::EvalBuiltIn(x) => x.queries(),
1200 Self::EvalCoerce(x) => x.queries(),
1201 Self::EvalCompiler(x) => x.queries(),
1202 Self::AdHocDirective(x) => x.queries(),
1203
1204 Self::None => BTreeMap::new(),
1208 Self::Bytes(_) => BTreeMap::new(),
1209 Self::Number(_) => BTreeMap::new(),
1210 Self::Bool(_) => BTreeMap::new(),
1211 Self::String(_) => BTreeMap::new(),
1212 Self::Address(_) => BTreeMap::new(),
1213 Self::Hash(_) => BTreeMap::new(),
1214 Self::UtxoRefs(_) => BTreeMap::new(),
1215 Self::UtxoSet(_) => BTreeMap::new(),
1216 }
1217 }
1218
1219 fn reduce(self) -> Result<Self, Error> {
1220 match self {
1221 Expression::List(x) => Ok(Self::List(
1223 x.into_iter()
1224 .map(|x| x.reduce())
1225 .collect::<Result<_, _>>()?,
1226 )),
1227 Expression::Map(x) => Ok(Self::Map(
1228 x.into_iter()
1229 .map(|(k, v)| Ok::<(Expression, Expression), Error>((k.reduce()?, v.reduce()?)))
1230 .collect::<Result<_, _>>()?,
1231 )),
1232 Expression::Tuple(x) => Ok(Self::Tuple(
1233 x.into_iter()
1234 .map(|x| x.reduce())
1235 .collect::<Result<_, _>>()?,
1236 )),
1237 Expression::Struct(x) => Ok(Self::Struct(x.reduce()?)),
1238 Expression::Assets(x) => Ok(Self::Assets(
1239 x.into_iter()
1240 .map(|x| x.reduce())
1241 .collect::<Result<_, _>>()?,
1242 )),
1243 Expression::EvalCompiler(x) => Ok(Self::EvalCompiler(Box::new(x.reduce()?))),
1244 Expression::AdHocDirective(x) => Ok(Self::AdHocDirective(Box::new(x.reduce()?))),
1245
1246 Expression::EvalBuiltIn(x) => match x.reduce()? {
1248 BuiltInOp::NoOp(x) => Ok(x),
1249 x => Ok(Expression::EvalBuiltIn(Box::new(x.reduce()?))),
1250 },
1251 Expression::EvalCoerce(x) => match x.reduce()? {
1252 Coerce::NoOp(x) => Ok(x),
1253 x => Ok(Expression::EvalCoerce(Box::new(x.reduce()?))),
1254 },
1255 Expression::EvalParam(x) => match x.reduce()? {
1256 Param::Set(x) => Ok(x),
1257 x => Ok(Expression::EvalParam(Box::new(x.reduce()?))),
1258 },
1259
1260 Self::None => Ok(self),
1264 Self::Bytes(_) => Ok(self),
1265 Self::Number(_) => Ok(self),
1266 Self::Bool(_) => Ok(self),
1267 Self::String(_) => Ok(self),
1268 Self::Address(_) => Ok(self),
1269 Self::Hash(_) => Ok(self),
1270 Self::UtxoRefs(_) => Ok(self),
1271 Self::UtxoSet(_) => Ok(self),
1272 }
1273 }
1274}
1275
1276impl Composite for Output {
1277 fn components(&self) -> Vec<&Expression> {
1278 vec![&self.address, &self.datum, &self.amount]
1279 }
1280
1281 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1282 where
1283 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1284 {
1285 Ok(Self {
1286 address: f(self.address)?,
1287 datum: f(self.datum)?,
1288 amount: f(self.amount)?,
1289 optional: self.optional,
1290 })
1291 }
1292}
1293
1294impl Composite for Mint {
1295 fn components(&self) -> Vec<&Expression> {
1296 vec![&self.amount, &self.redeemer]
1297 }
1298
1299 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1300 where
1301 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1302 {
1303 Ok(Self {
1304 amount: f(self.amount)?,
1305 redeemer: f(self.redeemer)?,
1306 })
1307 }
1308}
1309
1310impl Composite for AdHocDirective {
1311 fn components(&self) -> Vec<&Expression> {
1312 self.data.values().collect()
1313 }
1314
1315 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1316 where
1317 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1318 {
1319 Ok(Self {
1320 name: self.name,
1321 data: self
1322 .data
1323 .into_iter()
1324 .map(|(k, v)| f(v).map(|v| (k, v)))
1325 .collect::<Result<_, _>>()?,
1326 })
1327 }
1328}
1329
1330impl Composite for CompilerOp {
1331 fn components(&self) -> Vec<&Expression> {
1332 match self {
1333 CompilerOp::BuildScriptAddress(x) => vec![x],
1334 CompilerOp::ComputeMinUtxo(x) => vec![x],
1335 CompilerOp::ComputeTipSlot => vec![],
1336 CompilerOp::ComputeSlotToTime(x) => vec![x],
1337 CompilerOp::ComputeTimeToSlot(x) => vec![x],
1338 }
1339 }
1340
1341 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1342 where
1343 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1344 {
1345 match self {
1346 CompilerOp::BuildScriptAddress(x) => Ok(CompilerOp::BuildScriptAddress(f(x)?)),
1347 CompilerOp::ComputeMinUtxo(x) => Ok(CompilerOp::ComputeMinUtxo(f(x)?)),
1348 CompilerOp::ComputeTipSlot => Ok(CompilerOp::ComputeTipSlot),
1349 CompilerOp::ComputeSlotToTime(x) => Ok(CompilerOp::ComputeSlotToTime(f(x)?)),
1350 CompilerOp::ComputeTimeToSlot(x) => Ok(CompilerOp::ComputeTimeToSlot(f(x)?)),
1351 }
1352 }
1353}
1354
1355impl Composite for Signers {
1356 fn components(&self) -> Vec<&Expression> {
1357 self.signers.iter().collect()
1358 }
1359
1360 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1361 where
1362 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1363 {
1364 Ok(Self {
1365 signers: self.signers.into_iter().map(f).collect::<Result<_, _>>()?,
1366 })
1367 }
1368}
1369
1370impl Composite for Collateral {
1371 fn components(&self) -> Vec<&Expression> {
1372 vec![&self.utxos]
1373 }
1374
1375 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1376 where
1377 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1378 {
1379 Ok(Self {
1380 utxos: f(self.utxos)?,
1381 })
1382 }
1383}
1384
1385impl Composite for Validity {
1386 fn components(&self) -> Vec<&Expression> {
1387 vec![&self.since, &self.until]
1388 }
1389
1390 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1391 where
1392 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1393 {
1394 Ok(Self {
1395 since: f(self.since)?,
1396 until: f(self.until)?,
1397 })
1398 }
1399}
1400
1401impl Composite for Metadata {
1402 fn components(&self) -> Vec<&Expression> {
1403 vec![&self.key, &self.value]
1404 }
1405
1406 fn try_map_components<F>(self, f: F) -> Result<Self, Error>
1407 where
1408 F: Fn(Expression) -> Result<Expression, Error> + Clone,
1409 {
1410 Ok(Self {
1411 key: f(self.key)?,
1412 value: f(self.value)?,
1413 })
1414 }
1415}
1416
1417impl Apply for Tx {
1418 fn apply_args(self, args: &BTreeMap<String, ArgValue>) -> Result<Self, Error> {
1419 let tx = Tx {
1420 references: self.references.apply_args(args)?,
1421 inputs: self.inputs.apply_args(args)?,
1422 outputs: self.outputs.apply_args(args)?,
1423 validity: self.validity.apply_args(args)?,
1424 mints: self.mints.apply_args(args)?,
1425 burns: self.burns.apply_args(args)?,
1426 fees: self.fees.apply_args(args)?,
1427 adhoc: self.adhoc.apply_args(args)?,
1428 collateral: self.collateral.apply_args(args)?,
1429 signers: self.signers.apply_args(args)?,
1430 metadata: self.metadata.apply_args(args)?,
1431 };
1432
1433 Ok(tx)
1434 }
1435
1436 fn apply_inputs(self, args: &BTreeMap<String, UtxoSet>) -> Result<Self, Error> {
1437 Ok(Self {
1438 references: self.references.apply_inputs(args)?,
1439 inputs: self.inputs.apply_inputs(args)?,
1440 outputs: self.outputs.apply_inputs(args)?,
1441 validity: self.validity.apply_inputs(args)?,
1442 mints: self.mints.apply_inputs(args)?,
1443 burns: self.burns.apply_inputs(args)?,
1444 fees: self.fees.apply_inputs(args)?,
1445 adhoc: self.adhoc.apply_inputs(args)?,
1446 collateral: self.collateral.apply_inputs(args)?,
1447 signers: self.signers.apply_inputs(args)?,
1448 metadata: self.metadata.apply_inputs(args)?,
1449 })
1450 }
1451
1452 fn apply_fees(self, fees: u64) -> Result<Self, Error> {
1453 Ok(Self {
1454 references: self.references.apply_fees(fees)?,
1455 inputs: self.inputs.apply_fees(fees)?,
1456 outputs: self.outputs.apply_fees(fees)?,
1457 validity: self.validity.apply_fees(fees)?,
1458 mints: self.mints.apply_fees(fees)?,
1459 burns: self.burns.apply_fees(fees)?,
1460 fees: self.fees.apply_fees(fees)?,
1461 adhoc: self.adhoc.apply_fees(fees)?,
1462 collateral: self.collateral.apply_fees(fees)?,
1463 signers: self.signers.apply_fees(fees)?,
1464 metadata: self.metadata.apply_fees(fees)?,
1465 })
1466 }
1467
1468 fn is_constant(&self) -> bool {
1469 self.inputs.iter().all(|x| x.is_constant())
1470 && self.outputs.iter().all(|x| x.is_constant())
1471 && self.mints.iter().all(|x| x.is_constant())
1472 && self.burns.iter().all(|x| x.is_constant())
1473 && self.fees.is_constant()
1474 && self.metadata.is_constant()
1475 && self.validity.is_constant()
1476 && self.references.is_constant()
1477 && self.collateral.is_constant()
1478 && self.adhoc.iter().all(|x| x.is_constant())
1479 && self.signers.is_constant()
1480 }
1481
1482 fn params(&self) -> BTreeMap<String, Type> {
1483 let mut params = BTreeMap::new();
1485 params.extend(self.inputs.params());
1486 params.extend(self.outputs.params());
1487 params.extend(self.mints.params());
1488 params.extend(self.burns.params());
1489 params.extend(self.fees.params());
1490 params.extend(self.adhoc.params());
1491 params.extend(self.signers.params());
1492 params.extend(self.validity.params());
1493 params.extend(self.metadata.params());
1494 params.extend(self.references.params());
1495 params.extend(self.collateral.params());
1496 params
1497 }
1498
1499 fn queries(&self) -> BTreeMap<String, InputQuery> {
1500 let mut queries = BTreeMap::new();
1501 queries.extend(self.inputs.queries());
1502 queries.extend(self.outputs.queries());
1503 queries.extend(self.mints.queries());
1504 queries.extend(self.burns.queries());
1505 queries.extend(self.fees.queries());
1506 queries.extend(self.adhoc.queries());
1507 queries.extend(self.signers.queries());
1508 queries.extend(self.validity.queries());
1509 queries.extend(self.metadata.queries());
1510 queries.extend(self.collateral.queries());
1511 queries.extend(self.references.queries());
1512 queries
1513 }
1514
1515 fn reduce(self) -> Result<Self, Error> {
1516 Ok(Self {
1517 references: self.references.reduce()?,
1518 inputs: self.inputs.reduce()?,
1519 outputs: self.outputs.reduce()?,
1520 validity: self.validity.reduce()?,
1521 mints: self.mints.reduce()?,
1522 burns: self.burns.reduce()?,
1523 fees: self.fees.reduce()?,
1524 adhoc: self.adhoc.reduce()?,
1525 collateral: self.collateral.reduce()?,
1526 signers: self.signers.reduce()?,
1527 metadata: self.metadata.reduce()?,
1528 })
1529 }
1530}
1531
1532#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1533pub enum ArgValue {
1534 Int(i128),
1535 Bool(bool),
1536 String(String),
1537 Bytes(Vec<u8>),
1538 Address(Vec<u8>),
1539 UtxoSet(UtxoSet),
1540 UtxoRef(UtxoRef),
1541
1542 List(Vec<ArgValue>),
1545 Tuple(Vec<ArgValue>),
1546 Map(Vec<(ArgValue, ArgValue)>),
1547 Struct {
1548 constructor: usize,
1549 fields: Vec<ArgValue>,
1550 },
1551}
1552
1553impl From<Vec<u8>> for ArgValue {
1554 fn from(value: Vec<u8>) -> Self {
1555 Self::Bytes(value)
1556 }
1557}
1558
1559impl From<String> for ArgValue {
1560 fn from(value: String) -> Self {
1561 Self::String(value)
1562 }
1563}
1564
1565impl From<&str> for ArgValue {
1566 fn from(value: &str) -> Self {
1567 Self::String(value.to_string())
1568 }
1569}
1570
1571impl From<bool> for ArgValue {
1572 fn from(value: bool) -> Self {
1573 Self::Bool(value)
1574 }
1575}
1576
1577macro_rules! impl_from_int_for_arg_value {
1578 ($($t:ty),*) => {
1579 $(
1580 impl From<$t> for ArgValue {
1581 fn from(value: $t) -> Self {
1582 Self::Int(value as i128)
1583 }
1584 }
1585 )*
1586 };
1587}
1588
1589impl_from_int_for_arg_value!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
1590
1591pub type ArgMap = BTreeMap<String, ArgValue>;
1592
1593pub fn apply_args<T: Apply>(template: T, args: &ArgMap) -> Result<T, Error> {
1594 template.apply_args(args)
1595}
1596
1597pub fn apply_inputs<T: Apply>(template: T, args: &BTreeMap<String, UtxoSet>) -> Result<T, Error> {
1598 template.apply_inputs(args)
1599}
1600
1601pub fn apply_fees<T: Apply>(template: T, fees: u64) -> Result<T, Error> {
1602 template.apply_fees(fees)
1603}
1604
1605pub fn reduce<T: Apply>(template: T) -> Result<T, Error> {
1606 template.reduce()
1607}
1608
1609pub fn find_params<T: Apply>(template: &T) -> BTreeMap<String, Type> {
1610 template.params()
1611}
1612
1613pub fn find_queries<T: Apply>(template: &T) -> BTreeMap<String, InputQuery> {
1614 template.queries()
1615}
1616
1617#[cfg(test)]
1618mod tests {
1619 use super::*;
1620
1621 const SUBJECT_TIR: &str = include_str!("test_subject.tir");
1622
1623 fn get_subject_tx() -> Tx {
1624 serde_json::from_str::<Tx>(SUBJECT_TIR).unwrap()
1625 }
1626
1627 #[test]
1628 fn param_expression_is_applied() {
1629 let ir = Expression::EvalParam(Box::new(Param::ExpectValue("a".to_string(), Type::Int)));
1630
1631 let params = ir.params();
1632 assert_eq!(params.len(), 1);
1633 assert_eq!(params.get("a"), Some(&Type::Int));
1634
1635 let args = BTreeMap::from([("a".to_string(), ArgValue::Int(100))]);
1636
1637 let after = ir.apply_args(&args).unwrap();
1638
1639 assert_eq!(
1640 after,
1641 Expression::EvalParam(Box::new(Param::Set(Expression::Number(100),)))
1642 );
1643 }
1644
1645 #[test]
1646 fn nested_param_expression_is_applied() {
1647 let ir = Expression::EvalParam(Box::new(Param::ExpectInput(
1648 "out".to_string(),
1649 InputQuery {
1650 address: Expression::None,
1651 min_amount: Expression::None,
1652 r#ref: Expression::EvalParam(Box::new(Param::ExpectValue(
1653 "in".to_string(),
1654 Type::Int,
1655 ))),
1656 many: false,
1657 collateral: false,
1658 },
1659 )));
1660
1661 let params = ir.params();
1662 assert_eq!(params.len(), 1);
1663 assert_eq!(params.get("in"), Some(&Type::Int));
1664
1665 let args = BTreeMap::from([("in".to_string(), ArgValue::Int(100))]);
1666 let after = ir.apply_args(&args).unwrap();
1667
1668 let after = after.reduce().unwrap();
1669
1670 let queries = after.queries();
1671 assert_eq!(queries.len(), 1);
1672 assert_eq!(
1673 queries.get("out"),
1674 Some(&InputQuery {
1675 address: Expression::None,
1676 min_amount: Expression::None,
1677 r#ref: Expression::Number(100),
1678 many: false,
1679 collateral: false,
1680 })
1681 );
1682 }
1683
1684 #[test]
1685 fn param_expression_is_reduced() {
1686 let ir = Expression::EvalParam(Box::new(Param::Set(Expression::Number(3))));
1687
1688 let after = ir.reduce().unwrap();
1689
1690 assert_eq!(after, Expression::Number(3));
1691 }
1692
1693 #[test]
1694 fn test_apply_args() {
1695 let before = get_subject_tx();
1696
1697 let params = find_params(&before);
1698 assert_eq!(params.len(), 3);
1699 assert_eq!(params.get("sender"), Some(&Type::Address));
1700 assert_eq!(params.get("a"), Some(&Type::Int));
1701 assert_eq!(params.get("b"), Some(&Type::Int));
1702
1703 let args = BTreeMap::from([
1704 ("sender".to_string(), ArgValue::Address(b"abc".to_vec())),
1705 ("a".to_string(), ArgValue::Int(100)),
1706 ("b".to_string(), ArgValue::Int(200)),
1707 ]);
1708
1709 let after = apply_args(before, &args).unwrap();
1710
1711 let params = find_params(&after);
1712 assert_eq!(params.len(), 0);
1713 }
1714
1715 #[test]
1716 fn test_apply_inputs() {
1717 let before = get_subject_tx();
1718
1719 let args = BTreeMap::from([
1720 ("sender".to_string(), ArgValue::Address(b"abc".to_vec())),
1721 ("a".to_string(), ArgValue::Int(100)),
1722 ("b".to_string(), ArgValue::Int(200)),
1723 ]);
1724
1725 let before = apply_args(before, &args).unwrap();
1726
1727 let before = before.reduce().unwrap();
1728
1729 let queries = find_queries(&before);
1730 dbg!(&queries);
1731
1732 assert_eq!(queries.len(), 1);
1733 assert!(queries.contains_key("source"));
1734
1735 let inputs = BTreeMap::from([(
1736 "source".to_string(),
1737 UtxoSet::from([Utxo {
1738 r#ref: UtxoRef::new(b"abc", 0),
1739 address: b"abc".to_vec(),
1740 datum: None,
1741 assets: CanonicalAssets::from_naked_amount(300),
1742 script: None,
1743 }]),
1744 )]);
1745
1746 let after = apply_inputs(before, &inputs).unwrap();
1747
1748 let queries = find_queries(&after);
1749 dbg!(&queries);
1750
1751 assert_eq!(queries.len(), 0);
1752 }
1753
1754 #[test]
1755 fn test_apply_fees() {
1756 let before = get_subject_tx();
1757
1758 let args = BTreeMap::from([
1759 ("sender".to_string(), ArgValue::Address(b"abc".to_vec())),
1760 ("a".to_string(), ArgValue::Int(100)),
1761 ("b".to_string(), ArgValue::Int(200)),
1762 ]);
1763
1764 let before = apply_args(before, &args).unwrap().reduce().unwrap();
1765
1766 let after = before.apply_fees(100).unwrap().reduce().unwrap();
1767
1768 let queries = find_queries(&after);
1769
1770 let query = queries.get("source").unwrap();
1771
1772 assert_eq!(
1773 query,
1774 &InputQuery {
1775 address: Expression::Address(b"abc".to_vec()),
1776 min_amount: Expression::Assets(vec![AssetExpr {
1777 policy: Expression::None,
1778 asset_name: Expression::None,
1779 amount: Expression::Number(400),
1780 }]),
1781 r#ref: Expression::None,
1782 many: false,
1783 collateral: false,
1784 }
1785 );
1786 }
1787
1788 #[test]
1789 fn built_in_expression_is_reduced() {
1790 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::NoOp(Expression::Number(5))));
1791
1792 let after = op.reduce().unwrap();
1793
1794 assert_eq!(after, Expression::Number(5))
1795 }
1796
1797 #[test]
1798 fn numeric_add_is_reduced() {
1799 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
1800 Expression::Number(1),
1801 Expression::Number(5),
1802 )));
1803
1804 let after = op.reduce().unwrap();
1805
1806 assert_eq!(after, Expression::Number(6));
1807 }
1808
1809 #[test]
1810 fn numeric_sub_is_reduced() {
1811 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Sub(
1812 Expression::Number(8),
1813 Expression::Number(5),
1814 )));
1815
1816 let after = op.reduce().unwrap();
1817
1818 assert_eq!(after, Expression::Number(3));
1819 }
1820
1821 #[test]
1822 fn nested_numeric_binary_op_is_reduced() {
1823 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
1824 Expression::Number(1),
1825 Expression::EvalBuiltIn(Box::new(BuiltInOp::Sub(
1826 Expression::Number(5),
1827 Expression::Number(3),
1828 ))),
1829 )));
1830
1831 let after = op.reduce().unwrap();
1832
1833 assert_eq!(after, Expression::Number(3));
1834 }
1835
1836 #[test]
1837 fn numeric_mul_is_reduced() {
1838 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Mul(
1839 Expression::Number(6),
1840 Expression::Number(7),
1841 )));
1842
1843 let after = op.reduce().unwrap();
1844
1845 assert_eq!(after, Expression::Number(42));
1846 }
1847
1848 #[test]
1849 fn mul_binds_tighter_than_add_is_reduced() {
1850 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
1852 Expression::Number(2),
1853 Expression::EvalBuiltIn(Box::new(BuiltInOp::Mul(
1854 Expression::Number(3),
1855 Expression::Number(4),
1856 ))),
1857 )));
1858
1859 let after = op.reduce().unwrap();
1860
1861 assert_eq!(after, Expression::Number(14));
1862 }
1863
1864 #[test]
1865 fn asset_scaled_is_reduced() {
1866 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Mul(
1868 Expression::Assets(vec![AssetExpr {
1869 policy: Expression::Bytes(b"abc".to_vec()),
1870 asset_name: Expression::Bytes(b"111".to_vec()),
1871 amount: Expression::Number(100),
1872 }]),
1873 Expression::Number(3),
1874 )));
1875
1876 let reduced = op.reduce().unwrap();
1877
1878 match reduced {
1879 Expression::Assets(assets) => {
1880 assert_eq!(assets.len(), 1);
1881 assert_eq!(assets[0].policy, Expression::Bytes(b"abc".to_vec()));
1882 assert_eq!(assets[0].asset_name, Expression::Bytes(b"111".to_vec()));
1883 assert_eq!(assets[0].amount, Expression::Number(300));
1884 }
1885 _ => panic!("Expected assets"),
1886 };
1887 }
1888
1889 #[test]
1890 fn asset_scaled_commutes_is_reduced() {
1891 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Mul(
1893 Expression::Number(3),
1894 Expression::Assets(vec![AssetExpr {
1895 policy: Expression::Bytes(b"abc".to_vec()),
1896 asset_name: Expression::Bytes(b"111".to_vec()),
1897 amount: Expression::Number(100),
1898 }]),
1899 )));
1900
1901 let reduced = op.reduce().unwrap();
1902
1903 match reduced {
1904 Expression::Assets(assets) => {
1905 assert_eq!(assets.len(), 1);
1906 assert_eq!(assets[0].amount, Expression::Number(300));
1907 }
1908 _ => panic!("Expected assets"),
1909 };
1910 }
1911
1912 #[test]
1913 fn numeric_div_is_reduced() {
1914 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Div(
1916 Expression::Number(9),
1917 Expression::Number(2),
1918 )));
1919
1920 let after = op.reduce().unwrap();
1921
1922 assert_eq!(after, Expression::Number(4));
1923 }
1924
1925 #[test]
1926 fn div_binds_like_mul_is_reduced() {
1927 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Mul(
1929 Expression::EvalBuiltIn(Box::new(BuiltInOp::Div(
1930 Expression::Number(8),
1931 Expression::Number(4),
1932 ))),
1933 Expression::Number(2),
1934 )));
1935
1936 let after = op.reduce().unwrap();
1937
1938 assert_eq!(after, Expression::Number(4));
1939 }
1940
1941 #[test]
1942 fn asset_divided_is_reduced() {
1943 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Div(
1945 Expression::Assets(vec![AssetExpr {
1946 policy: Expression::Bytes(b"abc".to_vec()),
1947 asset_name: Expression::Bytes(b"111".to_vec()),
1948 amount: Expression::Number(300),
1949 }]),
1950 Expression::Number(2),
1951 )));
1952
1953 let reduced = op.reduce().unwrap();
1954
1955 match reduced {
1956 Expression::Assets(assets) => {
1957 assert_eq!(assets.len(), 1);
1958 assert_eq!(assets[0].amount, Expression::Number(150));
1959 }
1960 _ => panic!("Expected assets"),
1961 };
1962 }
1963
1964 #[test]
1965 fn div_by_zero_errors() {
1966 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Div(
1967 Expression::Number(5),
1968 Expression::Number(0),
1969 )));
1970
1971 assert!(op.reduce().is_err());
1972 }
1973
1974 #[test]
1975 fn test_reduce_single_custom_asset_binary_op() {
1976 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
1977 Expression::Assets(vec![AssetExpr {
1978 policy: Expression::Bytes(b"abc".to_vec()),
1979 asset_name: Expression::Bytes(b"111".to_vec()),
1980 amount: Expression::Number(100),
1981 }]),
1982 Expression::Assets(vec![AssetExpr {
1983 policy: Expression::Bytes(b"abc".to_vec()),
1984 asset_name: Expression::Bytes(b"111".to_vec()),
1985 amount: Expression::Number(200),
1986 }]),
1987 )));
1988
1989 let reduced = op.reduce().unwrap();
1990
1991 match reduced {
1992 Expression::Assets(assets) => {
1993 assert_eq!(assets.len(), 1);
1994 assert_eq!(assets[0].policy, Expression::Bytes(b"abc".to_vec()));
1995 assert_eq!(assets[0].asset_name, Expression::Bytes(b"111".to_vec()));
1996 assert_eq!(assets[0].amount, Expression::Number(300));
1997 }
1998 _ => panic!("Expected assets"),
1999 };
2000 }
2001
2002 #[test]
2003 fn test_reduce_native_asset_binary_op() {
2004 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
2005 Expression::Assets(vec![AssetExpr {
2006 policy: Expression::None,
2007 asset_name: Expression::None,
2008 amount: Expression::Number(100),
2009 }]),
2010 Expression::Assets(vec![AssetExpr {
2011 policy: Expression::None,
2012 asset_name: Expression::None,
2013 amount: Expression::Number(200),
2014 }]),
2015 )));
2016
2017 let reduced = op.reduce().unwrap();
2018
2019 match reduced {
2020 Expression::Assets(assets) => {
2021 assert_eq!(assets.len(), 1);
2022 assert_eq!(assets[0].policy, Expression::None);
2023 assert_eq!(assets[0].asset_name, Expression::None);
2024 assert_eq!(assets[0].amount, Expression::Number(300));
2025 }
2026 _ => panic!("Expected assets"),
2027 };
2028 }
2029
2030 #[test]
2031 fn test_reduce_mixed_asset_binary_op() {
2032 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
2033 Expression::Assets(vec![AssetExpr {
2034 policy: Expression::None,
2035 asset_name: Expression::None,
2036 amount: Expression::Number(100),
2037 }]),
2038 Expression::Assets(vec![AssetExpr {
2039 policy: Expression::Bytes(b"abc".to_vec()),
2040 asset_name: Expression::Bytes(b"111".to_vec()),
2041 amount: Expression::Number(200),
2042 }]),
2043 )));
2044
2045 let reduced = op.reduce().unwrap();
2046
2047 match reduced {
2048 Expression::Assets(assets) => {
2049 assert_eq!(assets.len(), 2);
2050
2051 for asset in assets {
2052 if asset.policy == Expression::None {
2053 assert_eq!(asset.asset_name, Expression::None);
2054 assert_eq!(asset.amount, Expression::Number(100));
2055 } else {
2056 assert_eq!(asset.policy, Expression::Bytes(b"abc".to_vec()));
2057 assert_eq!(asset.asset_name, Expression::Bytes(b"111".to_vec()));
2058 assert_eq!(asset.amount, Expression::Number(200));
2059 }
2060 }
2061 }
2062 _ => panic!("Expected assets"),
2063 };
2064 }
2065
2066 #[test]
2067 fn test_reduce_coerce_noop() {
2068 let op = Expression::EvalCoerce(Box::new(Coerce::NoOp(Expression::Number(5))));
2069
2070 let reduced = op.reduce().unwrap();
2071
2072 match reduced {
2073 Expression::Number(5) => (),
2074 _ => panic!("Expected number 5"),
2075 };
2076 }
2077
2078 #[test]
2079 fn test_coerce_utxo_set_into_assets() {
2080 let utxos = vec![Utxo {
2081 r#ref: UtxoRef::new(b"abc", 1),
2082 address: b"abc".into(),
2083 datum: Some(Expression::Number(1)),
2084 assets: CanonicalAssets::from_defined_asset(b"abc", b"111", 1),
2085 script: None,
2086 }];
2087
2088 let op = Coerce::IntoAssets(Expression::UtxoSet(
2089 std::collections::HashSet::from_iter(utxos.clone().into_iter()).into(),
2090 ));
2091
2092 let reduced = op.reduce().unwrap();
2093
2094 assert_eq!(
2095 reduced,
2096 Coerce::NoOp(Expression::Assets(utxos[0].assets.clone().into()))
2097 );
2098 }
2099
2100 #[test]
2101 fn test_coerce_utxo_set_into_datum() {
2102 let utxos = vec![Utxo {
2103 r#ref: UtxoRef::new(b"abc", 1),
2104 address: b"abc".into(),
2105 datum: Some(Expression::Number(1)),
2106 assets: CanonicalAssets::from_naked_amount(1),
2107 script: None,
2108 }];
2109
2110 let op = Coerce::IntoDatum(Expression::UtxoSet(
2111 std::collections::HashSet::from_iter(utxos.clone().into_iter()).into(),
2112 ));
2113
2114 let reduced = op.reduce().unwrap();
2115
2116 assert_eq!(reduced, Coerce::NoOp(utxos[0].datum.clone().unwrap()));
2117 }
2118
2119 #[test]
2120 fn test_reduce_struct_property_access() {
2121 let object = Expression::Struct(StructExpr {
2122 constructor: 0,
2123 fields: vec![
2124 Expression::Number(1),
2125 Expression::Number(2),
2126 Expression::Number(3),
2127 ],
2128 });
2129
2130 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2131 object.clone(),
2132 Expression::Number(1),
2133 )));
2134
2135 let reduced = op.reduce().unwrap();
2136
2137 assert_eq!(reduced, Expression::Number(2));
2138
2139 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2140 object.clone(),
2141 Expression::Number(100),
2142 )));
2143
2144 let reduced = op.reduce();
2145
2146 match reduced {
2147 Err(Error::PropertyIndexNotFound(100, _)) => (),
2148 _ => panic!("Expected property index not found"),
2149 };
2150 }
2151
2152 #[test]
2153 fn test_reduce_list_property_access() {
2154 let object = Expression::List(vec![
2155 Expression::Number(1),
2156 Expression::Number(2),
2157 Expression::Number(3),
2158 ]);
2159
2160 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2161 object.clone(),
2162 Expression::Number(1),
2163 )));
2164
2165 let reduced = op.reduce();
2166
2167 match reduced {
2168 Ok(Expression::Number(2)) => (),
2169 _ => panic!("Expected number 2"),
2170 };
2171
2172 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2173 object.clone(),
2174 Expression::Number(100),
2175 )));
2176
2177 let reduced = op.reduce();
2178
2179 match reduced {
2180 Err(Error::PropertyIndexNotFound(100, _)) => (),
2181 _ => panic!("Expected property index not found"),
2182 };
2183 }
2184
2185 #[test]
2186 fn test_reduce_tuple_property_access() {
2187 let object = Expression::Tuple(vec![
2188 Expression::Number(1),
2189 Expression::Number(2),
2190 Expression::Number(3),
2191 ]);
2192
2193 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2194 object.clone(),
2195 Expression::Number(1),
2196 )));
2197
2198 let reduced = op.reduce();
2199
2200 match reduced {
2201 Ok(Expression::Number(2)) => (),
2202 _ => panic!("Expected number 2"),
2203 };
2204
2205 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2207 object.clone(),
2208 Expression::Number(2),
2209 )));
2210
2211 match op.reduce() {
2212 Ok(Expression::Number(3)) => (),
2213 _ => panic!("Expected number 3"),
2214 };
2215
2216 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2217 object.clone(),
2218 Expression::Number(100),
2219 )));
2220
2221 let reduced = op.reduce();
2222
2223 match reduced {
2224 Err(Error::PropertyIndexNotFound(100, _)) => (),
2225 _ => panic!("Expected property index not found"),
2226 };
2227 }
2228
2229 #[test]
2230 fn test_string_concat_is_reduced() {
2231 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Concat(
2232 Expression::String("hello".to_string()),
2233 Expression::String("world".to_string()),
2234 )));
2235
2236 let reduced = op.reduce().unwrap();
2237
2238 match reduced {
2239 Expression::String(s) => assert_eq!(s, "helloworld"),
2240 _ => panic!("Expected string 'helloworld'"),
2241 }
2242 }
2243
2244 #[test]
2245 fn test_string_number_concat_is_reduced() {
2246 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Concat(
2247 Expression::String("hello".to_string()),
2248 Expression::Number(123),
2249 )));
2250
2251 let reduced = op.reduce().unwrap();
2252
2253 match reduced {
2254 Expression::String(s) => assert_eq!(s, "hello123"),
2255 _ => panic!("Expected string 'hello123'"),
2256 }
2257 }
2258
2259 #[test]
2260 fn test_bytes_concat_is_reduced() {
2261 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Concat(
2262 Expression::Bytes(vec![1, 2, 3]),
2263 Expression::Bytes(vec![4, 5, 6]),
2264 )));
2265
2266 let reduced = op.reduce().unwrap();
2267
2268 match reduced {
2269 Expression::Bytes(b) => assert_eq!(b, vec![1, 2, 3, 4, 5, 6]),
2270 _ => panic!("Expected bytes [1, 2, 3, 4, 5, 6]"),
2271 }
2272 }
2273
2274 #[test]
2275 fn test_list_concat_is_reduced() {
2276 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Concat(
2277 Expression::List(vec![Expression::Number(1)]),
2278 Expression::List(vec![Expression::Number(2)]),
2279 )));
2280
2281 let reduced = op.reduce().unwrap();
2282
2283 match reduced {
2284 Expression::List(b) => {
2285 assert_eq!(b, vec![Expression::Number(1), Expression::Number(2)])
2286 }
2287 _ => panic!("Expected List [Number(1), Number(2)"),
2288 }
2289 }
2290
2291 #[test]
2292 fn test_concat_type_mismatch_error() {
2293 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Concat(
2294 Expression::String("hello".to_string()),
2295 Expression::Bytes(vec![1, 2, 3]),
2296 )));
2297
2298 let reduced = op.reduce();
2299
2300 match reduced {
2301 Err(Error::InvalidBinaryOp(op, _, _)) => assert_eq!(op, "concat"),
2302 _ => panic!("Expected InvalidBinaryOp error"),
2303 }
2304 }
2305
2306 #[test]
2307 fn test_concat_with_none() {
2308 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Concat(
2309 Expression::String("hello".to_string()),
2310 Expression::None,
2311 )));
2312
2313 let reduced = op.reduce().unwrap();
2314
2315 match reduced {
2316 Expression::String(s) => assert_eq!(s, "hello"),
2317 _ => panic!("Expected string 'hello'"),
2318 }
2319 }
2320
2321 #[test]
2322 fn test_min_utxo_add_non_reduction() {
2323 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Add(
2324 Expression::Assets(vec![AssetExpr {
2325 policy: Expression::None,
2326 asset_name: Expression::None,
2327 amount: Expression::Number(29),
2328 }]),
2329 Expression::EvalCompiler(Box::new(CompilerOp::ComputeMinUtxo(Expression::Number(20)))),
2330 )));
2331
2332 let reduced = op.clone().reduce().unwrap();
2333
2334 assert!(op == reduced)
2335 }
2336
2337 #[test]
2338 fn test_min_utxo_sub_non_reduction() {
2339 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Sub(
2340 Expression::Assets(vec![AssetExpr {
2341 policy: Expression::None,
2342 asset_name: Expression::None,
2343 amount: Expression::Number(29),
2344 }]),
2345 Expression::EvalCompiler(Box::new(CompilerOp::ComputeMinUtxo(Expression::Number(20)))),
2346 )));
2347
2348 let reduced = op.clone().reduce().unwrap();
2349
2350 assert!(op == reduced)
2351 }
2352
2353 #[test]
2354 fn test_index_list_with_expression() {
2355 let list = Expression::List(vec![
2356 Expression::String("first".to_string()),
2357 Expression::String("second".to_string()),
2358 Expression::String("third".to_string()),
2359 ]);
2360
2361 let index_expr = Expression::Number(1);
2362 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(list.clone(), index_expr)));
2363
2364 let reduced = op.reduce().unwrap();
2365
2366 match reduced {
2367 Expression::String(s) => assert_eq!(s, "second"),
2368 _ => panic!("Expected string 'second'"),
2369 }
2370 }
2371
2372 #[test]
2373 fn test_index_list_out_of_bounds() {
2374 let list = Expression::List(vec![Expression::Number(1), Expression::Number(2)]);
2375
2376 let index_expr = Expression::Number(5);
2377 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(list.clone(), index_expr)));
2378
2379 let reduced = op.reduce();
2380
2381 match reduced {
2382 Err(Error::PropertyIndexNotFound(5, _)) => (),
2383 _ => panic!("Expected PropertyIndexNotFound error"),
2384 }
2385 }
2386
2387 #[test]
2388 fn test_index_tuple_with_expression() {
2389 let tuple = Expression::Tuple(vec![
2390 Expression::String("left".to_string()),
2391 Expression::String("right".to_string()),
2392 ]);
2393
2394 let index_expr = Expression::Number(0);
2395 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(tuple.clone(), index_expr)));
2396
2397 let reduced = op.reduce().unwrap();
2398
2399 match reduced {
2400 Expression::String(s) => assert_eq!(s, "left"),
2401 _ => panic!("Expected string 'left'"),
2402 }
2403
2404 let index_expr = Expression::Number(1);
2405 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(tuple.clone(), index_expr)));
2406
2407 let reduced = op.reduce().unwrap();
2408
2409 match reduced {
2410 Expression::String(s) => assert_eq!(s, "right"),
2411 _ => panic!("Expected string 'right'"),
2412 }
2413 }
2414
2415 #[test]
2416 fn test_n_tuple_params_and_apply() {
2417 let tuple = Expression::Tuple(vec![
2419 Expression::Number(1),
2420 Expression::EvalParam(Box::new(Param::ExpectValue("a".to_string(), Type::Int))),
2421 Expression::EvalParam(Box::new(Param::ExpectValue("b".to_string(), Type::Bytes))),
2422 ]);
2423
2424 let params = tuple.params();
2426 assert_eq!(params.len(), 2);
2427 assert_eq!(params.get("a"), Some(&Type::Int));
2428 assert_eq!(params.get("b"), Some(&Type::Bytes));
2429
2430 assert!(!tuple.is_constant());
2432
2433 let args = BTreeMap::from([
2434 ("a".to_string(), ArgValue::Int(42)),
2435 ("b".to_string(), ArgValue::Bytes(vec![0xff])),
2436 ]);
2437
2438 let reduced = tuple.apply_args(&args).unwrap().reduce().unwrap();
2439
2440 assert_eq!(
2441 reduced,
2442 Expression::Tuple(vec![
2443 Expression::Number(1),
2444 Expression::Number(42),
2445 Expression::Bytes(vec![0xff]),
2446 ])
2447 );
2448 assert!(reduced.is_constant());
2449 }
2450
2451 #[test]
2452 fn test_index_struct_with_expression() {
2453 let struct_expr = Expression::Struct(StructExpr {
2454 constructor: 0,
2455 fields: vec![
2456 Expression::String("field0".to_string()),
2457 Expression::String("field1".to_string()),
2458 Expression::String("field2".to_string()),
2459 ],
2460 });
2461
2462 let index_expr = Expression::Number(1);
2463 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2464 struct_expr.clone(),
2465 index_expr,
2466 )));
2467
2468 let reduced = op.reduce().unwrap();
2469
2470 match reduced {
2471 Expression::String(s) => assert_eq!(s, "field1"),
2472 _ => panic!("Expected string 'field1'"),
2473 }
2474 }
2475
2476 #[test]
2477 fn test_index_none_expression() {
2478 let none_expr = Expression::None;
2479 let index_expr = Expression::Number(0);
2480
2481 let op = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(none_expr, index_expr)));
2482
2483 let reduced = op.reduce();
2484
2485 match reduced {
2486 Err(Error::PropertyIndexNotFound(0, _)) => (),
2487 _ => panic!("Expected PropertyIndexNotFound error for None expression"),
2488 }
2489 }
2490
2491 #[test]
2492 fn test_indexable_trait_on_expression() {
2493 let list_expr = Expression::List(vec![Expression::Number(10), Expression::Number(20)]);
2494
2495 let result = list_expr.index(Expression::Number(0));
2496 assert_eq!(result, Some(Expression::Number(10)));
2497
2498 let result = list_expr.index(Expression::Number(1));
2499 assert_eq!(result, Some(Expression::Number(20)));
2500
2501 let result = list_expr.index(Expression::Number(2));
2502 assert_eq!(result, None);
2503
2504 let tuple_expr = Expression::Tuple(vec![
2505 Expression::Number(100),
2506 Expression::Number(200),
2507 Expression::Number(300),
2508 ]);
2509
2510 let result = tuple_expr.index(Expression::Number(0));
2511 assert_eq!(result, Some(Expression::Number(100)));
2512
2513 let result = tuple_expr.index(Expression::Number(1));
2514 assert_eq!(result, Some(Expression::Number(200)));
2515
2516 let result = tuple_expr.index(Expression::Number(2));
2517 assert_eq!(result, Some(Expression::Number(300)));
2518
2519 let result = tuple_expr.index(Expression::Number(3));
2520 assert_eq!(result, None);
2521 }
2522
2523 #[test]
2524 fn test_nested_property_access() {
2525 let nested_expr = Expression::List(vec![
2526 Expression::Tuple(vec![Expression::Number(1), Expression::Number(2)]),
2527 Expression::Tuple(vec![Expression::Number(3), Expression::Number(4)]),
2528 ]);
2529
2530 let first_access = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2532 nested_expr,
2533 Expression::Number(1),
2534 )));
2535
2536 let second_access = Expression::EvalBuiltIn(Box::new(BuiltInOp::Property(
2537 first_access,
2538 Expression::Number(0),
2539 )));
2540
2541 let reduced = second_access.reduce().unwrap();
2542
2543 match reduced {
2544 Expression::Number(n) => assert_eq!(n, 3),
2545 _ => panic!("Expected number 3"),
2546 }
2547 }
2548
2549 #[test]
2550 fn test_arg_value_list_into_expr() {
2551 let arg = ArgValue::List(vec![ArgValue::Int(1), ArgValue::Int(2)]);
2552 assert_eq!(
2553 arg_value_into_expr(arg),
2554 Expression::List(vec![Expression::Number(1), Expression::Number(2)])
2555 );
2556 }
2557
2558 #[test]
2559 fn test_arg_value_tuple_into_expr() {
2560 let arg = ArgValue::Tuple(vec![ArgValue::Int(7), ArgValue::Bytes(vec![0xff])]);
2561 assert_eq!(
2562 arg_value_into_expr(arg),
2563 Expression::Tuple(vec![Expression::Number(7), Expression::Bytes(vec![0xff])])
2564 );
2565 }
2566
2567 #[test]
2568 fn test_arg_value_map_into_expr() {
2569 let arg = ArgValue::Map(vec![(
2570 ArgValue::String("k".to_string()),
2571 ArgValue::Int(100),
2572 )]);
2573 assert_eq!(
2574 arg_value_into_expr(arg),
2575 Expression::Map(vec![(
2576 Expression::String("k".to_string()),
2577 Expression::Number(100)
2578 )])
2579 );
2580 }
2581
2582 #[test]
2583 fn test_arg_value_struct_into_expr() {
2584 let arg = ArgValue::Struct {
2585 constructor: 1,
2586 fields: vec![ArgValue::Int(5)],
2587 };
2588 assert_eq!(
2589 arg_value_into_expr(arg),
2590 Expression::Struct(StructExpr {
2591 constructor: 1,
2592 fields: vec![Expression::Number(5)],
2593 })
2594 );
2595 }
2596
2597 #[test]
2598 fn test_apply_args_nested_struct() {
2599 let template = Expression::EvalParam(Box::new(Param::ExpectValue(
2602 "meta".to_string(),
2603 Type::Custom("Meta".to_string()),
2604 )));
2605
2606 assert!(!template.is_constant());
2607
2608 let args = BTreeMap::from([(
2609 "meta".to_string(),
2610 ArgValue::Struct {
2611 constructor: 0,
2612 fields: vec![
2613 ArgValue::List(vec![ArgValue::Int(1), ArgValue::Int(2), ArgValue::Int(3)]),
2614 ArgValue::Int(7),
2615 ],
2616 },
2617 )]);
2618
2619 let reduced = template.apply_args(&args).unwrap().reduce().unwrap();
2620
2621 assert_eq!(
2622 reduced,
2623 Expression::Struct(StructExpr {
2624 constructor: 0,
2625 fields: vec![
2626 Expression::List(vec![
2627 Expression::Number(1),
2628 Expression::Number(2),
2629 Expression::Number(3),
2630 ]),
2631 Expression::Number(7),
2632 ],
2633 })
2634 );
2635 assert!(reduced.is_constant());
2636 }
2637}