diff --git a/Cargo.lock b/Cargo.lock index 0ee82c2..e9fed91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -688,7 +688,7 @@ dependencies = [ [[package]] name = "rgb-invoice" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-std?branch=mining#21f9b206697b08f8473092618d9801c197ed576a" +source = "git+https://github.com/RGB-WG/rgb-std?branch=iface-generics#2d8405cccb9f4c494108f50f0ddacbf9ce2fd579" dependencies = [ "amplify", "baid64", @@ -708,7 +708,7 @@ dependencies = [ [[package]] name = "rgb-std" version = "0.11.0-beta.6" -source = "git+https://github.com/RGB-WG/rgb-std?branch=mining#21f9b206697b08f8473092618d9801c197ed576a" +source = "git+https://github.com/RGB-WG/rgb-std?branch=iface-generics#2d8405cccb9f4c494108f50f0ddacbf9ce2fd579" dependencies = [ "aluvm", "amplify", diff --git a/Cargo.toml b/Cargo.toml index 027c4c3..7307f20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,5 +41,5 @@ fs = ["rgb-std/fs"] bp-consensus = { git = "https://github.com/BP-WG/bp-core", branch = "master" } bp-invoice = { git = "https://github.com/BP-WG/bp-std", branch = "master" } rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "mining" } -rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "mining" } -rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "mining" } +rgb-invoice = { git = "https://github.com/RGB-WG/rgb-std", branch = "iface-generics" } +rgb-std = { git = "https://github.com/RGB-WG/rgb-std", branch = "iface-generics" } diff --git a/src/dumb.rs b/src/dumb.rs deleted file mode 100644 index 258e25b..0000000 --- a/src/dumb.rs +++ /dev/null @@ -1,105 +0,0 @@ -// RGB interfaces by LNP/BP Standards Association -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2023-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2023 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::borrow::Borrow; -use std::iter; - -use amplify::num::u24; -use rgbstd::persistence::ContractStateRead; -use rgbstd::vm::{ - ContractState, GlobalContractState, GlobalOrd, GlobalStateIter, UnknownGlobalStateType, -}; -use rgbstd::{ - AssignmentType, AttachState, ContractId, DataState, FungibleState, GlobalStateType, - OutputAssignment, RevealedAttach, RevealedData, RevealedValue, SchemaId, VoidState, XOutpoint, -}; - -// TODO: Get rid of Dumb type -pub struct Dumb; -impl GlobalStateIter for Dumb { - type Data = DataState; - fn size(&mut self) -> u24 { unreachable!() } - fn prev(&mut self) -> Option<(GlobalOrd, Self::Data)> { unreachable!() } - fn last(&mut self) -> Option<(GlobalOrd, Self::Data)> { unreachable!() } - fn reset(&mut self, _: u24) { unreachable!() } -} -impl ContractState for Dumb { - fn global( - &self, - _: GlobalStateType, - ) -> Result, UnknownGlobalStateType> { - unreachable!(); - #[allow(unreachable_code)] - Ok(GlobalContractState::new(Dumb)) - } - fn rights(&self, _: XOutpoint, _: AssignmentType) -> u32 { unreachable!() } - fn fungible( - &self, - _: XOutpoint, - _: AssignmentType, - ) -> impl DoubleEndedIterator { - unreachable!(); - #[allow(unreachable_code)] - iter::empty() - } - fn data( - &self, - _: XOutpoint, - _: AssignmentType, - ) -> impl DoubleEndedIterator> { - unreachable!(); - #[allow(unreachable_code)] - iter::empty::() - } - fn attach( - &self, - _: XOutpoint, - _: AssignmentType, - ) -> impl DoubleEndedIterator> { - unreachable!(); - #[allow(unreachable_code)] - iter::empty::() - } -} -impl ContractStateRead for Dumb { - fn contract_id(&self) -> ContractId { unreachable!() } - fn schema_id(&self) -> SchemaId { unreachable!() } - fn rights_all(&self) -> impl Iterator> { - unreachable!(); - #[allow(unreachable_code)] - iter::empty() - } - fn fungible_all(&self) -> impl Iterator> { - unreachable!(); - #[allow(unreachable_code)] - iter::empty() - } - fn data_all(&self) -> impl Iterator> { - unreachable!(); - #[allow(unreachable_code)] - iter::empty() - } - fn attach_all(&self) -> impl Iterator> { - unreachable!(); - #[allow(unreachable_code)] - iter::empty() - } -} diff --git a/src/lib.rs b/src/lib.rs index 183e1ee..3362565 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,12 +32,10 @@ mod traits; pub mod rgb20; pub mod rgb21; pub mod rgb25; -mod dumb; -pub use dumb::Dumb; -pub use rgb20::Rgb20; -pub use rgb21::Rgb21; -pub use rgb25::Rgb25; +pub use rgb20::{Rgb20, Rgb20Info, Rgb20Wrapper}; +pub use rgb21::{Rgb21, Rgb21Wrapper}; +pub use rgb25::{Rgb25, Rgb25Info, Rgb25Wrapper}; pub use traits::{IssuerWrapper, SchemaIssuer}; pub const LNPBP_IDENTITY: &str = "ssi:LZS1ux-gjD9nXPF-OcetUUkW-6r3uSCS6-aQhs9W5f-8JE7w"; diff --git a/src/main.rs b/src/main.rs index c38c9b1..d7c9cbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use std::path::PathBuf; use std::str::FromStr; use std::{fs, io}; -use ifaces::{rgb20, rgb21, rgb25, Dumb, Rgb20, Rgb21, Rgb25, LNPBP_IDENTITY}; +use ifaces::{rgb20, rgb21, rgb25, Rgb20, Rgb21, LNPBP_IDENTITY}; use rgbstd::containers::{ FileContent, Kit, Supplement, SUPPL_ANNOT_IFACE_CLASS, SUPPL_ANNOT_IFACE_FEATURES, }; @@ -37,7 +37,7 @@ use strict_types::{StlFormat, SystemBuilder}; fn main() -> io::Result<()> { let ifsys = SystemBuilder::new() - .import(Rgb21::::stl()) + .import(Rgb21::ALL.stl()) .unwrap() .import(rgb_contract_stl()) .unwrap() @@ -75,8 +75,8 @@ fn main() -> io::Result<()> { kit.save_armored("interfaces/RGBStd.rgba")?; let mut kit = Kit::default(); - for features in rgb20::Features::ENUMERATE { - let iface = Rgb20::::iface(*features); + for features in rgb20::Rgb20::ENUMERATE { + let iface = features.iface(); let types = typesys.extract(iface.types()).unwrap(); let mut suppl = Supplement::new(iface.iface_id(), LNPBP_IDENTITY); suppl @@ -93,8 +93,8 @@ fn main() -> io::Result<()> { kit.save_armored("interfaces/RGB20.rgba")?; let mut kit = Kit::default(); - for features in rgb21::Features::ENUMERATE { - let iface = Rgb21::::iface(*features); + for features in rgb21::Rgb21::ENUMERATE { + let iface = features.iface(); let types = typesys.extract(iface.types()).unwrap(); let mut suppl = Supplement::new(iface.iface_id(), LNPBP_IDENTITY); suppl @@ -111,8 +111,8 @@ fn main() -> io::Result<()> { kit.save_armored("interfaces/RGB21.rgba")?; let mut kit = Kit::default(); - for features in rgb25::Features::ENUMERATE { - let iface = Rgb25::::iface(*features); + for features in rgb25::Rgb25::ENUMERATE { + let iface = features.iface(); let types = typesys.extract(iface.types()).unwrap(); let mut suppl = Supplement::new(iface.iface_id(), LNPBP_IDENTITY); suppl @@ -129,7 +129,7 @@ fn main() -> io::Result<()> { kit.save_armored("interfaces/RGB25.rgba")?; let dir = PathBuf::from_str("interfaces").unwrap(); - let stl = Rgb21::::stl(); + let stl = Rgb21::ALL.stl(); stl.serialize(StlFormat::Binary, Some(&dir), "0.11.0", None) .expect("unable to write to the file"); stl.serialize(StlFormat::Armored, Some(&dir), "0.11.0", None) @@ -165,12 +165,7 @@ fn main() -> io::Result<()> { } let mut ifaces = vec![rgb20::iface::rgb20_base(), rgb20::iface::rgb20_renamable()]; - ifaces.extend( - rgb20::Features::ENUMERATE - .iter() - .copied() - .map(Rgb20::::iface), - ); + ifaces.extend(rgb20::Rgb20::ENUMERATE.iter().map(Rgb20::iface)); map.extend( ifaces diff --git a/src/rgb20/info.rs b/src/rgb20/info.rs index bb95cd2..3cfef49 100644 --- a/src/rgb20/info.rs +++ b/src/rgb20/info.rs @@ -26,7 +26,7 @@ use rgbstd::info::ContractInfo; use rgbstd::stl::Attachment; use rgbstd::{Amount, Precision, XOutpoint, XWitnessId}; -use crate::rgb20::Features; +use crate::rgb20::Rgb20; #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr( @@ -44,7 +44,7 @@ pub struct Rgb20Info { pub terms: String, pub attach: Option, pub precision: Precision, - pub features: Features, + pub features: Rgb20, pub issued: Amount, // TODO: Replace with SupplyInfo pub burned: Amount, // TODO: Replace with SupplyInfo diff --git a/src/rgb20/issuer.rs b/src/rgb20/issuer.rs index 0ec2de5..e916321 100644 --- a/src/rgb20/issuer.rs +++ b/src/rgb20/issuer.rs @@ -25,7 +25,6 @@ use bp::dbc::Method; use rgbstd::containers::ValidContract; use rgbstd::interface::{BuilderError, ContractBuilder, IfaceClass, TxOutpoint}; use rgbstd::invoice::{Amount, Precision}; -use rgbstd::persistence::ContractStateRead; use rgbstd::stl::{AssetSpec, Attachment, ContractTerms, RicardianContract}; use rgbstd::{AltLayer1, AssetTag, BlindingFactor, GenesisSeal, Identity}; use strict_encoding::InvalidRString; @@ -62,8 +61,8 @@ pub struct PrimaryIssue { } impl PrimaryIssue { - pub fn testnet_with( - issuer: SchemaIssuer>, + pub fn testnet_with( + issuer: SchemaIssuer, by: &str, ticker: &str, name: &str, @@ -73,7 +72,7 @@ impl PrimaryIssue { Self::testnet_int(issuer, by, ticker, name, details, precision, false) } - pub fn testnet>, S: ContractStateRead>( + pub fn testnet>( by: &str, ticker: &str, name: &str, @@ -83,7 +82,7 @@ impl PrimaryIssue { Self::testnet_int(C::issuer(), by, ticker, name, details, precision, false) } - pub fn testnet_det>, S: ContractStateRead>( + pub fn testnet_det>( by: &str, ticker: &str, name: &str, @@ -99,8 +98,8 @@ impl PrimaryIssue { Ok(me) } - fn testnet_int( - issuer: SchemaIssuer>, + fn testnet_int( + issuer: SchemaIssuer, by: &str, ticker: &str, name: &str, @@ -118,7 +117,7 @@ impl PrimaryIssue { let mut builder = match deterministic { false => ContractBuilder::with( Identity::from_str(by).expect("invalid issuer identity string"), - Rgb20::::iface(features), + features.iface(), schema, main_iface_impl, types, @@ -126,7 +125,7 @@ impl PrimaryIssue { ), true => ContractBuilder::deterministic( Identity::from_str(by).expect("invalid issuer identity string"), - Rgb20::::iface(features), + features.iface(), schema, main_iface_impl, types, diff --git a/src/rgb20/mod.rs b/src/rgb20/mod.rs index 7f0c390..98725ea 100644 --- a/src/rgb20/mod.rs +++ b/src/rgb20/mod.rs @@ -25,10 +25,16 @@ mod issuer; mod info; use amplify::confinement::Confined; -pub use info::{Rgb20Info, SupplyEvent, SupplyInfo}; -pub use issuer::{IssuerError, PrimaryIssue}; use rgbstd::info::FeatureList; -pub use wrapper::{Rgb20, RGB20_FIXED_IFACE_ID, RGB20_IFACE_ID}; +use rgbstd::interface::{Iface, IfaceClass, IfaceId}; +use rgbstd::persistence::ContractStateRead; +use rgbstd::stl::rgb_contract_stl; +use strict_types::TypeLib; + +use self::iface::{burnable, fixed, inflatable, replaceable, rgb20_base, rgb20_renamable}; +pub use self::info::{Rgb20Info, SupplyEvent, SupplyInfo}; +pub use self::issuer::{IssuerError, PrimaryIssue}; +pub use self::wrapper::{Rgb20Wrapper, RGB20_FIXED_IFACE_ID, RGB20_IFACE_ID}; pub const LIB_NAME_RGB20: &str = "RGB20"; @@ -66,59 +72,59 @@ impl Inflation { derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase") )] -pub struct Features { +pub struct Rgb20 { pub renaming: bool, // pub reserves: bool, pub inflation: Inflation, } -impl Features { - pub const FIXED: Self = Features { +impl Rgb20 { + pub const FIXED: Self = Rgb20 { renaming: false, // reserves: false, inflation: Inflation::Fixed, }; - pub const RENAMABLE: Self = Features { + pub const RENAMABLE: Self = Rgb20 { renaming: true, // reserves: false, inflation: Inflation::Fixed, }; - pub const INFLATABLE: Self = Features { + pub const INFLATABLE: Self = Rgb20 { renaming: false, // reserves: false, inflation: Inflation::Inflatable, }; - pub const BURNABLE: Self = Features { + pub const BURNABLE: Self = Rgb20 { renaming: false, // reserves: false, inflation: Inflation::Burnable, }; - pub const INFLATABLE_BURNABLE: Self = Features { + pub const INFLATABLE_BURNABLE: Self = Rgb20 { renaming: false, // reserves: false, inflation: Inflation::InflatableBurnable, }; - pub const REPLACEABLE: Self = Features { + pub const REPLACEABLE: Self = Rgb20 { renaming: false, // reserves: false, inflation: Inflation::Replaceable, }; - pub const INFLATABLE_RENAMABLE: Self = Features { + pub const INFLATABLE_RENAMABLE: Self = Rgb20 { renaming: true, // reserves: false, inflation: Inflation::Inflatable, }; - pub const BURNABLE_RENAMABLE: Self = Features { + pub const BURNABLE_RENAMABLE: Self = Rgb20 { renaming: true, // reserves: false, inflation: Inflation::Burnable, }; - pub const INFLATABLE_BURNABLE_RENAMABLE: Self = Features { + pub const INFLATABLE_BURNABLE_RENAMABLE: Self = Rgb20 { renaming: true, // reserves: false, inflation: Inflation::InflatableBurnable, }; - pub const ALL: Self = Features { + pub const ALL: Self = Rgb20 { renaming: true, // reserves: true, inflation: Inflation::Replaceable, @@ -154,12 +160,55 @@ impl Features { } } +impl IfaceClass for Rgb20 { + const IFACE_NAME: &'static str = LIB_NAME_RGB20; + const IFACE_IDS: &'static [IfaceId] = &[ + RGB20_FIXED_IFACE_ID, + RGB20_IFACE_ID, // TODO: Add other iface ids + ]; + type Wrapper = Rgb20Wrapper; + + fn iface(&self) -> Iface { + let (mut name, mut iface) = if self.renaming { + (tn!("RGB20Renamable"), rgb20_renamable()) + } else { + (tn!("RGB20"), rgb20_base()) + }; + if self.inflation.is_fixed() { + iface = iface.expect_extended(fixed(), tn!(format!("{name}Fixed"))); + } else if self.inflation.is_inflatable() { + iface = iface.expect_extended(inflatable(), tn!(format!("{name}Inflatable"))); + name = tn!(format!("{name}Inflatable")); + } + if self.inflation.is_burnable() { + iface = iface.expect_extended(burnable(), tn!(format!("{name}Burnable"))); + if self.inflation.is_replaceable() { + name = tn!(format!("{}Replaceable", name.to_string().replace("Inflatable", ""))); + iface = iface.expect_extended(replaceable(), name); + } + } + /* TODO: Complete reservable interface + if features.reserves { + iface = iface.expect_extended(reservable(), "RGB20Reservable"); + } + */ + iface + } + + fn iface_id(&self) -> IfaceId { + // TODO: Optimize with constants + self.iface().iface_id() + } + + fn stl(&self) -> TypeLib { rgb_contract_stl() } +} + mod _display { use std::fmt::{self, Display, Formatter}; use super::*; - impl Display for Features { + impl Display for Rgb20 { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { if self.renaming { f.write_str("renamable, ")?; @@ -175,27 +224,26 @@ mod test { use rgbstd::interface::IfaceClass; use super::*; - use crate::Dumb; #[test] fn iface_id_all() { - let iface_id = Rgb20::::iface(Features::FIXED).iface_id(); + let iface_id = Rgb20::FIXED.iface_id(); eprintln!("{:#04x?}", iface_id.to_byte_array()); - assert_eq!(Rgb20::::IFACE_IDS[0], iface_id); - let iface_id = Rgb20::::iface(Features::ALL).iface_id(); + assert_eq!(Rgb20::IFACE_IDS[0], iface_id); + let iface_id = Rgb20::ALL.iface_id(); eprintln!("{:#04x?}", iface_id.to_byte_array()); - assert_eq!(Rgb20::::IFACE_IDS[1], iface_id); + assert_eq!(Rgb20::IFACE_IDS[1], iface_id); } #[test] fn iface_check() { - if let Err(err) = Rgb20::::iface(Features::FIXED).check() { + if let Err(err) = Rgb20::FIXED.iface().check() { for e in err { eprintln!("{e}"); } panic!("invalid RGB20Fixed interface definition"); } - if let Err(err) = Rgb20::::iface(Features::ALL).check() { + if let Err(err) = Rgb20::ALL.iface().check() { for e in err { eprintln!("{e}"); } diff --git a/src/rgb20/wrapper.rs b/src/rgb20/wrapper.rs index d782b0c..f6820e5 100644 --- a/src/rgb20/wrapper.rs +++ b/src/rgb20/wrapper.rs @@ -22,18 +22,16 @@ use std::collections::HashMap; use rgbstd::interface::{ - AmountChange, ContractIface, FungibleAllocation, Iface, IfaceClass, IfaceId, IfaceOp, + AmountChange, ContractIface, FungibleAllocation, IfaceClass, IfaceId, IfaceOp, IfaceWrapper, OutpointFilter, RightsAllocation, }; use rgbstd::invoice::{Amount, Precision}; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::{rgb_contract_stl, AssetSpec, ContractTerms, Details}; +use rgbstd::stl::{AssetSpec, ContractTerms, Details}; use rgbstd::{AssetTag, XWitnessId}; use strict_encoding::InvalidRString; -use strict_types::TypeLib; -use super::iface::*; -use super::{Features, Inflation, PrimaryIssue, Rgb20Info}; +use super::{Inflation, PrimaryIssue, Rgb20, Rgb20Info}; use crate::IssuerWrapper; pub const RGB20_FIXED_IFACE_ID: IfaceId = IfaceId::from_array([ @@ -46,49 +44,18 @@ pub const RGB20_IFACE_ID: IfaceId = IfaceId::from_array([ ]); #[derive(Clone, Eq, PartialEq, Debug, From)] -pub struct Rgb20(ContractIface); +pub struct Rgb20Wrapper(ContractIface); -impl IfaceClass for Rgb20 { - const IFACE_NAME: &'static str = "RGB20"; - const IFACE_IDS: &'static [IfaceId] = &[RGB20_FIXED_IFACE_ID, RGB20_IFACE_ID]; - - type Features = Features; +impl IfaceWrapper for Rgb20Wrapper { type Info = Rgb20Info; - fn iface(features: Features) -> Iface { - let (mut name, mut iface) = if features.renaming { - (tn!("RGB20Renamable"), rgb20_renamable()) - } else { - (tn!("RGB20"), rgb20_base()) - }; - if features.inflation.is_fixed() { - iface = iface.expect_extended(fixed(), tn!(format!("{name}Fixed"))); - } else if features.inflation.is_inflatable() { - iface = iface.expect_extended(inflatable(), tn!(format!("{name}Inflatable"))); - name = tn!(format!("{name}Inflatable")); - } - if features.inflation.is_burnable() { - iface = iface.expect_extended(burnable(), tn!(format!("{name}Burnable"))); - if features.inflation.is_replaceable() { - name = tn!(format!("{}Replaceable", name.to_string().replace("Inflatable", ""))); - iface = iface.expect_extended(replaceable(), name); - } + fn with(iface: ContractIface) -> Self { + if !Rgb20::IFACE_IDS.contains(&iface.iface.iface_id) { + panic!("the provided interface is not RGB21 interface"); } - /* TODO: Complete reservable interface - if features.reserves { - iface = iface.expect_extended(reservable(), "RGB20Reservable"); - } - */ - iface - } - - fn iface_id(features: Self::Features) -> IfaceId { - // TODO: Optimize with constants - Rgb20::::iface(features).iface_id() + Self(iface) } - fn stl() -> TypeLib { rgb_contract_stl() } - fn info(&self) -> Self::Info { let spec = self.spec(); let terms = self.contract_terms(); @@ -108,18 +75,18 @@ impl IfaceClass for Rgb20 { } } -impl Rgb20 { - pub fn testnet>( +impl Rgb20Wrapper { + pub fn testnet>( issuer: &str, ticker: &str, name: &str, details: Option<&str>, precision: Precision, ) -> Result { - PrimaryIssue::testnet::(issuer, ticker, name, details, precision) + PrimaryIssue::testnet::(issuer, ticker, name, details, precision) } - pub fn testnet_det>( + pub fn testnet_det>( issuer: &str, ticker: &str, name: &str, @@ -127,10 +94,10 @@ impl Rgb20 { precision: Precision, asset_tag: AssetTag, ) -> Result { - PrimaryIssue::testnet_det::(issuer, ticker, name, details, precision, asset_tag) + PrimaryIssue::testnet_det::(issuer, ticker, name, details, precision, asset_tag) } - pub fn features(&self) -> Features { + pub fn features(&self) -> Rgb20 { let renaming = self .0 .iface @@ -168,7 +135,7 @@ impl Rgb20 { (false, true, true) => panic!("replaceable but non-inflatible asset"), }; - Features { + Rgb20 { renaming, inflation, } diff --git a/src/rgb21/iface.rs b/src/rgb21/iface.rs index c036f2d..7327e31 100644 --- a/src/rgb21/iface.rs +++ b/src/rgb21/iface.rs @@ -26,11 +26,11 @@ use rgbstd::interface::{ use rgbstd::stl::StandardTypes; use rgbstd::{Identity, Occurrences}; -use crate::rgb21::wrapper::Rgb21; -use crate::{Dumb, LNPBP_IDENTITY}; +use super::Rgb21; +use crate::LNPBP_IDENTITY; pub fn nft() -> Iface { - let types = StandardTypes::with(Rgb21::::stl()); + let types = StandardTypes::with(Rgb21::ALL.stl()); Iface { version: VerNo::V1, name: tn!("NonFungibleToken"), @@ -107,7 +107,7 @@ pub fn nft() -> Iface { } pub fn unique() -> Iface { - let types = StandardTypes::with(Rgb21::::stl()); + let types = StandardTypes::with(Rgb21::ALL.stl()); Iface { version: VerNo::V1, name: tn!("UniqueNft"), @@ -144,7 +144,7 @@ pub fn unique() -> Iface { } pub fn limited() -> Iface { - let types = StandardTypes::with(Rgb21::::stl()); + let types = StandardTypes::with(Rgb21::ALL.stl()); Iface { version: VerNo::V1, name: tn!("LimitedNft"), @@ -181,7 +181,7 @@ pub fn limited() -> Iface { } pub fn engravable() -> Iface { - let types = StandardTypes::with(Rgb21::::stl()); + let types = StandardTypes::with(Rgb21::ALL.stl()); Iface { version: VerNo::V1, name: tn!("EngravableNft"), @@ -237,7 +237,7 @@ pub fn engravable() -> Iface { } pub fn issuable() -> Iface { - let types = StandardTypes::with(Rgb21::::stl()); + let types = StandardTypes::with(Rgb21::ALL.stl()); Iface { version: VerNo::V1, name: tn!("IssuableNft"), diff --git a/src/rgb21/mod.rs b/src/rgb21/mod.rs index b13879e..264de45 100644 --- a/src/rgb21/mod.rs +++ b/src/rgb21/mod.rs @@ -25,11 +25,18 @@ mod wrapper; use amplify::confinement::Confined; use rgbstd::info::FeatureList; -pub use types::{ +use rgbstd::interface::{Iface, IfaceClass, IfaceId}; +use rgbstd::persistence::ContractStateRead; +use strict_types::TypeLib; + +use self::iface::{engravable, issuable, limited, nft, unique}; +pub use self::types::{ AttachmentName, AttachmentType, EmbeddedMedia, EngravingData, ItemsCount, TokenData, LIB_ID_RGB21, LIB_NAME_RGB21, }; -pub use wrapper::{Rgb21, RGB21_UNIQUE_IFACE_ID}; +pub use self::wrapper::{Rgb21Wrapper, RGB21_IFACE_ID, RGB21_UNIQUE_IFACE_ID}; +use crate::rgb20::iface::{named_asset, renameable}; +use crate::rgb21::wrapper::rgb21_stl; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] pub enum Issues { @@ -40,21 +47,21 @@ pub enum Issues { } #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] -pub struct Features { +pub struct Rgb21 { pub renaming: bool, // pub reserves: bool, pub engraving: bool, pub issues: Issues, } -impl Features { - pub const NONE: Self = Features { +impl Rgb21 { + pub const NONE: Self = Rgb21 { renaming: false, // reserves: false, engraving: false, issues: Issues::Unique, }; - pub const ALL: Self = Features { + pub const ALL: Self = Rgb21 { renaming: true, // reserves: true, engraving: true, @@ -80,33 +87,66 @@ impl Features { } } +impl IfaceClass for Rgb21 { + const IFACE_NAME: &'static str = LIB_NAME_RGB21; + const IFACE_IDS: &'static [IfaceId] = &[RGB21_UNIQUE_IFACE_ID, RGB21_IFACE_ID]; + type Wrapper = Rgb21Wrapper; + + fn iface(&self) -> Iface { + let mut iface = named_asset().expect_extended(nft(), "RGB21Base"); + if self.renaming { + iface = iface.expect_extended(renameable(), "RGB21Renameable"); + } + if self.engraving { + iface = iface.expect_extended(engravable(), "RGB21Engravable"); + } + iface = match self.issues { + Issues::Unique => iface.expect_extended(unique(), "RGB21Unique"), + Issues::Limited => iface.expect_extended(limited(), "RGB21Limited"), + Issues::MultiIssue => iface.expect_extended(issuable(), "RGB21Issuable"), + }; + /* + if self.reserves { + iface = iface.expect_extended(reservable(), "RGB21Reservable"); + } + */ + iface + } + + fn iface_id(&self) -> IfaceId { + // TODO: Optimize with constants + self.iface().iface_id() + } + + fn stl(&self) -> TypeLib { rgb21_stl() } +} + #[cfg(test)] mod test { use amplify::ByteArray; use rgbstd::interface::IfaceClass; use super::*; - use crate::Dumb; #[test] fn iface_id() { - let iface_id = Rgb21::::iface(Features::NONE).iface_id(); + let iface_id = Rgb21::NONE.iface_id(); eprintln!("{:#04x?}", iface_id.to_byte_array()); - assert_eq!(Rgb21::::IFACE_IDS[0], iface_id); - let iface_id = Rgb21::::iface(Features::ALL).iface_id(); + assert_eq!(Rgb21::IFACE_IDS[0], iface_id); + let iface_id = Rgb21::ALL.iface_id(); eprintln!("{:#04x?}", iface_id.to_byte_array()); - assert_eq!(Rgb21::::IFACE_IDS[1], iface_id); + assert_eq!(Rgb21::IFACE_IDS[1], iface_id); } #[test] fn iface_check() { - if let Err(err) = Rgb21::::iface(Features::NONE).check() { + if let Err(err) = Rgb21::NONE.iface().check() { for e in err { eprintln!("{e}"); } panic!("invalid RGB21Unique interface definition"); } - if let Err(err) = Rgb21::::iface(Features::ALL).check() { + if let Err(err) = Rgb21::ALL.iface().check() { for e in err { eprintln!("{e}"); } diff --git a/src/rgb21/wrapper.rs b/src/rgb21/wrapper.rs index 4b34792..cf38864 100644 --- a/src/rgb21/wrapper.rs +++ b/src/rgb21/wrapper.rs @@ -20,7 +20,7 @@ // limitations under the License. use rgbstd::interface::{ - ContractIface, DataAllocation, Iface, IfaceClass, IfaceId, OutpointFilter, + ContractIface, DataAllocation, IfaceClass, IfaceId, IfaceWrapper, OutpointFilter, }; use rgbstd::persistence::ContractStateRead; use rgbstd::stl::{bp_tx_stl, rgb_contract_stl, AssetSpec, ContractTerms}; @@ -28,11 +28,7 @@ use rgbstd::Allocation; use strict_types::stl::std_stl; use strict_types::{CompileError, LibBuilder, TypeLib}; -use super::iface::*; -use super::{ - AttachmentType, EngravingData, Features, Issues, ItemsCount, TokenData, LIB_NAME_RGB21, -}; -use crate::rgb20::iface::{named_asset, renameable}; +use super::{AttachmentType, EngravingData, ItemsCount, Rgb21, TokenData, LIB_NAME_RGB21}; use crate::rgb20::Rgb20Info; pub const RGB21_UNIQUE_IFACE_ID: IfaceId = IfaceId::from_array([ @@ -60,59 +56,25 @@ fn _rgb21_stl() -> Result { } /// Generates strict type library providing data types for RGB21 interface. -fn rgb21_stl() -> TypeLib { _rgb21_stl().expect("invalid strict type RGB21 library") } +pub fn rgb21_stl() -> TypeLib { _rgb21_stl().expect("invalid strict type RGB21 library") } #[derive(Clone, Eq, PartialEq, Debug)] -pub struct Rgb21(ContractIface); - -impl From> for Rgb21 { - fn from(iface: ContractIface) -> Self { - if !Rgb21::::IFACE_IDS.contains(&iface.iface.iface_id) { - panic!("the provided interface is not RGB21 interface"); - } - Self(iface) - } -} - -impl IfaceClass for Rgb21 { - const IFACE_NAME: &'static str = LIB_NAME_RGB21; - const IFACE_IDS: &'static [IfaceId] = &[RGB21_UNIQUE_IFACE_ID, RGB21_IFACE_ID]; +pub struct Rgb21Wrapper(ContractIface); - type Features = Features; +impl IfaceWrapper for Rgb21Wrapper { type Info = Rgb20Info; - fn iface(features: Self::Features) -> Iface { - let mut iface = named_asset().expect_extended(nft(), "RGB21Base"); - if features.renaming { - iface = iface.expect_extended(renameable(), "RGB21Renameable"); - } - if features.engraving { - iface = iface.expect_extended(engravable(), "RGB21Engravable"); - } - iface = match features.issues { - Issues::Unique => iface.expect_extended(unique(), "RGB21Unique"), - Issues::Limited => iface.expect_extended(limited(), "RGB21Limited"), - Issues::MultiIssue => iface.expect_extended(issuable(), "RGB21Issuable"), - }; - /* - if features.reserves { - iface = iface.expect_extended(reservable(), "RGB21Reservable"); + fn with(iface: ContractIface) -> Self { + if !Rgb21::IFACE_IDS.contains(&iface.iface.iface_id) { + panic!("the provided interface is not RGB21 interface"); } - */ - iface - } - - fn iface_id(features: Self::Features) -> IfaceId { - // TODO: Optimize with constants - Rgb21::::iface(features).iface_id() + Self(iface) } - fn stl() -> TypeLib { rgb21_stl() } - fn info(&self) -> Self::Info { todo!() } } -impl Rgb21 { +impl Rgb21Wrapper { pub fn spec(&self) -> AssetSpec { let strict_val = &self .0 diff --git a/src/rgb25/info.rs b/src/rgb25/info.rs index 6bd17b4..b196704 100644 --- a/src/rgb25/info.rs +++ b/src/rgb25/info.rs @@ -25,7 +25,7 @@ use rgbstd::info::ContractInfo; use rgbstd::stl::Attachment; use rgbstd::Precision; -use crate::rgb25::Features; +use crate::rgb25::Rgb25; #[derive(Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr( @@ -43,7 +43,7 @@ pub struct Rgb25Info { pub terms: String, pub attach: Option, pub precision: Precision, - pub features: Features, + pub features: Rgb25, } impl Display for Rgb25Info { diff --git a/src/rgb25/issuer.rs b/src/rgb25/issuer.rs index 74bfe38..46a5010 100644 --- a/src/rgb25/issuer.rs +++ b/src/rgb25/issuer.rs @@ -25,7 +25,7 @@ use bp::dbc::Method; use rgbstd::containers::ValidContract; use rgbstd::interface::{BuilderError, ContractBuilder, IfaceClass, TxOutpoint}; use rgbstd::invoice::{Amount, Precision}; -use rgbstd::persistence::{ContractStateRead, PersistedState}; +use rgbstd::persistence::PersistedState; use rgbstd::stl::{Attachment, ContractTerms, Details, Name, RicardianContract}; use rgbstd::{AltLayer1, AssetTag, BlindingFactor, GenesisSeal, Identity}; use strict_encoding::InvalidRString; @@ -43,8 +43,8 @@ pub struct Issue { } impl Issue { - fn testnet_int( - issuer: SchemaIssuer>, + fn testnet_int( + issuer: SchemaIssuer, by: &str, name: &str, precision: Precision, @@ -57,7 +57,7 @@ impl Issue { let (schema, main_iface_impl, types, scripts, features) = issuer.into_split(); let builder = ContractBuilder::with( Identity::from_str(by).expect("invalid issuer identity string"), - Rgb25::::iface(features), + features.iface(), schema, main_iface_impl, types, @@ -76,7 +76,7 @@ impl Issue { }) } - pub fn testnet>, S: ContractStateRead>( + pub fn testnet>( by: &str, name: &str, precision: Precision, @@ -84,8 +84,8 @@ impl Issue { Self::testnet_int(C::issuer(), by, name, precision) } - pub fn testnet_with( - issuer: SchemaIssuer>, + pub fn testnet_with( + issuer: SchemaIssuer, by: &str, name: &str, precision: Precision, @@ -93,7 +93,7 @@ impl Issue { Self::testnet_int(issuer, by, name, precision) } - pub fn testnet_det>, S: ContractStateRead>( + pub fn testnet_det>( by: &str, name: &str, precision: Precision, diff --git a/src/rgb25/mod.rs b/src/rgb25/mod.rs index ba1d4ae..0c445fa 100644 --- a/src/rgb25/mod.rs +++ b/src/rgb25/mod.rs @@ -28,7 +28,15 @@ use amplify::confinement::Confined; pub use info::Rgb25Info; pub use issuer::Issue; use rgbstd::info::FeatureList; -pub use wrapper::{Rgb25, RGB25_IFACE_ID}; +use rgbstd::interface::{Iface, IfaceClass, IfaceId}; +use rgbstd::persistence::ContractStateRead; +use rgbstd::stl::rgb_contract_stl; +use strict_types::TypeLib; +pub use wrapper::{Rgb25Wrapper, RGB25_IFACE_ID}; + +use crate::rgb20::iface::{burnable, fungible}; +use crate::rgb25::iface::named_contract; +use crate::rgb25::wrapper::RGB25_BASE_IFACE_ID; #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)] #[cfg_attr( @@ -36,13 +44,13 @@ pub use wrapper::{Rgb25, RGB25_IFACE_ID}; derive(Serialize, Deserialize), serde(crate = "serde_crate", rename_all = "camelCase") )] -pub struct Features { +pub struct Rgb25 { pub burnable: bool, } -impl Features { - pub const NONE: Self = Features { burnable: false }; - pub const ALL: Self = Features { burnable: true }; +impl Rgb25 { + pub const NONE: Self = Rgb25 { burnable: false }; + pub const ALL: Self = Rgb25 { burnable: true }; pub const ENUMERATE: &'static [Self] = &[Self::NONE, Self::ALL]; @@ -55,33 +63,58 @@ impl Features { } } +impl IfaceClass for Rgb25 { + const IFACE_NAME: &'static str = "RGB25"; + const IFACE_IDS: &'static [IfaceId] = &[RGB25_BASE_IFACE_ID, RGB25_IFACE_ID]; + type Wrapper = Rgb25Wrapper; + + fn stl(&self) -> TypeLib { rgb_contract_stl() } + + fn iface(&self) -> Iface { + let mut iface = named_contract().expect_extended(fungible(), "RGB25Base"); + /* + if self.reserves { + iface = iface.expect_extended(reservable(), "RGB25Reservable"); + } + */ + if self.burnable { + iface = iface.expect_extended(burnable(), "RGB25Burnable"); + } + iface + } + + fn iface_id(&self) -> IfaceId { + // TODO: Optimize with constants + self.iface().iface_id() + } +} + #[cfg(test)] mod test { use amplify::ByteArray; use rgbstd::interface::IfaceClass; use super::*; - use crate::Dumb; #[test] fn iface_id_all() { - let iface_id = Rgb25::::iface(Features::NONE).iface_id(); + let iface_id = Rgb25::NONE.iface_id(); eprintln!("{:#04x?}", iface_id.to_byte_array()); - assert_eq!(Rgb25::::IFACE_IDS[0], iface_id); - let iface_id = Rgb25::::iface(Features::ALL).iface_id(); + assert_eq!(Rgb25::IFACE_IDS[0], iface_id); + let iface_id = Rgb25::ALL.iface_id(); eprintln!("{:#04x?}", iface_id.to_byte_array()); - assert_eq!(Rgb25::::IFACE_IDS[1], iface_id); + assert_eq!(Rgb25::IFACE_IDS[1], iface_id); } #[test] fn iface_check() { - if let Err(err) = Rgb25::::iface(Features::NONE).check() { + if let Err(err) = Rgb25::NONE.iface().check() { for e in err { eprintln!("- {e}"); } panic!("invalid RGB25 interface definition"); } - if let Err(err) = Rgb25::::iface(Features::ALL).check() { + if let Err(err) = Rgb25::ALL.iface().check() { for e in err { eprintln!("- {e}"); } diff --git a/src/rgb25/wrapper.rs b/src/rgb25/wrapper.rs index 23437f0..8f5b5ce 100644 --- a/src/rgb25/wrapper.rs +++ b/src/rgb25/wrapper.rs @@ -20,18 +20,15 @@ // limitations under the License. use rgbstd::interface::{ - ContractIface, FungibleAllocation, Iface, IfaceClass, IfaceId, OutpointFilter, + ContractIface, FungibleAllocation, IfaceClass, IfaceId, IfaceWrapper, OutpointFilter, }; use rgbstd::invoice::{Amount, Precision}; use rgbstd::persistence::ContractStateRead; -use rgbstd::stl::{rgb_contract_stl, ContractTerms, Details, Name}; +use rgbstd::stl::{ContractTerms, Details, Name}; use rgbstd::AssetTag; use strict_encoding::InvalidRString; -use strict_types::TypeLib; -use super::{Features, Issue, Rgb25Info}; -use crate::rgb20::iface::*; -use crate::rgb25::iface::named_contract; +use super::{Issue, Rgb25, Rgb25Info}; use crate::IssuerWrapper; pub const RGB25_BASE_IFACE_ID: IfaceId = IfaceId::from_array([ @@ -45,63 +42,37 @@ pub const RGB25_IFACE_ID: IfaceId = IfaceId::from_array([ ]); #[derive(Clone, Eq, PartialEq, Debug)] -pub struct Rgb25(ContractIface); +pub struct Rgb25Wrapper(ContractIface); -impl From> for Rgb25 { - fn from(iface: ContractIface) -> Self { - if !Rgb25::::IFACE_IDS.contains(&iface.iface.iface_id) { - panic!("the provided interface is not RGB25 interface"); - } - Self(iface) - } -} - -impl IfaceClass for Rgb25 { - const IFACE_NAME: &'static str = "RGB25"; - const IFACE_IDS: &'static [IfaceId] = &[RGB25_BASE_IFACE_ID, RGB25_IFACE_ID]; - - type Features = Features; +impl IfaceWrapper for Rgb25Wrapper { type Info = Rgb25Info; - fn iface(features: Features) -> Iface { - let mut iface = named_contract().expect_extended(fungible(), "RGB25Base"); - /* - if features.reserves { - iface = iface.expect_extended(reservable(), "RGB25Reservable"); - } - */ - if features.burnable { - iface = iface.expect_extended(burnable(), "RGB25Burnable"); + fn with(iface: ContractIface) -> Self { + if !Rgb25::IFACE_IDS.contains(&iface.iface.iface_id) { + panic!("the provided interface is not RGB25 interface"); } - iface - } - - fn iface_id(features: Self::Features) -> IfaceId { - // TODO: Optimize with constants - Rgb25::::iface(features).iface_id() + Self(iface) } - fn stl() -> TypeLib { rgb_contract_stl() } - fn info(&self) -> Self::Info { todo!() } } -impl Rgb25 { - pub fn testnet>( +impl Rgb25Wrapper { + pub fn testnet>( issuer: &str, name: &str, precision: Precision, ) -> Result { - Issue::testnet::(issuer, name, precision) + Issue::testnet::(issuer, name, precision) } - pub fn testnet_det>( + pub fn testnet_det>( issuer: &str, name: &str, precision: Precision, asset_tag: AssetTag, ) -> Result { - Issue::testnet_det::(issuer, name, precision, asset_tag) + Issue::testnet_det::(issuer, name, precision, asset_tag) } pub fn name(&self) -> Name { diff --git a/src/traits.rs b/src/traits.rs index b6a8290..98e4ad0 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -19,8 +19,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::marker::PhantomData; - use amplify::confinement::Confined; use rgbstd::containers::{ContainerVer, Kit, ValidKit}; use rgbstd::interface::{IfaceClass, IfaceImpl}; @@ -30,8 +28,8 @@ use strict_types::typesys::UnknownType; use strict_types::TypeSystem; pub trait IssuerWrapper { - const FEATURES: ::Features; type IssuingIface: IfaceClass; + const FEATURES: Self::IssuingIface; fn schema() -> Schema; fn issue_impl() -> IfaceImpl; @@ -52,7 +50,7 @@ pub trait IssuerWrapper { fn kit() -> ValidKit { let kit = Kit { version: ContainerVer::V2, - ifaces: tiny_bset![Self::IssuingIface::iface(Self::FEATURES)], + ifaces: tiny_bset![Self::FEATURES.iface()], schemata: tiny_bset![Self::schema()], iimpls: tiny_bset![Self::issue_impl()], supplements: none!(), @@ -68,10 +66,9 @@ pub trait IssuerWrapper { pub struct SchemaIssuer { schema: Schema, iimpl: IfaceImpl, - features: I::Features, + features: I, types: TypeSystem, scripts: Scripts, - phantom: PhantomData, } impl SchemaIssuer { @@ -81,7 +78,7 @@ impl SchemaIssuer { iimpl: IfaceImpl, type_system: TypeSystem, scripts: Scripts, - features: I::Features, + features: I, ) -> Result { let types = type_system.extract(schema.types())?; Ok(Self { @@ -90,12 +87,11 @@ impl SchemaIssuer { features, types, scripts, - phantom: default!(), }) } #[inline] - pub fn into_split(self) -> (Schema, IfaceImpl, TypeSystem, Scripts, I::Features) { + pub fn into_split(self) -> (Schema, IfaceImpl, TypeSystem, Scripts, I) { (self.schema, self.iimpl, self.types, self.scripts, self.features) } }