diff --git a/.gitignore b/.gitignore index 34d718f..0d6b06b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ -db/ -data/ -tmp/ - result secrets/ diff --git a/src/data/base.rs b/src/data/base.rs new file mode 100644 index 0000000..32aeb29 --- /dev/null +++ b/src/data/base.rs @@ -0,0 +1,182 @@ +use crate::utils::v2a; + +use super::plutus::{self, PData}; + +#[derive(Debug, Clone)] +pub struct Index(pub u64); + +impl PData for Index { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::int(self.0.into()) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(plutus::unint(data)?.try_into()?)) + } +} + +impl Index { + pub fn incr(&self) -> Self { + Self(self.0 + 1) + } +} + +#[derive(Debug, Clone)] +pub struct Timestamp(pub u64); + +impl PData for Timestamp { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::int(self.0.into()) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(plutus::unint(data)?.try_into()?)) + } +} + +#[derive(Debug, Clone)] +pub struct TimeDelta(pub u64); + +impl PData for TimeDelta { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::int(self.0.into()) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(plutus::unint(data)?.try_into()?)) + } +} + +#[derive(Debug, Clone)] +pub struct Amount(pub u64); + +impl PData for Amount { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::int(self.0.into()) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(plutus::unint(data)?.try_into()?)) + } +} + +impl Amount { + fn add(&self, x: u64) -> Self { + Self(self.0 + x) + } + fn sub(&self, x: u64) -> anyhow::Result { + if x <= self.0 { + Ok(Self(self.0 - x)) + } else { + panic!("Make proper error") + } + } +} + +#[derive(Debug, Clone)] +pub struct Hash32([u8; 32]); + +impl PData for Hash32 { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::bytes(&self.0) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(v2a(plutus::unbytes(data)?)?)) + } +} + +#[derive(Debug, Clone)] +pub struct Hash28(pub [u8; 28]); + +impl PData for Hash28 { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::bytes(&self.0) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(v2a(plutus::unbytes(data)?)?)) + } +} + +#[derive(Debug, Clone)] +pub struct Secret(pub [u8; 32]); + +impl PData for Secret { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::bytes(&self.0) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(v2a(plutus::unbytes(data)?)?)) + } +} + +#[derive(Debug, Clone)] +pub struct VKey(pub [u8; 32]); + +impl PData for VKey { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::bytes(&self.0) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(v2a(plutus::unbytes(data)?)?)) + } +} + +#[derive(Debug, Clone)] +pub struct Signature(pub [u8; 64]); + +impl PData for Signature { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::bytes(&self.0) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(v2a(plutus::unbytes(data)?)?)) + } +} + +#[derive(Debug, Clone)] +pub struct Tag(pub Vec); + +impl PData for Tag { + fn to_plutus_data(&self) -> uplc::PlutusData { + plutus::bytes(&self.0) + } + + fn from_plutus_data(data: &uplc::PlutusData) -> anyhow::Result + where + Self: Sized, + { + Ok(Self(plutus::unbytes(data)?)) + } +} diff --git a/src/data/cheque_body.rs b/src/data/cheque_body.rs new file mode 100644 index 0000000..39fabab --- /dev/null +++ b/src/data/cheque_body.rs @@ -0,0 +1,52 @@ +use anyhow::{anyhow, Result}; + +use pallas_primitives::PlutusData; + +use super::base::{Amount, Hash32, Index, Timestamp}; +use super::plutus::{self, PData}; + +#[derive(Debug, Clone)] +pub struct ChequeBody { + index: Index, + amount: Amount, + timeout: Timestamp, + image: Hash32, +} + +impl ChequeBody { + pub fn new(index: Index, amount: Amount, timeout: Timestamp, image: Hash32) -> Self { + Self { + index, + amount, + timeout, + image, + } + } +} + +impl PData for ChequeBody { + fn to_plutus_data(self: &Self) -> PlutusData { + let data = plutus::list(&vec![ + self.index.to_plutus_data(), + self.amount.to_plutus_data(), + self.timeout.to_plutus_data(), + self.image.to_plutus_data(), + ]); + data + } + + fn from_plutus_data(d: &PlutusData) -> Result { + match &plutus::unlist(d)?[..] { + [a, b, c, d] => { + let r = Self::new( + PData::from_plutus_data(a)?, + PData::from_plutus_data(b)?, + PData::from_plutus_data(c)?, + PData::from_plutus_data(d)?, + ); + Ok(r) + } + _ => Err(anyhow!("bad length")), + } + } +} diff --git a/src/data/constants.rs b/src/data/constants.rs new file mode 100644 index 0000000..347a71f --- /dev/null +++ b/src/data/constants.rs @@ -0,0 +1,52 @@ +use super::base::{Tag, TimeDelta, VKey}; +use anyhow::anyhow; + +use pallas_primitives::PlutusData; + +use super::plutus::{self, PData}; + +#[derive(Debug, Clone)] +pub struct Constants { + pub tag: Tag, + pub add_vkey: VKey, + pub sub_vkey: VKey, + pub close_period: TimeDelta, +} + +impl Constants { + pub fn new(tag: Tag, add_vkey: VKey, sub_vkey: VKey, close_period: TimeDelta) -> Self { + Self { + tag, + add_vkey, + sub_vkey, + close_period, + } + } +} + +impl PData for Constants { + fn to_plutus_data(self: &Self) -> PlutusData { + let data = plutus::list(&vec![ + self.tag.to_plutus_data(), + self.add_vkey.to_plutus_data(), + self.sub_vkey.to_plutus_data(), + self.close_period.to_plutus_data(), + ]); + data + } + + fn from_plutus_data(d: &PlutusData) -> anyhow::Result { + match &plutus::unlist(d)?[..] { + [a, b, c, d] => { + let r = Self::new( + PData::from_plutus_data(a)?, + PData::from_plutus_data(b)?, + PData::from_plutus_data(c)?, + PData::from_plutus_data(d)?, + ); + Ok(r) + } + _ => Err(anyhow!("bad length")), + } + } +} diff --git a/src/data/datum.rs b/src/data/datum.rs new file mode 100644 index 0000000..43f5b7e --- /dev/null +++ b/src/data/datum.rs @@ -0,0 +1,49 @@ +use super::base::Hash28; +use super::constants::Constants; +use super::stage::Stage; +use anyhow::anyhow; + +use pallas_primitives::PlutusData; + +use super::plutus::{self, PData}; + +pub struct Datum { + pub own_hash: Hash28, + pub constants: Constants, + pub stage: Stage, +} + +impl Datum { + pub fn new(own_hash: Hash28, constants: Constants, stage: Stage) -> Self { + Self { + own_hash, + constants, + stage, + } + } +} + +impl PData for Datum { + fn to_plutus_data(self: &Self) -> PlutusData { + let data = plutus::list(&vec![ + self.own_hash.to_plutus_data(), + self.constants.to_plutus_data(), + self.stage.to_plutus_data(), + ]); + data + } + + fn from_plutus_data(d: &PlutusData) -> anyhow::Result { + match &plutus::unlist(d)?[..] { + [a, b, c] => { + let r = Self::new( + PData::from_plutus_data(a)?, + PData::from_plutus_data(b)?, + PData::from_plutus_data(c)?, + ); + Ok(r) + } + _ => Err(anyhow!("bad length")), + } + } +} diff --git a/src/data/mix.rs b/src/data/mix.rs new file mode 100644 index 0000000..eb6f76a --- /dev/null +++ b/src/data/mix.rs @@ -0,0 +1,100 @@ +use anyhow::{anyhow, Result}; +use pallas_primitives::PlutusData; + +use super::{ + base::{Secret, Signature}, + cheque_body::ChequeBody, + plutus::{self, constr, PData}, + unlocked::Unlocked, +}; + +#[derive(Debug, Clone)] +pub enum Mix { + MUnlocked(Unlocked), + MPend(MPend), +} + +#[derive(Debug, Clone)] +pub struct MPend { + cheque_body: ChequeBody, + signature: Signature, +} + +impl Mix { + pub fn new_m_unlocked(cheque_body: ChequeBody, signature: Signature, secret: Secret) -> Self { + Self::MUnlocked(Unlocked { + cheque_body, + signature, + secret, + }) + } + + pub fn new_m_pend(cheque_body: ChequeBody, signature: Signature) -> Self { + Self::MPend(MPend { + cheque_body, + signature, + }) + } +} + +impl PData for Mix { + fn to_plutus_data(self: &Self) -> PlutusData { + match &self { + Mix::MUnlocked(unlocked) => constr( + 0, + vec![ + unlocked.cheque_body.to_plutus_data(), + unlocked.signature.to_plutus_data(), + unlocked.secret.to_plutus_data(), + ], + ), + Mix::MPend(m_pend) => constr( + 1, + vec![ + m_pend.cheque_body.to_plutus_data(), + m_pend.signature.to_plutus_data(), + ], + ), + } + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let (constr_index, v) = &plutus::unconstr(d)?; + match constr_index { + 0 => match &v[..] { + [a, b, c] => Ok(Self::new_m_unlocked( + PData::from_plutus_data(&a)?, + PData::from_plutus_data(&b)?, + PData::from_plutus_data(&c)?, + )), + _ => Err(anyhow!("bad length")), + }, + 1 => match &v[..] { + [a, b] => Ok(Self::new_m_pend( + PData::from_plutus_data(&a)?, + PData::from_plutus_data(&b)?, + )), + _ => Err(anyhow!("bad length")), + }, + _ => Err(anyhow!("Bad constr tag")), + } + } +} + +#[derive(Debug, Clone)] +pub struct Mixs(Vec); + +impl PData for Mixs { + fn to_plutus_data(self: &Self) -> PlutusData { + plutus::list(&self.0.iter().map(|x| x.to_plutus_data()).collect()) + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let v = plutus::unlist(d)?; + let x: Vec = v + .iter() + .map(|x| PData::from_plutus_data(x)) + .collect::>>()?; + Ok(Self(x)) + } +} diff --git a/src/data/pend_cheque.rs b/src/data/pend_cheque.rs new file mode 100644 index 0000000..17c3f33 --- /dev/null +++ b/src/data/pend_cheque.rs @@ -0,0 +1,66 @@ +use anyhow::{anyhow, Result}; + +use pallas_primitives::PlutusData; + +use super::base::{Amount, Hash32, Timestamp}; +use super::plutus::{self, PData}; + +#[derive(Debug, Clone)] +pub struct PendCheque { + amount: Amount, + timeout: Timestamp, + image: Hash32, +} + +impl PendCheque { + pub fn new(amount: Amount, timeout: Timestamp, image: Hash32) -> Self { + Self { + amount, + timeout, + image, + } + } +} + +impl PData for PendCheque { + fn to_plutus_data(self: &Self) -> PlutusData { + let data = plutus::list(&vec![ + self.amount.to_plutus_data(), + self.timeout.to_plutus_data(), + self.image.to_plutus_data(), + ]); + data + } + + fn from_plutus_data(d: &PlutusData) -> Result { + match &plutus::unlist(d)?[..] { + [a, b, c] => { + let r = Self::new( + PData::from_plutus_data(a)?, + PData::from_plutus_data(b)?, + PData::from_plutus_data(c)?, + ); + Ok(r) + } + _ => Err(anyhow!("bad length")), + } + } +} + +#[derive(Debug, Clone)] +pub struct PendCheques(pub Vec); + +impl PData for PendCheques { + fn to_plutus_data(self: &Self) -> PlutusData { + plutus::list(&self.0.iter().map(|x| x.to_plutus_data()).collect()) + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let v = plutus::unlist(d)?; + let x: Vec = v + .iter() + .map(|x| PendCheque::from_plutus_data(x)) + .collect::>>()?; + Ok(PendCheques(x)) + } +} diff --git a/src/data/plutus.rs b/src/data/plutus.rs new file mode 100644 index 0000000..1b4a95f --- /dev/null +++ b/src/data/plutus.rs @@ -0,0 +1,182 @@ +use anyhow::{anyhow, Result}; +use pallas_primitives::PlutusData; + +use crate::utils::{concat, v2a}; + +pub fn bytes(b: &[u8]) -> PlutusData { + PlutusData::BoundedBytes(pallas_primitives::BoundedBytes::from( + Into::>::into(b), + )) +} + +pub fn unbytes(u: &PlutusData) -> Result, anyhow::Error> { + match u { + PlutusData::BoundedBytes(b) => Ok(b.to_vec()), + _ => Err(anyhow!("not int")), + } +} + +pub fn int(i: i128) -> PlutusData { + PlutusData::BigInt(pallas_primitives::BigInt::Int( + pallas_primitives::Int::try_from(i).unwrap(), + )) +} + +pub fn unint(u: &PlutusData) -> Result { + // Pattern match to ensure we have the correct variant. + match u { + PlutusData::BigInt(pallas_primitives::BigInt::Int(x)) => { + // Access the inner `i128` value from the newtype `Int(i128)`. + let y = x.0.try_into()?; + Ok(y) + } + _ => Err(anyhow!("not an integer PlutusData")), + } +} + +pub fn list(v: &Vec) -> PlutusData { + PlutusData::Array(pallas_primitives::MaybeIndefArray::Indef(v.clone())) +} + +pub fn unlist(u: &PlutusData) -> Result> { + match u { + PlutusData::Array(pallas_primitives::MaybeIndefArray::Indef(v)) => Ok(v.clone()), + _ => Err(anyhow!("not list")), + } +} + +pub fn constr(constr_index: u64, v: Vec) -> PlutusData { + let fields = pallas_primitives::MaybeIndefArray::Indef(v.clone()); + constr_arr(constr_index, fields) +} + +pub fn constr_arr( + constr_index: u64, + fields: pallas_primitives::MaybeIndefArray, +) -> PlutusData { + let tag = if constr_index < 8 { + 121 + constr_index + } else { + panic!("I don't know what the number is"); + }; + // FIXME :: What is this? + let any_constructor: Option = None; + PlutusData::Constr(pallas_primitives::Constr { + tag, + any_constructor, + fields, + }) +} + +pub fn unconstr(u: &PlutusData) -> Result<(u64, Vec)> { + match u { + PlutusData::Constr(pallas_primitives::Constr { tag, fields, .. }) => { + let constr_index = if *tag < 128 { + tag - 121 + } else { + panic!("I don't know what the number is"); + }; + + Ok((constr_index, fields.clone().to_vec())) + } + _ => Err(anyhow!("not list")), + } +} + +// Define the `PData` trait. +// It requires any implementing type to be able to convert to and from `PlutusData`. +pub trait PData { + // Converts the current instance into a `PlutusData` representation. + fn to_plutus_data(&self) -> PlutusData; + + // Creates a new instance of the implementing type from a `PlutusData` object. + // It returns a `Result` to handle potential conversion errors. + fn from_plutus_data(data: &PlutusData) -> Result + where + Self: Sized; +} + +impl PData for u64 { + fn to_plutus_data(&self) -> PlutusData { + int(*self as i128) + } + + fn from_plutus_data(d: &PlutusData) -> Result + where + Self: Sized, + { + let n: i128 = unint(d)?; + let m: u64 = u64::try_from(n)?; + Ok(m) + } +} + +impl PData for i128 { + fn to_plutus_data(&self) -> PlutusData { + int(*self) + } + + fn from_plutus_data(d: &PlutusData) -> Result + where + Self: Sized, + { + let n: i128 = unint(d)?; + Ok(n) + } +} + +impl PData for Vec { + fn to_plutus_data(&self) -> PlutusData { + bytes(self) + } + + fn from_plutus_data(data: &PlutusData) -> Result { + unbytes(data) + } +} + +impl PData for Vec +where + T: PData, +{ + fn to_plutus_data(&self) -> PlutusData { + list( + &self + .iter() + .map(|x| x.to_plutus_data()) + .collect::>(), + ) + } + + fn from_plutus_data(data: &PlutusData) -> Result { + unlist(data)? + .iter() + .map(|x| PData::from_plutus_data(x)) + .collect::>() + } +} + +impl PData for [u8; N] { + fn to_plutus_data(&self) -> PlutusData { + self.to_vec().to_plutus_data() + } + + fn from_plutus_data(data: &PlutusData) -> Result { + let v = Vec::::from_plutus_data(data)?; + v2a(v) + } +} + +pub fn to_cbor(x: &T) -> Result> { + let v = minicbor::to_vec(x.to_plutus_data())?; + Ok(v) +} + +pub fn from_cbor(x: &[u8]) -> Result { + let d: PlutusData = minicbor::decode(x)?; + T::from_plutus_data(&d) +} + +pub fn mk_msg(tag: &Vec, body: &T) -> Result> { + Ok(concat(tag, &to_cbor(body)?)) +} diff --git a/src/data/redeemer.rs b/src/data/redeemer.rs new file mode 100644 index 0000000..b65be93 --- /dev/null +++ b/src/data/redeemer.rs @@ -0,0 +1,55 @@ +use anyhow::{anyhow, Result}; +use pallas_primitives::PlutusData; + +use super::plutus::{self, constr, constr_arr, unlist, PData}; +use super::step::Steps; + +#[derive(Debug, Clone)] +pub enum Redeemer { + Batch, + Main(Steps), + Mutual, +} + +impl Redeemer { + pub fn new_batch() -> Self { + Self::Batch + } + + pub fn new_main(steps: Steps) -> Self { + Self::Main(steps) + } + + pub fn new_mutual() -> Self { + Self::Mutual + } +} + +impl PData for Redeemer { + fn to_plutus_data(self: &Self) -> PlutusData { + match &self { + Redeemer::Batch => constr(0, vec![]), + Redeemer::Main(steps) => constr(1, steps.0.iter().map(PData::to_plutus_data).collect()), + Redeemer::Mutual => constr(2, vec![]), + } + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let (constr_index, v) = &plutus::unconstr(d)?; + match constr_index { + 0 => match &v[..] { + [] => Ok(Self::new_batch()), + _ => Err(anyhow!("bad length")), + }, + 1 => match &v[..] { + [a] => Ok(Self::new_main(PData::from_plutus_data(&a)?)), + _ => Err(anyhow!("bad length")), + }, + 2 => match &v[..] { + [] => Ok(Self::new_mutual()), + _ => Err(anyhow!("bad length")), + }, + _ => Err(anyhow!("Bad constr tag")), + } + } +} diff --git a/src/data/squash.rs b/src/data/squash.rs new file mode 100644 index 0000000..c8985bc --- /dev/null +++ b/src/data/squash.rs @@ -0,0 +1,66 @@ +use anyhow::{anyhow, Result}; + +use pallas_primitives::PlutusData; + +use super::base::{Amount, Index}; +use super::plutus::{self, PData}; + +#[derive(Debug, Clone)] +pub struct Exclude(pub Vec); + +impl PData for Exclude { + fn to_plutus_data(self: &Self) -> PlutusData { + plutus::list(&self.0.iter().map(|x| x.to_plutus_data()).collect()) + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let v = plutus::unlist(d)?; + let x: Vec = v + .iter() + .map(|x| PData::from_plutus_data(x)) + .collect::>>()?; + Ok(Exclude(x)) + } +} + +#[derive(Debug, Clone)] +pub struct Squash { + amount: Amount, + index: Index, + exclude: Exclude, +} + +impl Squash { + pub fn new(amount: Amount, index: Index, exclude: Exclude) -> Self { + Self { + amount, + index, + exclude, + } + } +} + +impl PData for Squash { + fn to_plutus_data(self: &Self) -> PlutusData { + let data = plutus::list(&vec![ + self.amount.to_plutus_data(), + self.index.to_plutus_data(), + self.exclude.to_plutus_data(), + ]); + data + } + + fn from_plutus_data(d: &PlutusData) -> Result { + match &plutus::unlist(d)?[..] { + [a, b, c] => { + let r = Self::new( + PData::from_plutus_data(a)?, + PData::from_plutus_data(b)?, + PData::from_plutus_data(c)?, + ); + Ok(r) + } + _ => Err(anyhow!("bad length")), + } + } +} diff --git a/src/data/stage.rs b/src/data/stage.rs new file mode 100644 index 0000000..436fcc3 --- /dev/null +++ b/src/data/stage.rs @@ -0,0 +1,70 @@ +use anyhow::{anyhow, Result}; +use pallas_primitives::PlutusData; + +use super::plutus::{self, constr, PData}; + +use super::{ + base::{Amount, Timestamp}, + pend_cheque::PendCheques, +}; + +#[derive(Debug, Clone)] +pub enum Stage { + Opened(Amount), + Closed(Amount, Timestamp), + Responded(Amount, PendCheques), +} + +impl Stage { + pub fn new_opened(amount: Amount) -> Self { + Self::Opened(amount) + } + + pub fn new_closed(amount: Amount, timeout: Timestamp) -> Self { + Self::Closed(amount, timeout) + } + + pub fn new_responded(amount: Amount, pends: PendCheques) -> Self { + Self::Responded(amount, pends) + } +} + +impl PData for Stage { + fn to_plutus_data(self: &Self) -> PlutusData { + match &self { + Stage::Opened(amount) => constr(0, vec![amount.to_plutus_data()]), + Stage::Closed(amount, timeout) => { + constr(1, vec![amount.to_plutus_data(), timeout.to_plutus_data()]) + } + Stage::Responded(amount, pend_cheques) => constr( + 2, + vec![amount.to_plutus_data(), pend_cheques.to_plutus_data()], + ), + } + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let (constr_index, v) = &plutus::unconstr(d)?; + match constr_index { + 0 => match &v[..] { + [a] => Ok(Self::new_opened(PData::from_plutus_data(&a)?)), + _ => Err(anyhow!("bad length")), + }, + 1 => match &v[..] { + [a, b] => Ok(Self::new_closed( + PData::from_plutus_data(&a)?, + PData::from_plutus_data(&b)?, + )), + _ => Err(anyhow!("bad length")), + }, + 2 => match &v[..] { + [a, b] => Ok(Self::new_responded( + PData::from_plutus_data(&a)?, + PData::from_plutus_data(&b)?, + )), + _ => Err(anyhow!("bad length")), + }, + _ => Err(anyhow!("Bad constr tag")), + } + } +} diff --git a/src/data/step.rs b/src/data/step.rs new file mode 100644 index 0000000..4ecbebb --- /dev/null +++ b/src/data/step.rs @@ -0,0 +1,204 @@ +use anyhow::{anyhow, Result}; +use pallas_primitives::PlutusData; + +use super::{ + mix::Mixs, + plutus::{self, constr, PData}, + squash::Squash, + unlocked::Unlockeds, +}; + +#[derive(Debug, Clone)] +pub struct Unpends(pub Vec>); +impl PData for Unpends { + fn to_plutus_data(&self) -> PlutusData { + PData::to_plutus_data(&self.0) + } + + fn from_plutus_data(data: &PlutusData) -> Result + where + Self: Sized, + { + Ok(Self(PData::from_plutus_data(data)?)) + } +} + +#[derive(Debug, Clone)] +pub enum Step { + Cont(Cont), + Eol(Eol), +} + +impl PData for Step { + fn to_plutus_data(&self) -> PlutusData { + match self { + Self::Cont(x) => constr(0, vec![x.to_plutus_data()]), + Self::Eol(x) => constr(1, vec![x.to_plutus_data()]), + } + } + + fn from_plutus_data(data: &PlutusData) -> Result + where + Self: Sized, + { + let (constr_index, v) = &plutus::unconstr(data)?; + match constr_index { + 0 => match &v[..] { + [x] => Ok(Self::Cont(PData::from_plutus_data(x)?)), + _ => Err(anyhow!("bad length")), + }, + 1 => match &v[..] { + [x] => Ok(Self::Eol(PData::from_plutus_data(x)?)), + _ => Err(anyhow!("bad length")), + }, + _ => Err(anyhow!("Bad constr tag")), + } + } +} + +#[derive(Debug, Clone)] +pub enum Cont { + Add, + Sub(Squash, Unlockeds), + Close, + Respond(Squash, Mixs), + Unlock(Unpends), + Expire(Unpends), +} + +#[derive(Debug, Clone)] +pub enum Eol { + End, + Elapse, +} + +impl PData for Eol { + fn to_plutus_data(&self) -> PlutusData { + match self { + Self::End => constr(0, vec![]), + Self::Elapse => constr(1, vec![]), + } + } + + fn from_plutus_data(data: &PlutusData) -> Result + where + Self: Sized, + { + let (constr_index, v) = &plutus::unconstr(data)?; + match constr_index { + 0 => match &v[..] { + [] => Ok(Self::End), + _ => Err(anyhow!("bad length")), + }, + 1 => match &v[..] { + [] => Ok(Self::Elapse), + _ => Err(anyhow!("bad length")), + }, + _ => Err(anyhow!("Bad constr tag")), + } + } +} + +impl Cont { + pub fn new_add() -> Self { + Self::Add + } + + pub fn new_sub(squash: Squash, unlockeds: Unlockeds) -> Self { + Self::Sub(squash, unlockeds) + } + + pub fn new_close() -> Self { + Self::Close + } + + pub fn new_respond(squash: Squash, mixs: Mixs) -> Self { + Self::Respond(squash, mixs) + } + + pub fn new_unlock(unpends: Unpends) -> Self { + Self::Unlock(unpends) + } + + pub fn new_expire(unpends: Unpends) -> Self { + Self::Expire(unpends) + } +} + +impl PData for Cont { + fn to_plutus_data(self: &Self) -> PlutusData { + match &self { + Self::Add => constr(0, vec![]), + Self::Sub(squash, unlockeds) => { + constr(1, vec![squash.to_plutus_data(), unlockeds.to_plutus_data()]) + } + Self::Close => constr(2, vec![]), + Self::Respond(squash, mixs) => { + constr(3, vec![squash.to_plutus_data(), mixs.to_plutus_data()]) + } + Self::Unlock(unpends) => { + constr(4, unpends.0.iter().map(PData::to_plutus_data).collect()) + } + Self::Expire(unpends) => { + constr(4, unpends.0.iter().map(PData::to_plutus_data).collect()) + } + } + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let (constr_index, v) = &plutus::unconstr(d)?; + match constr_index { + 0 => match &v[..] { + [] => Ok(Self::new_add()), + _ => Err(anyhow!("bad length")), + }, + 1 => match &v[..] { + [a, b] => Ok(Self::new_sub( + PData::from_plutus_data(&a)?, + PData::from_plutus_data(&b)?, + )), + _ => Err(anyhow!("bad length")), + }, + 2 => match &v[..] { + [] => Ok(Self::new_close()), + _ => Err(anyhow!("bad length")), + }, + 3 => match &v[..] { + [a, b] => Ok(Self::new_respond( + PData::from_plutus_data(&a)?, + PData::from_plutus_data(&b)?, + )), + _ => Err(anyhow!("bad length")), + }, + 4 => Ok(Self::new_unlock(Unpends( + v.iter() + .map(PData::from_plutus_data) + .collect::>>>()?, + ))), + 5 => Ok(Self::new_expire(Unpends( + v.iter() + .map(PData::from_plutus_data) + .collect::>>>()?, + ))), + _ => Err(anyhow!("Bad constr tag")), + } + } +} + +#[derive(Debug, Clone)] +pub struct Steps(pub Vec); + +impl PData for Steps { + fn to_plutus_data(self: &Self) -> PlutusData { + PData::to_plutus_data(&self.0) + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let v = plutus::unlist(d)?; + let x: Vec = v + .iter() + .map(|x| PData::from_plutus_data(x)) + .collect::>>()?; + Ok(Self(x)) + } +} diff --git a/src/data/unlocked.rs b/src/data/unlocked.rs new file mode 100644 index 0000000..cc1d9ac --- /dev/null +++ b/src/data/unlocked.rs @@ -0,0 +1,66 @@ +use anyhow::{anyhow, Result}; +use pallas_primitives::PlutusData; + +use super::base::{Secret, Signature}; +use super::cheque_body::ChequeBody; +use super::plutus::{self, PData}; + +#[derive(Debug, Clone)] +pub struct Unlocked { + pub cheque_body: ChequeBody, + pub signature: Signature, + pub secret: Secret, +} + +impl Unlocked { + pub fn new(cheque_body: ChequeBody, signature: Signature, secret: Secret) -> Self { + Self { + cheque_body, + signature, + secret, + } + } +} + +impl PData for Unlocked { + fn to_plutus_data(self: &Self) -> PlutusData { + let data = plutus::list(&vec![ + self.cheque_body.to_plutus_data(), + self.signature.to_plutus_data(), + self.secret.to_plutus_data(), + ]); + data + } + + fn from_plutus_data(d: &PlutusData) -> Result { + match &plutus::unlist(d)?[..] { + [a, b, c] => { + let r = Self::new( + PData::from_plutus_data(a)?, + PData::from_plutus_data(b)?, + PData::from_plutus_data(c)?, + ); + Ok(r) + } + _ => Err(anyhow!("bad length")), + } + } +} + +#[derive(Debug, Clone)] +pub struct Unlockeds(pub Vec); + +impl PData for Unlockeds { + fn to_plutus_data(self: &Self) -> PlutusData { + plutus::list(&self.0.iter().map(|x| x.to_plutus_data()).collect()) + } + + fn from_plutus_data(d: &PlutusData) -> Result { + let v = plutus::unlist(d)?; + let x: Vec = v + .iter() + .map(|x| PData::from_plutus_data(x)) + .collect::>>()?; + Ok(Self(x)) + } +}