#![allow(unused_braces)]
use std::fmt::Debug;
use bp::bc::stl::bitcoin_stl;
use strict_encoding::{StrictDumb, StrictEncode};
use strict_types::stl::std_stl;
use strict_types::{CompileError, LibBuilder, TypeLib};
use super::{
AssignIface, GenesisIface, GlobalIface, Iface, OwnedIface, Req, TransitionIface, VerNo,
};
use crate::interface::{ArgSpec, ContractIface};
use crate::stl::{rgb_contract_stl, Amount, ContractData, Details, Name, Precision, StandardTypes};
pub const LIB_NAME_RGB25: &str = "RGB25";
pub const LIB_ID_RGB25: &str =
"urn:ubideco:stl:4JmGrg7oTgwuCQtyC4ezC38ToHMzgMCVS5kMSDPwo2ee#camera-betty-bank";
const SUPPLY_MISMATCH: u8 = 1;
const NON_EQUAL_AMOUNTS: u8 = 2;
const INVALID_PROOF: u8 = 3;
const INSUFFICIENT_RESERVES: u8 = 4;
const INSUFFICIENT_COVERAGE: u8 = 5;
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB25, tags = repr, into_u8, try_from_u8)]
#[repr(u8)]
pub enum Error {
#[strict_type(dumb)]
SupplyMismatch = SUPPLY_MISMATCH,
NonEqualAmounts = NON_EQUAL_AMOUNTS,
InvalidProof = INVALID_PROOF,
InsufficientReserves = INSUFFICIENT_RESERVES,
InsufficientCoverage = INSUFFICIENT_COVERAGE,
}
fn _rgb25_stl() -> Result<TypeLib, CompileError> {
LibBuilder::new(libname!(LIB_NAME_RGB25), tiny_bset! {
std_stl().to_dependency(),
bitcoin_stl().to_dependency(),
rgb_contract_stl().to_dependency(),
})
.transpile::<Error>()
.compile()
}
pub fn rgb25_stl() -> TypeLib { _rgb25_stl().expect("invalid strict type RGB25 library") }
pub fn rgb25() -> Iface {
let types = StandardTypes::with(rgb25_stl());
Iface {
version: VerNo::V1,
name: tn!("RGB25"),
global_state: tiny_bmap! {
fname!("name") => GlobalIface::required(types.get("RGBContract.Name")),
fname!("details") => GlobalIface::optional(types.get("RGBContract.Details")),
fname!("precision") => GlobalIface::required(types.get("RGBContract.Precision")),
fname!("data") => GlobalIface::required(types.get("RGBContract.ContractData")),
fname!("created") => GlobalIface::required(types.get("RGBContract.Timestamp")),
fname!("issuedSupply") => GlobalIface::required(types.get("RGBContract.Amount")),
fname!("burnedSupply") => GlobalIface::none_or_many(types.get("RGBContract.Amount")),
},
assignments: tiny_bmap! {
fname!("assetOwner") => AssignIface::private(OwnedIface::Amount, Req::OneOrMore),
fname!("burnRight") => AssignIface::public(OwnedIface::Rights, Req::NoneOrMore),
},
valencies: none!(),
genesis: GenesisIface {
metadata: Some(types.get("RGBContract.IssueMeta")),
global: tiny_bmap! {
fname!("name") => ArgSpec::required(),
fname!("details") => ArgSpec::optional(),
fname!("precision") => ArgSpec::required(),
fname!("data") => ArgSpec::required(),
fname!("created") => ArgSpec::required(),
fname!("issuedSupply") => ArgSpec::required(),
},
assignments: tiny_bmap! {
fname!("assetOwner") => ArgSpec::non_empty(),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_RESERVES
},
},
transitions: tiny_bmap! {
tn!("Transfer") => TransitionIface {
optional: false,
metadata: None,
globals: none!(),
inputs: tiny_bmap! {
fname!("previous") => ArgSpec::from_non_empty("assetOwner"),
},
assignments: tiny_bmap! {
fname!("beneficiary") => ArgSpec::from_non_empty("assetOwner"),
},
valencies: none!(),
errors: tiny_bset! {
NON_EQUAL_AMOUNTS
},
default_assignment: Some(fname!("beneficiary")),
},
tn!("Burn") => TransitionIface {
optional: true,
metadata: Some(types.get("RGBContract.BurnMeta")),
globals: tiny_bmap! {
fname!("burnedSupply") => ArgSpec::required(),
},
inputs: tiny_bmap! {
fname!("used") => ArgSpec::from_required("burnRight"),
},
assignments: tiny_bmap! {
fname!("future") => ArgSpec::from_optional("burnRight"),
},
valencies: none!(),
errors: tiny_bset! {
SUPPLY_MISMATCH,
INVALID_PROOF,
INSUFFICIENT_COVERAGE
},
default_assignment: None,
},
},
extensions: none!(),
error_type: types.get("RGB25.Error"),
default_operation: Some(tn!("Transfer")),
type_system: types.type_system(),
}
}
#[derive(Wrapper, WrapperMut, Clone, Eq, PartialEq, Debug)]
#[wrapper(Deref)]
#[wrapper_mut(DerefMut)]
pub struct Rgb25(ContractIface);
impl From<ContractIface> for Rgb25 {
fn from(iface: ContractIface) -> Self {
if iface.iface.iface_id != rgb25().iface_id() {
panic!("the provided interface is not RGB25 interface");
}
Self(iface)
}
}
impl Rgb25 {
pub fn name(&self) -> Name {
let strict_val = &self
.0
.global("name")
.expect("RGB25 interface requires global `name`")[0];
Name::from_strict_val_unchecked(strict_val)
}
pub fn details(&self) -> Option<Details> {
let strict_val = &self
.0
.global("details")
.expect("RGB25 interface requires global `details`");
if strict_val.len() == 0 {
None
} else {
Some(Details::from_strict_val_unchecked(&strict_val[0]))
}
}
pub fn precision(&self) -> Precision {
let strict_val = &self
.0
.global("precision")
.expect("RGB25 interface requires global `precision`")[0];
Precision::from_strict_val_unchecked(strict_val)
}
pub fn total_issued_supply(&self) -> Amount {
self.0
.global("issuedSupply")
.expect("RGB25 interface requires global `issuedSupply`")
.iter()
.map(Amount::from_strict_val_unchecked)
.sum()
}
pub fn total_burned_supply(&self) -> Amount {
self.0
.global("burnedSupply")
.unwrap_or_default()
.iter()
.map(Amount::from_strict_val_unchecked)
.sum()
}
pub fn contract_data(&self) -> ContractData {
let strict_val = &self
.0
.global("data")
.expect("RGB25 interface requires global `data`")[0];
ContractData::from_strict_val_unchecked(strict_val)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::containers::BindleContent;
const RGB25: &str = include_str!("../../tests/data/rgb25.rgba");
#[test]
fn lib_id() {
let lib = rgb25_stl();
assert_eq!(lib.id().to_string(), LIB_ID_RGB25);
}
#[test]
fn iface_creation() { rgb25(); }
#[test]
fn iface_bindle() {
assert_eq!(format!("{}", rgb25().bindle()), RGB25);
}
}