1use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13
14use crate::{
15 encoding::{TirRoot, TirVersion},
16 model::core::*,
17 Node, Visitor,
18};
19
20pub const IR_VERSION: &str = "v1beta0";
21
22#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
23pub struct StructExpr {
24 pub constructor: usize,
25 pub fields: Vec<Expression>,
26}
27
28impl StructExpr {
29 pub fn unit() -> Self {
30 Self {
31 constructor: 0,
32 fields: vec![],
33 }
34 }
35}
36
37#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
38pub enum Coerce {
39 NoOp(Expression),
40 IntoAssets(Expression),
41 IntoDatum(Expression),
42 IntoScript(Expression),
43}
44
45#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
54pub enum BuiltInOp {
55 NoOp(Expression),
56 Add(Expression, Expression),
57 Sub(Expression, Expression),
58 Concat(Expression, Expression),
59 Negate(Expression),
60 Property(Expression, Expression),
61 Mul(Expression, Expression),
63 Div(Expression, Expression),
64}
65
66#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
75pub enum CompilerOp {
76 BuildScriptAddress(Expression),
77 ComputeMinUtxo(Expression),
78 ComputeTipSlot,
79 ComputeSlotToTime(Expression),
80 ComputeTimeToSlot(Expression),
81}
82
83#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
84pub struct AssetExpr {
85 pub policy: Expression,
86 pub asset_name: Expression,
87 pub amount: Expression,
88}
89
90impl AssetExpr {
91 pub fn class_matches(&self, other: &Self) -> bool {
92 self.policy.as_bytes() == other.policy.as_bytes()
93 && self.asset_name.as_bytes() == other.asset_name.as_bytes()
94 }
95}
96
97#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
104pub struct AdHocDirective {
105 pub name: String,
106 pub data: HashMap<String, Expression>,
107}
108
109#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
110pub enum ScriptSource {
111 Embedded(Expression),
112 UtxoRef {
113 r#ref: Expression,
114 source: Option<Expression>,
115 },
116}
117
118impl ScriptSource {
119 pub fn new_ref(r#ref: Expression, source: Expression) -> Self {
120 Self::UtxoRef {
121 r#ref,
122 source: Some(source),
123 }
124 }
125
126 pub fn new_embedded(source: Expression) -> Self {
127 Self::Embedded(source)
128 }
129
130 pub fn expect_parameter(policy_name: String) -> Self {
131 Self::Embedded(
132 Param::ExpectValue(
133 format!("{}_script", policy_name.to_lowercase()),
134 Type::Bytes,
135 )
136 .into(),
137 )
138 }
139
140 pub fn expect_ref_input(policy_name: String, r#ref: Expression) -> Self {
141 Self::UtxoRef {
142 r#ref: r#ref.clone(),
143 source: Some(
144 Coerce::IntoScript(
145 Param::ExpectInput(
146 format!("{}_script", policy_name.to_lowercase()),
147 InputQuery {
148 address: Expression::None,
149 min_amount: Expression::None,
150 many: false,
151 r#ref,
152 collateral: false,
153 },
154 )
155 .into(),
156 )
157 .into(),
158 ),
159 }
160 }
161
162 pub fn as_utxo_ref(&self) -> Option<Expression> {
163 match self {
164 Self::UtxoRef { r#ref, .. } => Some(r#ref.clone()),
165 Self::Embedded(Expression::UtxoRefs(x)) => Some(Expression::UtxoRefs(x.clone())),
166 _ => None,
167 }
168 }
169}
170
171#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
172pub struct PolicyExpr {
173 pub name: String,
174 pub hash: Expression,
175 pub script: ScriptSource,
176}
177
178#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
179pub enum Param {
180 Set(Expression),
181 ExpectValue(String, Type),
182 ExpectInput(String, InputQuery),
183 ExpectFees,
184}
185
186#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
187pub enum Expression {
188 #[default]
189 None,
190
191 List(Vec<Expression>),
192 Map(Vec<(Expression, Expression)>),
193 Tuple(Vec<Expression>),
194 Struct(StructExpr),
195 Bytes(Vec<u8>),
196 Number(i128),
197 Bool(bool),
198 String(String),
199 Address(Vec<u8>),
200 Hash(Vec<u8>),
201 UtxoRefs(Vec<UtxoRef>),
202 UtxoSet(UtxoSet),
203 Assets(Vec<AssetExpr>),
204
205 EvalParam(Box<Param>),
206 EvalBuiltIn(Box<BuiltInOp>),
207 EvalCompiler(Box<CompilerOp>),
208 EvalCoerce(Box<Coerce>),
209
210 AdHocDirective(Box<AdHocDirective>),
212}
213
214impl Expression {
215 pub fn is_none(&self) -> bool {
216 matches!(self, Self::None)
217 }
218
219 pub fn as_option(&self) -> Option<&Self> {
220 match self {
221 Self::None => None,
222 _ => Some(self),
223 }
224 }
225
226 pub fn into_option(self) -> Option<Self> {
227 match self {
228 Self::None => None,
229 _ => Some(self),
230 }
231 }
232
233 pub fn as_bytes(&self) -> Option<&[u8]> {
234 match self {
235 Self::Bytes(bytes) => Some(bytes),
236 Self::String(s) => Some(s.as_bytes()),
237 Self::Address(x) => Some(x),
238 Self::Hash(x) => Some(x),
239 _ => None,
240 }
241 }
242
243 pub fn as_number(&self) -> Option<i128> {
244 match self {
245 Self::Number(x) => Some(*x),
246 _ => None,
247 }
248 }
249
250 pub fn as_assets(&self) -> Option<&[AssetExpr]> {
251 match self {
252 Self::Assets(assets) => Some(assets),
253 _ => None,
254 }
255 }
256
257 pub fn as_utxo_refs(&self) -> Option<&[UtxoRef]> {
258 match self {
259 Self::UtxoRefs(refs) => Some(refs),
260 _ => None,
261 }
262 }
263}
264
265impl From<BuiltInOp> for Expression {
266 fn from(op: BuiltInOp) -> Self {
267 Self::EvalBuiltIn(Box::new(op))
268 }
269}
270
271impl From<CompilerOp> for Expression {
272 fn from(op: CompilerOp) -> Self {
273 Self::EvalCompiler(Box::new(op))
274 }
275}
276
277impl From<Coerce> for Expression {
278 fn from(coerce: Coerce) -> Self {
279 Self::EvalCoerce(Box::new(coerce))
280 }
281}
282
283impl From<Param> for Expression {
284 fn from(param: Param) -> Self {
285 Self::EvalParam(Box::new(param))
286 }
287}
288
289#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
290pub struct InputQuery {
291 pub address: Expression,
292 pub min_amount: Expression,
293 pub r#ref: Expression,
294 pub many: bool,
295 pub collateral: bool,
296}
297
298#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
299pub struct Input {
300 pub name: String,
301 pub utxos: Expression,
302 pub redeemer: Expression,
303}
304
305#[derive(Serialize, Deserialize, Debug, Clone)]
306pub struct Output {
307 pub address: Expression,
308 pub datum: Expression,
309 pub amount: Expression,
310 pub optional: bool,
311}
312
313#[derive(Serialize, Deserialize, Debug, Clone)]
314pub struct Validity {
315 pub since: Expression,
316 pub until: Expression,
317}
318
319#[derive(Serialize, Deserialize, Debug, Clone)]
320pub struct Mint {
321 pub amount: Expression,
322 pub redeemer: Expression,
323}
324
325#[derive(Serialize, Deserialize, Debug, Clone)]
326pub struct Collateral {
327 pub utxos: Expression,
328}
329
330#[derive(Serialize, Deserialize, Debug, Clone)]
331pub struct Metadata {
332 pub key: Expression,
333 pub value: Expression,
334}
335
336#[derive(Serialize, Deserialize, Debug, Clone)]
337pub struct Signers {
338 pub signers: Vec<Expression>,
339}
340
341#[derive(Serialize, Deserialize, Debug, Clone)]
342pub struct Tx {
343 pub fees: Expression,
344 pub references: Vec<Expression>,
345 pub inputs: Vec<Input>,
346 pub outputs: Vec<Output>,
347 pub validity: Option<Validity>,
348 pub mints: Vec<Mint>,
349 pub burns: Vec<Mint>,
350 pub adhoc: Vec<AdHocDirective>,
351 pub collateral: Vec<Collateral>,
352 pub signers: Option<Signers>,
353 pub metadata: Vec<Metadata>,
354}
355
356impl TirRoot for Tx {
357 const VERSION: TirVersion = TirVersion::V1Beta0;
358}
359
360impl<T: Node> Node for Option<T> {
361 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
362 self.map(|x| x.apply(visitor)).transpose()
363 }
364}
365
366impl<T: Node> Node for Box<T> {
367 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
368 let visited = (*self).apply(visitor)?;
369 Ok(Box::new(visited))
370 }
371}
372
373impl Node for (Expression, Expression) {
374 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
375 let (a, b) = self;
376 Ok((a.apply(visitor)?, b.apply(visitor)?))
377 }
378}
379
380impl<T: Node> Node for Vec<T> {
381 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
382 self.into_iter().map(|x| x.apply(visitor)).collect()
383 }
384}
385
386impl Node for StructExpr {
387 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
388 let visited = Self {
389 constructor: self.constructor,
390 fields: self.fields.apply(visitor)?,
391 };
392
393 Ok(visited)
394 }
395}
396
397impl Node for AssetExpr {
398 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
399 let visited = Self {
400 policy: self.policy.apply(visitor)?,
401 asset_name: self.asset_name.apply(visitor)?,
402 amount: self.amount.apply(visitor)?,
403 };
404
405 Ok(visited)
406 }
407}
408
409impl Node for InputQuery {
410 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
411 let visited = Self {
412 address: self.address.apply(visitor)?,
413 min_amount: self.min_amount.apply(visitor)?,
414 r#ref: self.r#ref.apply(visitor)?,
415 ..self
416 };
417
418 Ok(visited)
419 }
420}
421
422impl Node for Param {
423 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
424 let visited = match self {
425 Param::Set(x) => Param::Set(x.apply(visitor)?),
426 Param::ExpectValue(name, ty) => Param::ExpectValue(name, ty),
427 Param::ExpectInput(name, query) => Param::ExpectInput(name, query.apply(visitor)?),
428 Param::ExpectFees => Param::ExpectFees,
429 };
430
431 Ok(visited)
432 }
433}
434
435impl Node for BuiltInOp {
436 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
437 let visited = match self {
438 BuiltInOp::NoOp(x) => BuiltInOp::NoOp(x.apply(visitor)?),
439 BuiltInOp::Add(a, b) => BuiltInOp::Add(a.apply(visitor)?, b.apply(visitor)?),
440 BuiltInOp::Sub(a, b) => BuiltInOp::Sub(a.apply(visitor)?, b.apply(visitor)?),
441 BuiltInOp::Mul(a, b) => BuiltInOp::Mul(a.apply(visitor)?, b.apply(visitor)?),
442 BuiltInOp::Div(a, b) => BuiltInOp::Div(a.apply(visitor)?, b.apply(visitor)?),
443 BuiltInOp::Concat(a, b) => BuiltInOp::Concat(a.apply(visitor)?, b.apply(visitor)?),
444 BuiltInOp::Negate(x) => BuiltInOp::Negate(x.apply(visitor)?),
445 BuiltInOp::Property(x, i) => BuiltInOp::Property(x.apply(visitor)?, i),
446 };
447
448 Ok(visited)
449 }
450}
451
452impl Node for CompilerOp {
453 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
454 let visited = match self {
455 CompilerOp::BuildScriptAddress(x) => CompilerOp::BuildScriptAddress(x.apply(visitor)?),
456 CompilerOp::ComputeMinUtxo(x) => CompilerOp::ComputeMinUtxo(x.apply(visitor)?),
457 CompilerOp::ComputeTipSlot => CompilerOp::ComputeTipSlot,
458 CompilerOp::ComputeSlotToTime(x) => CompilerOp::ComputeSlotToTime(x.apply(visitor)?),
459 CompilerOp::ComputeTimeToSlot(x) => CompilerOp::ComputeTimeToSlot(x.apply(visitor)?),
460 };
461
462 Ok(visited)
463 }
464}
465
466impl Node for Coerce {
467 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
468 let visited = match self {
469 Coerce::NoOp(x) => Coerce::NoOp(x.apply(visitor)?),
470 Coerce::IntoAssets(x) => Coerce::IntoAssets(x.apply(visitor)?),
471 Coerce::IntoDatum(x) => Coerce::IntoDatum(x.apply(visitor)?),
472 Coerce::IntoScript(x) => Coerce::IntoScript(x.apply(visitor)?),
473 };
474
475 Ok(visited)
476 }
477}
478
479impl Node for Expression {
480 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
481 let visited = match self {
483 Expression::List(x) => Expression::List(x.apply(visitor)?),
484 Expression::Map(x) => Expression::Map(x.apply(visitor)?),
485 Expression::Tuple(x) => Expression::Tuple(x.apply(visitor)?),
486 Expression::Struct(x) => Expression::Struct(x.apply(visitor)?),
487 Expression::Assets(x) => Expression::Assets(x.apply(visitor)?),
488 Expression::EvalParam(x) => Expression::EvalParam(x.apply(visitor)?),
489 Expression::AdHocDirective(x) => Expression::AdHocDirective(x.apply(visitor)?),
490 Expression::EvalBuiltIn(x) => Expression::EvalBuiltIn(x.apply(visitor)?),
491 Expression::EvalCompiler(x) => Expression::EvalCompiler(x.apply(visitor)?),
492 Expression::EvalCoerce(x) => Expression::EvalCoerce(x.apply(visitor)?),
493
494 Expression::Bytes(x) => Expression::Bytes(x),
496 Expression::None => Expression::None,
497 Expression::Number(x) => Expression::Number(x),
498 Expression::Bool(x) => Expression::Bool(x),
499 Expression::String(x) => Expression::String(x),
500 Expression::Address(x) => Expression::Address(x),
501 Expression::Hash(x) => Expression::Hash(x),
502 Expression::UtxoRefs(x) => Expression::UtxoRefs(x),
503 Expression::UtxoSet(x) => Expression::UtxoSet(x),
504 };
505
506 visitor.reduce(visited)
508 }
509}
510
511impl Node for Input {
512 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
513 let visited = Self {
514 utxos: self.utxos.apply(visitor)?,
515 redeemer: self.redeemer.apply(visitor)?,
516 ..self
517 };
518
519 Ok(visited)
520 }
521}
522
523impl Node for Output {
524 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
525 let visited = Self {
526 address: self.address.apply(visitor)?,
527 datum: self.datum.apply(visitor)?,
528 amount: self.amount.apply(visitor)?,
529 optional: self.optional,
530 };
531
532 Ok(visited)
533 }
534}
535
536impl Node for Validity {
537 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
538 let visited = Self {
539 since: self.since.apply(visitor)?,
540 until: self.until.apply(visitor)?,
541 };
542
543 Ok(visited)
544 }
545}
546
547impl Node for Mint {
548 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
549 let visited = Self {
550 amount: self.amount.apply(visitor)?,
551 redeemer: self.redeemer.apply(visitor)?,
552 };
553
554 Ok(visited)
555 }
556}
557
558impl Node for Collateral {
559 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
560 let visited = Self {
561 utxos: self.utxos.apply(visitor)?,
562 };
563
564 Ok(visited)
565 }
566}
567
568impl Node for Metadata {
569 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
570 let visited = Self {
571 key: self.key.apply(visitor)?,
572 value: self.value.apply(visitor)?,
573 };
574
575 Ok(visited)
576 }
577}
578
579impl Node for Signers {
580 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
581 let visited = Self {
582 signers: self.signers.apply(visitor)?,
583 };
584
585 Ok(visited)
586 }
587}
588
589impl Node for HashMap<String, Expression> {
590 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
591 let visited: Vec<_> = self
592 .into_iter()
593 .map(|(k, v)| visitor.reduce(v).map(|v| (k, v)))
594 .collect::<Result<_, _>>()?;
595
596 Ok(visited.into_iter().collect())
597 }
598}
599
600impl Node for AdHocDirective {
601 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
602 let visited = Self {
603 name: self.name,
604 data: self.data.apply(visitor)?,
605 };
606
607 Ok(visited)
608 }
609}
610
611impl Node for Tx {
612 fn apply<V: Visitor>(self, visitor: &mut V) -> Result<Self, crate::reduce::Error> {
613 let visited = Self {
614 fees: self.fees.apply(visitor)?,
615 references: self.references.apply(visitor)?,
616 inputs: self.inputs.apply(visitor)?,
617 outputs: self.outputs.apply(visitor)?,
618 validity: self.validity.apply(visitor)?,
619 mints: self.mints.apply(visitor)?,
620 burns: self.burns.apply(visitor)?,
621 adhoc: self.adhoc.apply(visitor)?,
622 collateral: self.collateral.apply(visitor)?,
623 signers: self.signers.apply(visitor)?,
624 metadata: self.metadata.apply(visitor)?,
625 };
626
627 Ok(visited)
628 }
629}