1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
// RGB20 Library: high-level API to RGB fungible assets.
// Written in 2019-2022 by
// Dr. Maxim Orlovsky <orlovsky@lnp-bp.org>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy of the MIT License along with this software.
// If not, see <https://opensource.org/licenses/MIT>.
use std::collections::btree_set;
use bitcoin::OutPoint;
use rgb::{ConsignmentType, ContractState, InmemConsignment, NodeId, OwnedValue};
/// RGB20 asset information.
///
/// Structure presents complete set of RGB20 asset-related data which can be
/// extracted from the genesis or a consignment. It is not the source of the
/// truth, and the presence of the data in the structure does not imply their
/// validity, since the structure constructor does not validates blockchain or
/// LN-based transaction commitments or satisfaction of schema requirements.
///
/// The main reason of the structure is:
/// 1) to persist *cached* copy of the asset data without the requirement to
/// parse all stash transition each time in order to extract allocation
/// information;
/// 2) to present data from asset genesis or consignment for UI in convenient
/// form.
/// 3) to orchestrate generation of new state transitions taking into account
/// known asset information.
///
/// (1) is important for wallets, (2) is for more generic software, like
/// client-side-validated data explorers, developer & debugging tools etc and
/// (3) for asset-management software.
///
/// In both (2) and (3) case there is no need to persist the structure; genesis
/// /consignment should be persisted instead and the structure must be
/// reconstructed each time from that data upon the launch
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
#[derive(StrictEncode, StrictDecode)]
pub struct Asset(ContractState);
impl Asset {
/// Lists all known allocations for the given bitcoin transaction
/// [`OutPoint`]
pub fn known_coins(&self) -> btree_set::Iter<OwnedValue> { self.0.owned_values.iter() }
/// Lists all known allocations for the given bitcoin transaction
/// [`OutPoint`]
pub fn outpoint_coins(&self, outpoint: OutPoint) -> Vec<OwnedValue> {
self.known_coins()
.filter(|a| a.seal == outpoint)
.cloned()
.collect()
}
}
impl<T> TryFrom<&InmemConsignment<T>> for Asset
where T: ConsignmentType
{
type Error = Error;
fn try_from(consignment: &InmemConsignment<T>) -> Result<Self, Self::Error> {
let state = ContractState::from(consignment);
let asset = Asset(state);
asset.validate()?;
Ok(asset)
}
}
impl Asset {
fn validate(&self) -> Result<(), Error> {
if self.0.schema_id != crate::schema().schema_id() {
Err(Error::WrongSchemaId)?;
}
// TODO: Validate the state
Ok(())
}
}
/// Errors generated during RGB20 asset information parsing from the underlying
/// genesis or consignment data
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Display, From, Error)]
#[display(doc_comments)]
pub enum Error {
/// genesis schema id does not match any of RGB20 schemata
WrongSchemaId,
/// genesis defines a seal referencing witness transaction while there
/// can't be a witness transaction for genesis
GenesisSeal,
/// epoch seal definition for node {0} contains confidential data
EpochSealConfidential(NodeId),
/// nurn & replace seal definition for node {0} contains confidential data
BurnSealConfidential(NodeId),
/// inflation assignment (seal or state) for node {0} contains confidential
/// data
InflationAssignmentConfidential(NodeId),
/// not of all epochs referenced in burn or burn & replace operation
/// history are known from the consignment
NotAllEpochsExposed,
}