From 83b42ec1df8b65f034e1265f93bd06b43b7f95ef Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 26 Oct 2023 01:39:09 -0300 Subject: [PATCH 1/3] feat: interface improviments --- std/src/interface/contract.rs | 49 ++++++++++++++++++++++++++++++++--- std/src/interface/rgb21.rs | 3 +++ std/src/stl/specs.rs | 12 +++++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/std/src/interface/contract.rs b/std/src/interface/contract.rs index 50d01091..d26d3e17 100644 --- a/std/src/interface/contract.rs +++ b/std/src/interface/contract.rs @@ -21,16 +21,17 @@ use std::collections::{BTreeSet, HashSet}; -use amplify::confinement::{LargeOrdMap, LargeVec, SmallVec}; +use amplify::confinement::{LargeOrdMap, LargeVec, SmallVec, U16}; use bp::Outpoint; use rgb::{ - AssignmentType, AttachId, ContractId, ContractState, FungibleOutput, MediaType, RevealedAttach, - RevealedData, SealWitness, + AssignmentType, AttachId, ContractId, ContractState, DataOutput, FungibleOutput, MediaType, + RevealedAttach, RevealedData, SealWitness, }; -use strict_encoding::FieldName; +use strict_encoding::{FieldName, StrictDeserialize}; use strict_types::typify::TypedVal; use strict_types::{decode, StrictVal}; +use crate::interface::rgb21::Allocation; use crate::interface::IfaceImpl; #[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -94,6 +95,28 @@ impl From<&FungibleOutput> for FungibleAllocation { } } +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct DataAllocation { + pub owner: Outpoint, + pub witness: SealWitness, + pub value: Allocation, +} + +impl From for DataAllocation { + fn from(out: DataOutput) -> Self { Self::from(&out) } +} + +impl From<&DataOutput> for DataAllocation { + fn from(out: &DataOutput) -> Self { + DataAllocation { + owner: out.seal, + witness: out.witness, + value: Allocation::from_strict_serialized::(out.state.as_ref().to_owned()) + .expect("invalid allocation data"), + } + } +} + pub trait OutpointFilter { fn include_outpoint(&self, outpoint: Outpoint) -> bool; } @@ -182,6 +205,24 @@ impl ContractIface { Ok(LargeVec::try_from_iter(state).expect("same or smaller collection size")) } + pub fn data( + &self, + name: impl Into, + ) -> Result, ContractError> { + let name = name.into(); + let type_id = self + .iface + .assignments_type(&name) + .ok_or(ContractError::FieldNameUnknown(name))?; + let state = self + .state + .data() + .iter() + .filter(|outp| outp.opout.ty == type_id) + .map(DataAllocation::from); + Ok(LargeVec::try_from_iter(state).expect("same or smaller collection size")) + } + // TODO: Add rights, attachments and structured data APIs pub fn outpoint( &self, diff --git a/std/src/interface/rgb21.rs b/std/src/interface/rgb21.rs index 9fba8a69..7a0c2f71 100644 --- a/std/src/interface/rgb21.rs +++ b/std/src/interface/rgb21.rs @@ -101,6 +101,9 @@ impl Allocation { pub fn with(index: TokenIndex, fraction: OwnedFraction) -> Allocation { Allocation(index, fraction) } + + pub fn token_id(self) -> TokenIndex { self.0 } + pub fn fraction(self) -> OwnedFraction { self.1 } } impl StrictSerialize for Allocation {} diff --git a/std/src/stl/specs.rs b/std/src/stl/specs.rs index c5095d68..493e47f3 100644 --- a/std/src/stl/specs.rs +++ b/std/src/stl/specs.rs @@ -477,8 +477,9 @@ impl DivisibleAssetSpec { pub fn details(&self) -> Option<&str> { self.naming.details.as_ref().map(|d| d.as_str()) } } -#[derive(Clone, Eq, PartialEq, Debug, Default)] -#[derive(StrictType, StrictEncode, StrictDecode)] +#[derive(Wrapper, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, From, Debug)] +#[wrapper(Deref, Display)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_CONTRACT)] #[cfg_attr( feature = "serde", @@ -498,6 +499,13 @@ impl FromStr for RicardianContract { } } +impl RicardianContract { + pub fn from_strict_val_unchecked(value: &StrictVal) -> Self { + let s = value.unwrap_string(); + RicardianContract::from_str(&s).expect("invalid term data") + } +} + #[derive(Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug, From)] #[wrapper(Deref, Display, FromStr, MathOps)] #[wrapper_mut(DerefMut, MathAssign)] From 8c82a0b6e2cbc74f2808b7de5ebcc6e8ecbd9c1a Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 26 Oct 2023 01:39:42 -0300 Subject: [PATCH 2/3] feat: import rgb21 and rgb25 ifaces --- std/src/persistence/hoard.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/std/src/persistence/hoard.rs b/std/src/persistence/hoard.rs index 6e10a5ee..73ecf1da 100644 --- a/std/src/persistence/hoard.rs +++ b/std/src/persistence/hoard.rs @@ -35,7 +35,9 @@ use strict_encoding::TypeName; use crate::accessors::{MergeReveal, MergeRevealError}; use crate::containers::{Cert, Consignment, ContentId, ContentSigs}; -use crate::interface::{rgb20, ContractSuppl, Iface, IfaceId, IfacePair, SchemaIfaces}; +use crate::interface::{ + rgb20, rgb21, rgb25, ContractSuppl, Iface, IfaceId, IfacePair, SchemaIfaces, +}; use crate::persistence::{InventoryError, Stash, StashError, StashInconsistency}; use crate::LIB_NAME_RGB_STD; @@ -78,10 +80,16 @@ impl Hoard { pub fn preset() -> Self { let rgb20 = rgb20(); let rgb20_id = rgb20.iface_id(); + let rgb21 = rgb21(); + let rgb21_id = rgb21.iface_id(); + let rgb25 = rgb25(); + let rgb25_id = rgb25.iface_id(); Hoard { schemata: none!(), ifaces: tiny_bmap! { rgb20_id => rgb20, + rgb21_id => rgb21, + rgb25_id => rgb25, }, geneses: none!(), suppl: none!(), From a94dd7a3ad79347eb27ebe676c6def3ae516159f Mon Sep 17 00:00:00 2001 From: Armando Dutra Date: Thu, 26 Oct 2023 02:15:25 -0300 Subject: [PATCH 3/3] fix: generate blank transition to others iimpls --- std/src/persistence/inventory.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/std/src/persistence/inventory.rs b/std/src/persistence/inventory.rs index 0786e595..a9ff727e 100644 --- a/std/src/persistence/inventory.rs +++ b/std/src/persistence/inventory.rs @@ -410,13 +410,29 @@ pub trait Inventory: Deref { let schema_ifaces = self.contract_schema(contract_id)?; let iface = self.iface_by_name(&iface.into())?; let schema = &schema_ifaces.schema; - let iimpl = schema_ifaces - .iimpls - .get(&iface.iface_id()) - .ok_or(DataError::NoIfaceImpl(schema.schema_id(), iface.iface_id()))?; - let builder = + + if schema_ifaces.iimpls.is_empty() { + return Err(InventoryError::DataError(DataError::NoIfaceImpl( + schema.schema_id(), + iface.iface_id(), + ))); + } + + let builder = if let Some(iimpl) = schema_ifaces.iimpls.get(&iface.iface_id()) { TransitionBuilder::blank_transition(iface.clone(), schema.clone(), iimpl.clone()) - .expect("internal inconsistency"); + .expect("internal inconsistency") + } else { + let (default_iface_id, default_iimpl) = schema_ifaces.iimpls.first_key_value().unwrap(); + let default_iface = self.iface_by_id(*default_iface_id)?; + + TransitionBuilder::blank_transition( + default_iface.clone(), + schema.clone(), + default_iimpl.clone(), + ) + .expect("internal inconsistency") + }; + Ok(builder) }