radix-engine 1.3.1

Reference implementation of Radix Engine, from the Radix DLT project.
Documentation
use crate::blueprints::resource::{
    fungible_vault, non_fungible_vault, BurnFungibleResourceEvent, BurnNonFungibleResourceEvent,
    MintFungibleResourceEvent, MintNonFungibleResourceEvent,
};
use crate::system::checkers::ApplicationEventChecker;
use radix_common::constants::RESOURCE_PACKAGE;
use radix_common::math::{CheckedAdd, CheckedSub, Decimal};
use radix_common::prelude::{scrypto_decode, ResourceAddress};
use radix_common::traits::ScryptoEvent;
use radix_common::types::NodeId;
use radix_engine_interface::api::ModuleId;
use radix_engine_interface::blueprints::resource::{
    FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, FUNGIBLE_VAULT_BLUEPRINT,
    NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT, NON_FUNGIBLE_VAULT_BLUEPRINT,
};
use radix_engine_interface::prelude::{BlueprintInfo, Emitter};
use radix_engine_interface::types::EventTypeIdentifier;
use sbor::rust::collections::BTreeMap;
use sbor::rust::vec::Vec;

#[derive(Debug, Default)]
pub struct ResourceEventChecker {
    resource_tracker: BTreeMap<ResourceAddress, Decimal>,
    vault_tracker: BTreeMap<NodeId, Decimal>,
}

#[derive(Debug, Default)]
pub struct ResourceEventCheckerResults {
    pub total_supply: BTreeMap<ResourceAddress, Decimal>,
    pub vault_amounts: BTreeMap<NodeId, Decimal>,
}

impl ApplicationEventChecker for ResourceEventChecker {
    type ApplicationEventCheckerResults = ResourceEventCheckerResults;

    fn on_event(
        &mut self,
        info: BlueprintInfo,
        event_id: EventTypeIdentifier,
        event_payload: &Vec<u8>,
    ) {
        if info.blueprint_id.package_address.ne(&RESOURCE_PACKAGE) {
            return;
        }

        match info.blueprint_id.blueprint_name.as_str() {
            FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT => {
                if let EventTypeIdentifier(Emitter::Method(node_id, ModuleId::Main), event_name) =
                    event_id
                {
                    let address = ResourceAddress::new_or_panic(node_id.0);
                    match event_name.as_str() {
                        MintFungibleResourceEvent::EVENT_NAME => {
                            let event: MintFungibleResourceEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.resource_tracker.entry(address).or_default();
                            *tracked = tracked.checked_add(event.amount).unwrap();
                        }
                        BurnFungibleResourceEvent::EVENT_NAME => {
                            let event: BurnFungibleResourceEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.resource_tracker.entry(address).or_default();
                            *tracked = tracked.checked_sub(event.amount).unwrap();

                            if tracked.is_negative() {
                                panic!("Burnt more resources than was minted.");
                            }
                        }
                        _ => {}
                    }
                }
            }
            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT => {
                if let EventTypeIdentifier(Emitter::Method(node_id, ModuleId::Main), event_name) =
                    event_id
                {
                    let address = ResourceAddress::new_or_panic(node_id.0);
                    match event_name.as_str() {
                        MintNonFungibleResourceEvent::EVENT_NAME => {
                            let event: MintNonFungibleResourceEvent =
                                scrypto_decode(event_payload).unwrap();
                            let amount: Decimal = event.ids.len().into();
                            let tracked = self.resource_tracker.entry(address).or_default();
                            *tracked = tracked.checked_add(amount).unwrap();
                        }
                        BurnNonFungibleResourceEvent::EVENT_NAME => {
                            let event: BurnNonFungibleResourceEvent =
                                scrypto_decode(event_payload).unwrap();
                            let amount: Decimal = event.ids.len().into();
                            let tracked = self.resource_tracker.entry(address).or_default();
                            *tracked = tracked.checked_sub(amount).unwrap();

                            if tracked.is_negative() {
                                panic!("Burnt more resources than was minted.");
                            }
                        }
                        _ => {}
                    }
                }
            }
            FUNGIBLE_VAULT_BLUEPRINT => {
                if let EventTypeIdentifier(Emitter::Method(node_id, ModuleId::Main), event_name) =
                    event_id
                {
                    match event_name.as_str() {
                        fungible_vault::DepositEvent::EVENT_NAME => {
                            let event: fungible_vault::DepositEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            *tracked = tracked.checked_add(event.amount).unwrap();
                        }
                        fungible_vault::WithdrawEvent::EVENT_NAME => {
                            let event: fungible_vault::WithdrawEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            *tracked = tracked.checked_sub(event.amount).unwrap();
                            if tracked.is_negative() {
                                panic!("Removed more resources than exists.");
                            }
                        }
                        fungible_vault::RecallEvent::EVENT_NAME => {
                            let event: fungible_vault::RecallEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            *tracked = tracked.checked_sub(event.amount).unwrap();
                            if tracked.is_negative() {
                                panic!("Removed more resources than exists.");
                            }
                        }
                        fungible_vault::PayFeeEvent::EVENT_NAME => {
                            let event: fungible_vault::PayFeeEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            *tracked = tracked.checked_sub(event.amount).unwrap();
                            if tracked.is_negative() {
                                panic!("Removed more resources than exists.");
                            }
                        }
                        _ => {}
                    }
                }
            }
            NON_FUNGIBLE_VAULT_BLUEPRINT => {
                if let EventTypeIdentifier(Emitter::Method(node_id, ModuleId::Main), event_name) =
                    event_id
                {
                    match event_name.as_str() {
                        non_fungible_vault::DepositEvent::EVENT_NAME => {
                            let event: non_fungible_vault::DepositEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            let amount: Decimal = event.ids.len().into();
                            *tracked = tracked.checked_add(amount).unwrap();
                        }
                        non_fungible_vault::WithdrawEvent::EVENT_NAME => {
                            let event: non_fungible_vault::WithdrawEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            let amount: Decimal = event.ids.len().into();
                            *tracked = tracked.checked_sub(amount).unwrap();
                            if tracked.is_negative() {
                                panic!("Removed more resources than exists.");
                            }
                        }
                        fungible_vault::RecallEvent::EVENT_NAME => {
                            let event: non_fungible_vault::RecallEvent =
                                scrypto_decode(event_payload).unwrap();
                            let tracked = self.vault_tracker.entry(node_id).or_default();
                            let amount: Decimal = event.ids.len().into();
                            *tracked = tracked.checked_sub(amount).unwrap();
                            if tracked.is_negative() {
                                panic!("Removed more resources than exists.");
                            }
                        }
                        _ => {}
                    }
                }
            }
            _ => {}
        }
    }

    fn on_finish(&self) -> Self::ApplicationEventCheckerResults {
        ResourceEventCheckerResults {
            total_supply: self.resource_tracker.clone(),
            vault_amounts: self.vault_tracker.clone(),
        }
    }
}