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