Skip to content

Commit

Permalink
fungible operation history
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Jan 7, 2024
1 parent 65c8a51 commit 30ccb1a
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 15 deletions.
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 36 additions & 8 deletions cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ use psbt::{Psbt, PsbtVer};
use rgb_rt::{DescriptorRgb, RgbKeychain, RuntimeError, TransferParams};
use rgbstd::containers::{Bindle, BuilderSeal, Transfer, UniversalBindle};
use rgbstd::contract::{ContractId, GenesisSeal, GraphSeal, StateType};
use rgbstd::interface::{ContractBuilder, FilterExclude, IfaceId, SchemaIfaces};
use rgbstd::interface::{AmountChange, ContractBuilder, FilterExclude, IfaceId, SchemaIfaces};
use rgbstd::invoice::{Beneficiary, RgbInvoice, RgbInvoiceBuilder, XChainNet};
use rgbstd::persistence::{Inventory, Stash};
use rgbstd::schema::SchemaId;
use rgbstd::validation::Validity;
use rgbstd::{OutputSeal, XChain};
use rgbstd::{OutputSeal, XChain, XOutputSeal};
use seals::txout::CloseMethod;
use strict_types::encoding::{FieldName, TypeName};
use strict_types::StrictVal;
Expand Down Expand Up @@ -128,11 +128,15 @@ pub enum Command {
iface: String,
},

/// Print operation history
#[display("history")]
History {
/// Print operation history for a default fungible token under a given
/// interface
#[display("history-fungible")]
HistoryFungible {
/// Contract identifier
contract_id: Option<ContractId>,
contract_id: ContractId,

/// Interface to interpret the state data
iface: String,
},

/// Display all known UTXOs belonging to this wallet
Expand Down Expand Up @@ -335,8 +339,32 @@ impl Exec for RgbArgs {
None
}

Command::History { contract_id: _ } => {
todo!();
Command::HistoryFungible { contract_id, iface } => {
let runtime = self.rgb_runtime(&config)?;
let iface: TypeName = tn!(iface.clone());
let history = runtime.fungible_history(*contract_id, iface)?;
println!("Amount\tCounterparty\tWitness Id");
for (id, op) in history {
let (cparty, more) = match op.state_change {
AmountChange::Dec(_) => {
(op.beneficiaries.first(), op.beneficiaries.len().saturating_sub(1))
}
AmountChange::Zero => continue,
AmountChange::Inc(_) => {
(op.payers.first(), op.payers.len().saturating_sub(1))
}
};
let more = if more > 0 {
format!(" (+{more})")
} else {
s!("")
};
let cparty = cparty
.map(XOutputSeal::to_string)
.unwrap_or_else(|| s!("none"));
println!("{}\t{}{}\t{}", op.state_change, cparty, more, id);
}
None
}

Command::Import { armored, file } => {
Expand Down
67 changes: 63 additions & 4 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#![allow(clippy::result_large_err)]

use std::collections::HashMap;
use std::convert::Infallible;
use std::io;
use std::io::ErrorKind;
Expand All @@ -32,12 +33,16 @@ use bpstd::{Network, XpubDerivable};
use bpwallet::Wallet;
use rgbfs::StockFs;
use rgbstd::containers::{Contract, LoadError, Transfer};
use rgbstd::interface::{BuilderError, OutpointFilter};
use rgbstd::persistence::{Inventory, InventoryDataError, InventoryError, StashError, Stock};
use rgbstd::interface::{
AmountChange, BuilderError, ContractError, IfaceOp, OutpointFilter, WitnessFilter,
};
use rgbstd::persistence::{
Inventory, InventoryDataError, InventoryError, Stash, StashError, Stock,
};
use rgbstd::resolvers::ResolveHeight;
use rgbstd::validation::{self, ResolveWitness};
use rgbstd::{ContractId, XChain, XOutpoint};
use strict_types::encoding::{DecodeError, DeserializeError, Ident, SerializeError};
use rgbstd::{AssignmentWitness, ContractId, WitnessId, XChain, XOutpoint};
use strict_types::encoding::{DecodeError, DeserializeError, Ident, SerializeError, TypeName};

use crate::{DescriptorRgb, RgbDescr};

Expand Down Expand Up @@ -67,6 +72,12 @@ pub enum RuntimeError {
#[from]
Builder(BuilderError),

#[from]
History(HistoryError),

#[from]
Contract(ContractError),

#[from]
PsbtDecode(psbt::DecodeError),

Expand Down Expand Up @@ -111,6 +122,7 @@ impl From<Infallible> for RuntimeError {
pub struct Runtime<D: DescriptorRgb<K> = RgbDescr, K = XpubDerivable> {
stock_path: PathBuf,
#[getter(as_mut)]
// TODO: Parametrize by the stock
stock: Stock,
bprt: bpwallet::Runtime<D, K /* TODO: Add layer 2 */>,
}
Expand All @@ -134,6 +146,16 @@ impl<D: DescriptorRgb<K>, K> OutpointFilter for Runtime<D, K> {
}
}

impl<D: DescriptorRgb<K>, K> WitnessFilter for Runtime<D, K> {
fn include_witness(&self, witness: impl Into<AssignmentWitness>) -> bool {
let witness = witness.into();
self.wallet()
.transactions()
.keys()
.any(|txid| AssignmentWitness::Present(WitnessId::Bitcoin(*txid)) == witness)
}
}

pub struct ContractOutpointsFilter<'runtime, D: DescriptorRgb<K>, K> {
pub contract_id: ContractId,
pub filter: &'runtime Runtime<D, K>,
Expand Down Expand Up @@ -234,4 +256,41 @@ impl<D: DescriptorRgb<K>, K> Runtime<D, K> {
.accept_transfer(transfer, resolver, force)
.map_err(RuntimeError::from)
}

// TODO: Integrate into BP Wallet `TxRow` as L2 and provide transactional info
pub fn fungible_history(
&self,
contract_id: ContractId,
iface_name: impl Into<TypeName>,
) -> Result<HashMap<WitnessId, IfaceOp<AmountChange>>, RuntimeError> {
let iface_name = iface_name.into();
let iface = self.stock.iface_by_name(&iface_name)?;
let default_op = iface
.default_operation
.as_ref()
.ok_or(HistoryError::NoDefaultOp)?;
let state_name = iface
.transitions
.get(default_op)
.ok_or(HistoryError::DefaultOpNotTransition)?
.default_assignment
.as_ref()
.ok_or(HistoryError::NoDefaultAssignment)?
.clone();
let contract = self.stock.contract_iface_named(contract_id, iface_name)?;
contract
.fungible_ops::<AmountChange>(state_name, self, self)
.map_err(RuntimeError::from)
}
}

#[derive(Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum HistoryError {
/// interface doesn't define default operation
NoDefaultOp,
/// default operation defined by the interface is not a state transition
DefaultOpNotTransition,
/// interface doesn't define default fungible state
NoDefaultAssignment,
}

0 comments on commit 30ccb1a

Please sign in to comment.