use std::borrow::Cow;
use ootle_byte_type::FromByteType;
use serde::{Deserialize, Serialize};
use tari_crypto::{ristretto::RistrettoPublicKey, tari_utilities::ByteArrayError};
use tari_template_lib::{
resource::TOKEN_SYMBOL,
types::{
Amount,
AuthHook,
Metadata,
ResourceType,
SubstateOwnerRule,
access_rules::ResourceAccessRules,
crypto::RistrettoPublicKeyBytes,
},
};
use crate::ownership::Ownership;
#[derive(Debug, Clone, Serialize, Deserialize, borsh::BorshSerialize)]
#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))]
pub struct Resource {
resource_type: ResourceType,
owner_rule: SubstateOwnerRule,
access_rules: ResourceAccessRules,
metadata: Metadata,
total_supply: Option<Amount>,
view_key: Option<RistrettoPublicKeyBytes>,
auth_hook: Option<AuthHook>,
divisibility: u8,
}
impl Resource {
pub const fn new(
resource_type: ResourceType,
owner_rule: SubstateOwnerRule,
access_rules: ResourceAccessRules,
metadata: Metadata,
view_key: Option<RistrettoPublicKeyBytes>,
auth_hook: Option<AuthHook>,
mut divisibility: u8,
is_total_supply_tracking_enabled: bool,
) -> Self {
if resource_type.is_non_fungible() {
divisibility = 0;
}
Self {
resource_type,
owner_rule,
access_rules,
metadata,
total_supply: if is_total_supply_tracking_enabled {
Some(Amount::zero())
} else {
None
},
divisibility,
view_key,
auth_hook,
}
}
pub fn load(
resource_type: ResourceType,
owner_rule: SubstateOwnerRule,
access_rules: ResourceAccessRules,
metadata: Metadata,
view_key: Option<RistrettoPublicKeyBytes>,
auth_hook: Option<AuthHook>,
divisibility: u8,
total_supply: Option<Amount>,
) -> Self {
Self {
resource_type,
owner_rule,
access_rules,
metadata,
total_supply,
view_key,
auth_hook,
divisibility,
}
}
pub fn resource_type(&self) -> ResourceType {
self.resource_type
}
pub fn owner_rule(&self) -> &SubstateOwnerRule {
&self.owner_rule
}
pub fn owner_key(&self) -> Option<&RistrettoPublicKeyBytes> {
self.owner_rule.owned_by_public_key()
}
pub fn as_ownership(&self) -> Ownership<'_> {
Ownership {
owner_rule: Cow::Borrowed(&self.owner_rule),
}
}
pub fn view_key(&self) -> Option<&RistrettoPublicKeyBytes> {
self.view_key.as_ref()
}
pub fn to_view_key_public_key(&self) -> Result<Option<RistrettoPublicKey>, ByteArrayError> {
match self.view_key.as_ref() {
Some(view_key) => view_key.try_from_byte_type().map(Some),
None => Ok(None),
}
}
pub fn auth_hook(&self) -> Option<&AuthHook> {
self.auth_hook.as_ref()
}
pub fn access_rules(&self) -> &ResourceAccessRules {
&self.access_rules
}
pub fn set_access_rules(&mut self, access_rules: ResourceAccessRules) {
self.access_rules = access_rules;
}
pub fn is_supply_tracking_enabled(&self) -> bool {
self.total_supply.is_some()
}
pub fn increase_total_supply(&mut self, amount: Amount) -> bool {
let Some(supply_mut) = self.total_supply.as_mut() else {
return true;
};
let next_supply = supply_mut.checked_add(amount);
match next_supply {
Some(new_supply) => {
*supply_mut = new_supply;
true
},
None => false,
}
}
pub fn decrease_total_supply(&mut self, amount: Amount) {
if let Some(supply_mut) = self.total_supply.as_mut() {
*supply_mut = supply_mut.checked_sub(amount).expect(
"Invariant violation in decrease_total_supply: decrease total supply by more than total supply",
);
}
}
pub fn total_supply(&self) -> Option<Amount> {
self.total_supply
}
pub fn metadata(&self) -> &Metadata {
&self.metadata
}
pub fn metadata_mut(&mut self) -> &mut Metadata {
&mut self.metadata
}
pub fn token_symbol(&self) -> Option<&str> {
self.metadata.get(TOKEN_SYMBOL)
}
pub fn divisibility(&self) -> u8 {
self.divisibility
}
}