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