diff --git a/src/cardano/blockfrost.rs b/src/cardano/blockfrost.rs index 828d0fb..ece0236 100644 --- a/src/cardano/blockfrost.rs +++ b/src/cardano/blockfrost.rs @@ -7,7 +7,7 @@ use anyhow::{anyhow, Result}; use minicbor::decode; -use crate::{tx::plutus::BuildParams, utils::v2a}; +use crate::{cardano_types::{address::Address, DatumOrHash, Output, Utxo}, tx::plutus::BuildParams, utils::v2a}; use blockfrost::{BlockfrostAPI, Pagination}; use blockfrost_openapi::models::{ asset_history_inner::Action, tx_content_output_amount_inner::TxContentOutputAmountInner, @@ -15,15 +15,12 @@ use blockfrost_openapi::models::{ use pallas_addresses::{Network, ShelleyAddress, ShelleyDelegationPart, ShelleyPaymentPart}; use pallas_codec::{ minicbor as cbor, - utils::{CborWrap, NonEmptyKeyValuePairs}, -}; -use pallas_primitives::{ - conway::{ - AssetName, DatumOption, PolicyId, PostAlonzoTransactionOutput, PseudoDatumOption, - ScriptRef, TransactionInput, TransactionOutput, Tx, Value, - }, - PlutusScript, + utils::NonEmptyKeyValuePairs, }; +use pallas_primitives::conway::{ + AssetName, PolicyId, PostAlonzoTransactionOutput, + TransactionInput, TransactionOutput, Tx, Value, + }; use std::collections::{BTreeMap, HashMap}; use uplc::{tx::ResolvedInput, PlutusData}; @@ -147,20 +144,16 @@ impl Blockfrost { plutus_data_from_inline(&data) } - pub async fn resolve_datum_option( + pub async fn resolve_datum( &self, datum_hash: &Option, inline_datum: &Option, - ) -> Result> { + ) -> Result> { if let Some(inline_datum) = inline_datum { - Ok(Some(PseudoDatumOption::Data(CborWrap( - plutus_data_from_inline(inline_datum)?, - )))) + Ok(Some(DatumOrHash::Data(plutus_data_from_inline(inline_datum)?))) } else { if let Some(datum_hash) = datum_hash { - Ok(Some(PseudoDatumOption::Data(CborWrap( - self.plutus_data_from_hash(&datum_hash).await?, - )))) + Ok(Some(DatumOrHash::Data(self.plutus_data_from_hash(&datum_hash).await?,))) } else { Ok(None) } @@ -273,7 +266,7 @@ impl Cardano for Blockfrost { (&pp).into() } - async fn resolve_many(&self, inputs: Vec) -> Vec { + async fn resolve_many(&self, inputs: Vec) -> Vec { let mut resolved = vec![]; for i in inputs { if let Ok(r) = self.resolve(i).await { @@ -283,7 +276,7 @@ impl Cardano for Blockfrost { resolved } - async fn resolve(&self, input: TransactionInput) -> Result { + async fn resolve(&self, input: TransactionInput) -> Result { let utxo = self .api .transactions_utxos(hex::encode(input.transaction_id).as_str()) @@ -299,23 +292,23 @@ impl Cardano for Blockfrost { output.output_index, input.index as i32, "somehow resolved the wrong ouput", ); - let datum_option = self - .resolve_datum_option(&output.data_hash, &output.inline_datum) + let datum = self + .resolve_datum(&output.data_hash, &output.inline_datum) .await - .expect("Something went wrong"); + ?; // let script_ref = self.resolve_script(&output.reference_script_hash).await.expect("Something went wrong"); // FIXME!!!! let script_ref = None; - Ok(ResolvedInput { + Ok(Utxo { input: input.clone(), - output: TransactionOutput::PostAlonzo(PostAlonzoTransactionOutput { - address: from_bech32(&output.address).into(), + output: Output { + address: Address::from_bech32(&output.address)?, value: from_tx_content_output_amounts(&output.amount[..]), - datum_option, + datum, script_ref, - }), + }, }) } else { Err(anyhow!("No output found")) diff --git a/src/cardano/cardano.rs b/src/cardano/cardano.rs index cb44be2..f026c43 100644 --- a/src/cardano/cardano.rs +++ b/src/cardano/cardano.rs @@ -2,6 +2,7 @@ use anyhow::Result; use pallas_addresses::{Network, ShelleyPaymentPart}; use pallas_primitives::conway::Tx; use uplc::{tx::ResolvedInput, TransactionInput}; +use crate::cardano_types::{Utxo}; use crate::tx::plutus::BuildParams; @@ -11,11 +12,11 @@ pub trait Cardano { fn resolve_many( &self, inputs: Vec, - ) -> impl std::future::Future> + Send; + ) -> impl std::future::Future> + Send; fn resolve( &self, input: TransactionInput, - ) -> impl std::future::Future> + Send; + ) -> impl std::future::Future> + Send; fn transaction_by_hash( &self, tx_hash: &str, diff --git a/src/cardano_types.rs b/src/cardano_types.rs new file mode 100644 index 0000000..aa66da7 --- /dev/null +++ b/src/cardano_types.rs @@ -0,0 +1,113 @@ +use pallas_addresses; +use pallas_codec::utils::CborWrap; +use pallas_crypto::hash::Hash; +use pallas_primitives::{ + conway::{DatumOption, NativeScript, PostAlonzoTransactionOutput, PseudoScript, PseudoTransactionOutput, Value}, + PlutusScript, +}; +use uplc::PlutusData; + +pub mod address; +use address::Address; + +/// This is a sad file: yet another set of wrapping. +/// +/// The pallas types are too confusing. +/// This is surely a consequence of supporting all eras. +/// At least in part. +/// Another part may also be that this support has simply grown, +/// rather than be rationalised. + + +/// +/// Script. +/// There is no support for native scripts, +/// and we only really care about V3. +pub enum Script { + V1(Vec), + V2(Vec), + V3(Vec), +} + +impl Into> for Script { + fn into(self) -> PseudoScript { + match self { + Script::V1(items) => PseudoScript::PlutusV1Script(PlutusScript(items.into())), + Script::V2(items) => PseudoScript::PlutusV2Script(PlutusScript(items.into())), + Script::V3(items) => PseudoScript::PlutusV3Script(PlutusScript(items.into())), + } + } +} + +impl Into>> for Script { + fn into(self) -> CborWrap> { + CborWrap(self.into()) + } +} + +/// Datum +/// We are not being too clever with this. +/// We make use of rust's `Optional` for the no datum case. +/// We are yet to distinguish cases where we need the data, +/// in place of the hash. +/// It should be documented. +pub enum DatumOrHash { + Hash(Hash<32>),// Check this + Data(PlutusData), +} + +impl Into for DatumOrHash { + fn into(self) -> DatumOption { + match self { + DatumOrHash::Hash(hash) => DatumOption::Hash(hash), + DatumOrHash::Data(plutus_data) => DatumOption::Data(CborWrap(plutus_data)), + } + } +} + +/// Output +pub struct Output { + pub address: Address, + pub value: Value, + pub datum: Option, + pub script_ref: Option