use std::str::FromStr;
use rgb::schema::{
DiscreteFiniteFieldFormat, GenesisSchema, Occurrences, Schema, SchemaId, StateSchema,
TransitionSchema,
};
use rgb::script::OverrideRules;
use rgb::vm::embedded::constants::*;
use rgb::ValidationScript;
use stens::{PrimitiveType, StructField, TypeRef, TypeSystem};
pub const SCHEMA_ID_BECH32: &str =
"rgbsh1ykclt9qxkskqt88dwgccsp4w624k7adjwj06sknjkh04ygtc7rqsnykld7";
pub const SUBSCHEMA_ID_BECH32: &str =
"rgbsh1ep4k4qvghntwptcn0gqmfpdvr8vz3amslvy4pc7s32u7h500l5hqxlzjsk";
pub const FIELD_TYPE_PARENT_ID: u16 = 0xC3;
pub const TRANSITION_TYPE_ENGRAVING: u16 = 0x10A4;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
#[display(Debug)]
#[repr(u16)]
pub enum FieldType {
Name = FIELD_TYPE_NAME,
RicardianContract = FIELD_TYPE_CONTRACT_TEXT,
Description = FIELD_TYPE_COMMENTARY,
Data = FIELD_TYPE_DATA,
DataFormat = FIELD_TYPE_DATA_FORMAT,
Precision = FIELD_TYPE_PRECISION,
IssuedSupply = FIELD_TYPE_ISSUED_SUPPLY,
Timestamp = FIELD_TYPE_TIMESTAMP,
ParentId = FIELD_TYPE_PARENT_ID,
}
impl From<FieldType> for rgb::schema::FieldType {
#[inline]
fn from(ft: FieldType) -> Self { ft as rgb::schema::FieldType }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
#[display(Debug)]
#[repr(u16)]
pub enum OwnedRightType {
Assets = STATE_TYPE_OWNERSHIP_RIGHT,
Engraving = STATE_TYPE_OWNERSHIP_RIGHT + 1,
}
impl From<OwnedRightType> for rgb::schema::OwnedRightType {
#[inline]
fn from(t: OwnedRightType) -> Self { t as rgb::schema::OwnedRightType }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
#[display(Debug)]
#[repr(u16)]
pub enum TransitionType {
Issue = TRANSITION_TYPE_ISSUE_NFT,
Transfer = TRANSITION_TYPE_VALUE_TRANSFER,
Engraving = TRANSITION_TYPE_ENGRAVING,
}
impl From<TransitionType> for rgb::schema::TransitionType {
#[inline]
fn from(t: TransitionType) -> Self { t as rgb::schema::TransitionType }
}
fn type_system() -> TypeSystem {
type_system! {
"OutPoint" :: {
StructField::with("Txid"),
StructField::primitive(PrimitiveType::U16),
},
"Txid" :: { StructField::array(PrimitiveType::U8, 32) }
}
}
fn genesis() -> GenesisSchema {
use Occurrences::*;
GenesisSchema {
metadata: type_map! {
FieldType::Name => Once,
FieldType::RicardianContract => NoneOrOnce,
FieldType::Description => NoneOrOnce,
FieldType::Data => NoneOrMore,
FieldType::DataFormat => NoneOrOnce,
FieldType::Precision => Once,
FieldType::Timestamp => Once,
FieldType::IssuedSupply => Once,
FieldType::ParentId => NoneOrOnce
},
owned_rights: type_map! {
OwnedRightType::Assets => NoneOrMore,
OwnedRightType::Engraving => NoneOrMore
},
public_rights: none!(),
}
}
fn issue() -> TransitionSchema {
use Occurrences::*;
TransitionSchema {
metadata: type_map! {
FieldType::IssuedSupply => Once,
FieldType::Data => NoneOrMore,
FieldType::DataFormat => NoneOrOnce
},
closes: none!(),
owned_rights: type_map! {
OwnedRightType::Assets => NoneOrMore,
OwnedRightType::Engraving => NoneOrMore
},
public_rights: none!(),
}
}
pub fn schema() -> Schema {
use Occurrences::*;
Schema {
rgb_features: none!(),
root_id: none!(),
genesis: genesis(),
type_system: type_system(),
extensions: none!(),
transitions: type_map! {
TransitionType::Issue => issue(),
TransitionType::Transfer => TransitionSchema {
metadata: none!(),
closes: type_map! {
OwnedRightType::Assets => OnceOrMore
},
owned_rights: type_map! {
OwnedRightType::Assets => NoneOrMore
},
public_rights: none!()
},
TransitionType::Engraving => TransitionSchema {
metadata: type_map! {
FieldType::Data => NoneOrMore,
FieldType::DataFormat => NoneOrOnce
},
closes: type_map! {
OwnedRightType::Assets => OnceOrMore,
OwnedRightType::Engraving => NoneOrMore
},
owned_rights: type_map! {
OwnedRightType::Assets => NoneOrMore,
OwnedRightType::Engraving => NoneOrMore
},
public_rights: none!()
}
},
field_types: type_map! {
FieldType::Name => TypeRef::ascii_string(),
FieldType::RicardianContract => TypeRef::ascii_string(),
FieldType::Description => TypeRef::ascii_string(),
FieldType::Data => TypeRef::bytes(),
FieldType::DataFormat => TypeRef::u16(),
FieldType::Precision => TypeRef::u8(),
FieldType::IssuedSupply => TypeRef::u64(),
FieldType::Timestamp => TypeRef::i64(),
FieldType::ParentId => TypeRef::ascii_string()
},
owned_right_types: type_map! {
OwnedRightType::Assets => StateSchema::DiscreteFiniteField(DiscreteFiniteFieldFormat::Unsigned64bit),
OwnedRightType::Engraving => StateSchema::DataContainer
},
public_right_types: none!(),
script: ValidationScript::Embedded,
override_rules: OverrideRules::AllowAnyVm,
}
}
pub fn subschema() -> Schema {
use Occurrences::*;
Schema {
rgb_features: none!(),
root_id: SchemaId::from_str(SCHEMA_ID_BECH32)
.expect("Broken root schema ID for RGB121 sub-schema"),
type_system: type_system(),
genesis: genesis(),
extensions: none!(),
transitions: type_map! {
TransitionType::Issue => issue(),
TransitionType::Transfer => TransitionSchema {
metadata: none!(),
closes: type_map! {
OwnedRightType::Assets => OnceOrMore
},
owned_rights: type_map! {
OwnedRightType::Assets => NoneOrMore
},
public_rights: none!()
}
},
field_types: type_map! {
FieldType::Name => TypeRef::ascii_string(),
FieldType::RicardianContract => TypeRef::ascii_string(),
FieldType::Description => TypeRef::ascii_string(),
FieldType::Data => TypeRef::bytes(),
FieldType::DataFormat => TypeRef::u16(),
FieldType::Precision => TypeRef::u8(),
FieldType::IssuedSupply => TypeRef::u64(),
FieldType::Timestamp => TypeRef::i64(),
FieldType::ParentId => TypeRef::ascii_string()
},
owned_right_types: type_map! {
OwnedRightType::Assets => StateSchema::DiscreteFiniteField(DiscreteFiniteFieldFormat::Unsigned64bit),
OwnedRightType::Engraving => StateSchema::DataContainer
},
public_right_types: none!(),
script: ValidationScript::Embedded,
override_rules: OverrideRules::AllowAnyVm,
}
}
#[cfg(test)]
mod test {
use lnpbp::bech32::Bech32ZipString;
use rgb::schema::SchemaVerify;
use rgb::Validity;
use strict_encoding::{StrictDecode, StrictEncode};
use super::*;
#[test]
fn schema_id() {
let id = schema().schema_id();
assert_eq!(id.to_string(), SCHEMA_ID_BECH32);
assert_eq!(
id.to_string(),
"rgbsh1ykclt9qxkskqt88dwgccsp4w624k7adjwj06sknjkh04ygtc7rqsnykld7"
);
}
#[test]
fn subschema_id() {
let id = subschema().schema_id();
assert_eq!(id.to_string(), SUBSCHEMA_ID_BECH32);
assert_eq!(
id.to_string(),
"rgbsh1ep4k4qvghntwptcn0gqmfpdvr8vz3amslvy4pc7s32u7h500l5hqxlzjsk"
);
}
#[test]
fn schema_strict_encode() {
let data = schema()
.strict_serialize()
.expect("RGB-121 schema serialization failed");
let bech32data = data.bech32_zip_string();
println!("{}", bech32data);
let schema121 =
Schema::strict_deserialize(data).expect("RGB-121 schema deserialization failed");
assert_eq!(schema(), schema121);
assert_eq!(format!("{:#?}", schema()), format!("{:#?}", schema121));
assert_eq!(
bech32data,
"z1qxz56wgwcfqqe894xuf8fzlcqqlc9q386zjgzfjg8sn5fapuytlkyxtmjv3g0994wej8k0pnmp7gy8wweln0\
928035szpch64fhjf33kqr5ug7w0p58r7v2s2dr0ucm9vv3tp2rfp8df0wehq5wmg29dc3wat7lgtrucvuhya3a\
tf0h0h5mskce6g79lghpjv6whxxrcuzfkfc3zcdz4rnnahey4wv43ejfn7eajpk0"
);
}
#[test]
fn subschema_verify() {
let status = subschema().schema_verify(&schema());
assert_eq!(status.validity(), Validity::Valid);
}
}