From 65c8a51569e431c29d349a3a1d4c7b8ab87669bf Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 7 Jan 2024 12:31:33 +0100 Subject: [PATCH 1/2] chore: update dependencies --- Cargo.lock | 9 +++------ Cargo.toml | 5 +++++ cli/src/command.rs | 4 ++-- src/pay.rs | 14 ++++++++------ src/runtime.rs | 6 +++--- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9418872..3974e63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1529,8 +1529,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0581f9bc33b509400aa9225d2308dfd45af413a4fe38f7c4b823a7e09e6036" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#b1232f5f77ff253bbe79bdcee04a2cf0d4ef0c05" dependencies = [ "aluvm", "amplify", @@ -1550,8 +1549,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4898f1ca45d70ed18f3f1977ef35ffe8ee35870c982ad9fb842a6fbaeb512490" +source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#b71d58fd087506746347c68d676b8079e3b751d3" dependencies = [ "amplify", "baid58", @@ -1620,8 +1618,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bc24f24f2e942d1c20f46a68b331d7864fbdf94ab334c6fac20840816d30a54" +source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#b71d58fd087506746347c68d676b8079e3b751d3" dependencies = [ "amplify", "baid58", diff --git a/Cargo.toml b/Cargo.toml index 305119b..e61af5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,3 +91,8 @@ serde = ["serde_crate", "serde_with", "serde_yaml", "bp-std/serde", "bp-wallet/s [package.metadata.docs.rs] features = [ "all" ] + +[patch.crates-io] +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "v0.11" } +rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "v0.11" } +rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "v0.11" } diff --git a/cli/src/command.rs b/cli/src/command.rs index 6a84f9e..0064941 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -439,7 +439,7 @@ impl Exec for RgbArgs { for allocation in allocations { println!( " amount={}, utxo={}, witness={} # owned by the wallet", - allocation.value, allocation.owner, allocation.witness + allocation.state, allocation.seal, allocation.witness ); } } @@ -450,7 +450,7 @@ impl Exec for RgbArgs { for allocation in allocations { println!( " amount={}, utxo={}, witness={} # owner unknown", - allocation.value, allocation.owner, allocation.witness + allocation.state, allocation.seal, allocation.witness ); } } diff --git a/src/pay.rs b/src/pay.rs index ee61fbd..a753507 100644 --- a/src/pay.rs +++ b/src/pay.rs @@ -30,7 +30,7 @@ use bpwallet::{Beneficiary as BpBeneficiary, ConstructionError, PsbtMeta, TxPara use psbt::{CommitError, EmbedError, Psbt, RgbPsbt, TapretKeyError}; use rgbstd::containers::{Bindle, Transfer}; use rgbstd::interface::ContractError; -use rgbstd::invoice::{Beneficiary, InvoiceState, RgbInvoice}; +use rgbstd::invoice::{Amount, Beneficiary, InvoiceState, RgbInvoice}; use rgbstd::persistence::{ ComposeError, ConsignerError, Inventory, InventoryError, Stash, StashError, }; @@ -206,9 +206,11 @@ impl Runtime { contract_id, filter: self, }; - let mut state = contract.fungible(assignment_name, &filter)?.into_inner(); - state.sort_by_key(|a| a.value); - let mut sum = 0u64; + let mut state = contract + .fungible(assignment_name, &filter)? + .collect::>(); + state.sort_by_key(|a| a.state); + let mut sum = Amount::ZERO; state .iter() .rev() @@ -216,11 +218,11 @@ impl Runtime { if sum >= amount { false } else { - sum += a.value; + sum += a.state; true } }) - .map(|a| a.owner) + .map(|a| a.seal) .collect::>() } _ => return Err(CompositionError::Unsupported), diff --git a/src/runtime.rs b/src/runtime.rs index 29377ea..56b7e6c 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -126,7 +126,7 @@ impl, K> DerefMut for Runtime { } impl, K> OutpointFilter for Runtime { - fn include_output(&self, output: impl Into) -> bool { + fn include_outpoint(&self, output: impl Into) -> bool { let output = output.into(); self.wallet() .coins() @@ -140,9 +140,9 @@ pub struct ContractOutpointsFilter<'runtime, D: DescriptorRgb, K> { } impl<'runtime, D: DescriptorRgb, K> OutpointFilter for ContractOutpointsFilter<'runtime, D, K> { - fn include_output(&self, output: impl Into) -> bool { + fn include_outpoint(&self, output: impl Into) -> bool { let output = output.into(); - if !self.filter.include_output(output) { + if !self.filter.include_outpoint(output) { return false; } matches!(self.filter.stock.state_for_outpoints(self.contract_id, [output]), Ok(list) if !list.is_empty()) From 30ccb1a55dc71b800fb03c461fdfac3ec49c4ea4 Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Sun, 7 Jan 2024 14:09:15 +0100 Subject: [PATCH 2/2] fungible operation history --- Cargo.lock | 6 ++--- cli/src/command.rs | 44 ++++++++++++++++++++++++------ src/runtime.rs | 67 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3974e63..75d115b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1529,7 +1529,7 @@ dependencies = [ [[package]] name = "rgb-core" version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#b1232f5f77ff253bbe79bdcee04a2cf0d4ef0c05" +source = "git+https://github.com/RGB-WG/rgb-core?branch=v0.11#2b59903039770df4766c9681bc74691382308ef5" dependencies = [ "aluvm", "amplify", @@ -1549,7 +1549,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#b71d58fd087506746347c68d676b8079e3b751d3" +source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#9db17e1a6b08d3817ffeebdfb85a4b405818fec4" dependencies = [ "amplify", "baid58", @@ -1618,7 +1618,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.4" -source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#b71d58fd087506746347c68d676b8079e3b751d3" +source = "git+https://github.com/RGB-WG/rgb-std?branch=v0.11#9db17e1a6b08d3817ffeebdfb85a4b405818fec4" dependencies = [ "amplify", "baid58", diff --git a/cli/src/command.rs b/cli/src/command.rs index 0064941..9ee4179 100644 --- a/cli/src/command.rs +++ b/cli/src/command.rs @@ -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; @@ -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, + contract_id: ContractId, + + /// Interface to interpret the state data + iface: String, }, /// Display all known UTXOs belonging to this wallet @@ -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 } => { diff --git a/src/runtime.rs b/src/runtime.rs index 56b7e6c..11c1451 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -21,6 +21,7 @@ #![allow(clippy::result_large_err)] +use std::collections::HashMap; use std::convert::Infallible; use std::io; use std::io::ErrorKind; @@ -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}; @@ -67,6 +72,12 @@ pub enum RuntimeError { #[from] Builder(BuilderError), + #[from] + History(HistoryError), + + #[from] + Contract(ContractError), + #[from] PsbtDecode(psbt::DecodeError), @@ -111,6 +122,7 @@ impl From for RuntimeError { pub struct Runtime = RgbDescr, K = XpubDerivable> { stock_path: PathBuf, #[getter(as_mut)] + // TODO: Parametrize by the stock stock: Stock, bprt: bpwallet::Runtime, } @@ -134,6 +146,16 @@ impl, K> OutpointFilter for Runtime { } } +impl, K> WitnessFilter for Runtime { + fn include_witness(&self, witness: impl Into) -> bool { + let witness = witness.into(); + self.wallet() + .transactions() + .keys() + .any(|txid| AssignmentWitness::Present(WitnessId::Bitcoin(*txid)) == witness) + } +} + pub struct ContractOutpointsFilter<'runtime, D: DescriptorRgb, K> { pub contract_id: ContractId, pub filter: &'runtime Runtime, @@ -234,4 +256,41 @@ impl, K> Runtime { .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, + ) -> Result>, 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::(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, }