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