feat: Provide access to all assets at a tx out (#180)

This commit is contained in:
Lucas 2022-09-16 16:53:45 -04:00 committed by GitHub
parent be91bfbb5a
commit bfc5a0a312
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 100 additions and 4 deletions

View file

@ -1,6 +1,6 @@
use minicbor::{data::Tag, Decode, Encode};
use serde::{Deserialize, Serialize};
use std::ops::Deref;
use std::{fmt, ops::Deref};
/// Utility for skipping parts of the CBOR payload, use only for debugging
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
@ -778,6 +778,14 @@ impl From<Bytes> for String {
}
}
impl fmt::Display for Bytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let bytes: Vec<u8> = self.clone().into();
f.write_str(&hex::encode(bytes))
}
}
#[derive(
Serialize, Deserialize, Clone, Copy, Encode, Decode, Debug, PartialEq, Eq, PartialOrd, Ord,
)]

View file

@ -7,7 +7,11 @@ use thiserror::Error;
use pallas_codec::utils::KeepRaw;
use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, babbage, byron};
use pallas_primitives::{
alonzo,
babbage::{self, AssetName, PolicyId},
byron,
};
pub mod block;
pub mod cert;
@ -132,6 +136,27 @@ pub enum MultiEraSigners<'b> {
#[derive(Debug, Clone)]
pub struct OutputRef(Hash<32>, u64);
#[derive(Debug, Clone)]
pub struct Asset {
pub subject: Subject,
pub quantity: u64,
}
#[derive(Debug, Clone)]
pub enum Subject {
Lovelace,
NativeAsset(PolicyId, AssetName),
}
impl ToString for Subject {
fn to_string(&self) -> String {
match self {
Self::Lovelace => String::from("lovelace"),
Self::NativeAsset(p, n) => format!("{p}.{n}"),
}
}
}
#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid CBOR structure: {0}")]

View file

@ -4,11 +4,11 @@ use pallas_addresses::{Address, ByronAddress, Error as AddressError};
use pallas_codec::minicbor;
use pallas_primitives::{
alonzo,
babbage::{self, DatumOption, ScriptRef},
babbage::{self, Coin, DatumOption, ScriptRef},
byron,
};
use crate::{Era, MultiEraOutput};
use crate::{Asset, Era, MultiEraOutput, Subject};
impl<'b> MultiEraOutput<'b> {
pub fn from_byron(output: &'b byron::TxOut) -> Self {
@ -77,6 +77,50 @@ impl<'b> MultiEraOutput<'b> {
}
}
pub fn assets(&self) -> Vec<Asset> {
let mut assets = Vec::new();
match self {
MultiEraOutput::Byron(x) => {
push_lovelace(&mut assets, x.amount);
}
MultiEraOutput::Babbage(x) => match x.deref().deref() {
babbage::TransactionOutput::Legacy(x) => match &x.amount {
babbage::Value::Coin(c) => {
push_lovelace(&mut assets, *c);
}
babbage::Value::Multiasset(c, multi_asset) => {
push_lovelace(&mut assets, *c);
push_native_asset(&mut assets, multi_asset);
}
},
babbage::TransactionOutput::PostAlonzo(x) => match &x.value {
babbage::Value::Coin(c) => {
push_lovelace(&mut assets, *c);
}
babbage::Value::Multiasset(c, multi_asset) => {
push_lovelace(&mut assets, *c);
push_native_asset(&mut assets, multi_asset);
}
},
},
MultiEraOutput::AlonzoCompatible(x) => match &x.amount {
alonzo::Value::Coin(c) => {
push_lovelace(&mut assets, *c);
}
alonzo::Value::Multiasset(c, multi_asset) => {
push_lovelace(&mut assets, *c);
push_native_asset(&mut assets, multi_asset);
}
},
};
assets
}
pub fn as_babbage(&self) -> Option<&babbage::TransactionOutput> {
match self {
MultiEraOutput::AlonzoCompatible(_) => None,
@ -131,6 +175,24 @@ impl<'b> MultiEraOutput<'b> {
}
}
fn push_lovelace(assets: &mut Vec<Asset>, quantity: u64) {
assets.push(Asset {
subject: Subject::Lovelace,
quantity,
})
}
fn push_native_asset(assets: &mut Vec<Asset>, multi_asset: &alonzo::Multiasset<Coin>) {
for (policy_id, names) in multi_asset.iter() {
for (asset_name, quantity) in names.iter() {
assets.push(Asset {
subject: Subject::NativeAsset(*policy_id, asset_name.clone()),
quantity: *quantity,
});
}
}
}
#[cfg(test)]
mod tests {
use crate::MultiEraBlock;
@ -143,6 +205,7 @@ mod tests {
for tx in block.txs() {
for output in tx.outputs() {
assert_ne!(output.assets()[0].quantity, 0);
assert_ne!(output.ada_amount(), 0);
assert!(matches!(output.address(), Ok(_)));
}