radix_substate_store_queries/
typed_native_events.rs

1//! This module contains the code and models that are required to convert native events into a typed
2//! model based on the [`EventTypeIdentifier`] and the raw SBOR bytes of the event. This is used in
3//! the toolkit and consumed by the gateway for some of its internal operations.
4
5use crate::typed_substate_layout::*;
6use radix_common::prelude::*;
7use radix_engine::blueprints::access_controller::latest::*;
8use radix_engine::blueprints::account;
9use radix_engine::blueprints::locker::*;
10use radix_engine::blueprints::native_schema::*;
11use radix_engine::blueprints::pool::v1::events as pool_events;
12use radix_engine::object_modules::metadata::*;
13use radix_engine_interface::prelude::*;
14
15/// Given an [`EventTypeIdentifier`] and the raw event data, this function attempts to convert the
16/// event data into a structured model provided that the event is registered to a native blueprint.
17pub fn to_typed_native_event(
18    event_type_identifier: &EventTypeIdentifier,
19    event_data: &[u8],
20) -> Result<TypedNativeEvent, TypedNativeEventError> {
21    let typed_native_event_key =
22        resolve_typed_event_key_from_event_type_identifier(event_type_identifier)?;
23    to_typed_event_with_event_key(&typed_native_event_key, event_data)
24}
25
26fn resolve_typed_event_key_from_event_type_identifier(
27    event_type_identifier: &EventTypeIdentifier,
28) -> Result<TypedNativeEventKey, TypedNativeEventError> {
29    let event_name = &event_type_identifier.1;
30
31    match &event_type_identifier.0 {
32        /* Method or Function emitter on a known node module */
33        Emitter::Method(_, ModuleId::RoleAssignment) => {
34            TypedRoleAssignmentBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
35        }
36        Emitter::Method(_, ModuleId::Metadata) => {
37            TypedMetadataBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
38        }
39        Emitter::Method(_, ModuleId::Royalty) => {
40            TypedComponentRoyaltyBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
41        }
42
43        /* Functions on well-known packages */
44        Emitter::Function(blueprint_id) => match blueprint_id.package_address {
45            PACKAGE_PACKAGE => TypedPackagePackageEventKey::new(
46                &PACKAGE_PACKAGE_DEFINITION,
47                &blueprint_id.blueprint_name,
48                &event_name,
49            )
50            .map(TypedNativeEventKey::from),
51            RESOURCE_PACKAGE => TypedResourcePackageEventKey::new(
52                &RESOURCE_PACKAGE_DEFINITION,
53                &blueprint_id.blueprint_name,
54                &event_name,
55            )
56            .map(TypedNativeEventKey::from),
57            ACCOUNT_PACKAGE => TypedAccountPackageEventKey::new(
58                &ACCOUNT_PACKAGE_DEFINITION,
59                &blueprint_id.blueprint_name,
60                &event_name,
61            )
62            .map(TypedNativeEventKey::from),
63            IDENTITY_PACKAGE => TypedIdentityPackageEventKey::new(
64                &IDENTITY_PACKAGE_DEFINITION,
65                &blueprint_id.blueprint_name,
66                &event_name,
67            )
68            .map(TypedNativeEventKey::from),
69            CONSENSUS_MANAGER_PACKAGE => TypedConsensusManagerPackageEventKey::new(
70                &CONSENSUS_MANAGER_PACKAGE_DEFINITION,
71                &blueprint_id.blueprint_name,
72                &event_name,
73            )
74            .map(TypedNativeEventKey::from),
75            ACCESS_CONTROLLER_PACKAGE => TypedAccessControllerPackageEventKey::new(
76                &ACCESS_CONTROLLER_PACKAGE_DEFINITION_V1_0,
77                &blueprint_id.blueprint_name,
78                &event_name,
79            )
80            .map(TypedNativeEventKey::from),
81            POOL_PACKAGE => TypedPoolPackageEventKey::new(
82                &POOL_PACKAGE_DEFINITION_V1_0,
83                &blueprint_id.blueprint_name,
84                &event_name,
85            )
86            .map(TypedNativeEventKey::from),
87            TRANSACTION_PROCESSOR_PACKAGE => TypedTransactionProcessorPackageEventKey::new(
88                &TRANSACTION_PROCESSOR_PACKAGE_DEFINITION,
89                &blueprint_id.blueprint_name,
90                &event_name,
91            )
92            .map(TypedNativeEventKey::from),
93            METADATA_MODULE_PACKAGE => TypedMetadataPackageEventKey::new(
94                &METADATA_PACKAGE_DEFINITION,
95                &blueprint_id.blueprint_name,
96                &event_name,
97            )
98            .map(TypedNativeEventKey::from),
99            ROYALTY_MODULE_PACKAGE => TypedRoyaltyPackageEventKey::new(
100                &ROYALTY_PACKAGE_DEFINITION,
101                &blueprint_id.blueprint_name,
102                &event_name,
103            )
104            .map(TypedNativeEventKey::from),
105            ROLE_ASSIGNMENT_MODULE_PACKAGE => TypedRoleAssignmentPackageEventKey::new(
106                &ROLE_ASSIGNMENT_PACKAGE_DEFINITION,
107                &blueprint_id.blueprint_name,
108                &event_name,
109            )
110            .map(TypedNativeEventKey::from),
111            TRANSACTION_TRACKER_PACKAGE => TypedTransactionTrackerPackageEventKey::new(
112                &TRANSACTION_TRACKER_PACKAGE_DEFINITION,
113                &blueprint_id.blueprint_name,
114                &event_name,
115            )
116            .map(TypedNativeEventKey::from),
117            _ => Err(TypedNativeEventError::NotANativeBlueprint(
118                event_type_identifier.clone(),
119            )),
120        },
121
122        /* Methods on non-generic components */
123        Emitter::Method(node_id, ModuleId::Main) => match node_id.entity_type().unwrap() {
124            EntityType::GlobalPackage => {
125                TypedPackageBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
126            }
127            EntityType::GlobalConsensusManager => {
128                TypedConsensusManagerBlueprintEventKey::new(&event_name)
129                    .map(TypedNativeEventKey::from)
130            }
131            EntityType::GlobalValidator => {
132                TypedValidatorBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
133            }
134            EntityType::GlobalTransactionTracker => {
135                TypedTransactionTrackerBlueprintEventKey::new(&event_name)
136                    .map(TypedNativeEventKey::from)
137            }
138            EntityType::GlobalAccount
139            | EntityType::GlobalPreallocatedSecp256k1Account
140            | EntityType::GlobalPreallocatedEd25519Account => {
141                TypedAccountBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
142            }
143            EntityType::GlobalIdentity
144            | EntityType::GlobalPreallocatedSecp256k1Identity
145            | EntityType::GlobalPreallocatedEd25519Identity => {
146                TypedIdentityBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
147            }
148            EntityType::GlobalAccessController => {
149                TypedAccessControllerBlueprintEventKey::new(&event_name)
150                    .map(TypedNativeEventKey::from)
151            }
152            EntityType::GlobalOneResourcePool => {
153                TypedOneResourcePoolBlueprintEventKey::new(&event_name)
154                    .map(TypedNativeEventKey::from)
155            }
156            EntityType::GlobalTwoResourcePool => {
157                TypedTwoResourcePoolBlueprintEventKey::new(&event_name)
158                    .map(TypedNativeEventKey::from)
159            }
160            EntityType::GlobalMultiResourcePool => {
161                TypedMultiResourcePoolBlueprintEventKey::new(&event_name)
162                    .map(TypedNativeEventKey::from)
163            }
164            EntityType::GlobalAccountLocker => {
165                TypedAccountLockerBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
166            }
167            EntityType::GlobalFungibleResourceManager => {
168                TypedFungibleResourceManagerBlueprintEventKey::new(&event_name)
169                    .map(TypedNativeEventKey::from)
170            }
171            EntityType::GlobalNonFungibleResourceManager => {
172                TypedNonFungibleResourceManagerBlueprintEventKey::new(&event_name)
173                    .map(TypedNativeEventKey::from)
174            }
175            EntityType::InternalFungibleVault => {
176                TypedFungibleVaultBlueprintEventKey::new(&event_name).map(TypedNativeEventKey::from)
177            }
178            EntityType::InternalNonFungibleVault => {
179                TypedNonFungibleVaultBlueprintEventKey::new(&event_name)
180                    .map(TypedNativeEventKey::from)
181            }
182            EntityType::GlobalGenericComponent
183            | EntityType::InternalGenericComponent
184            | EntityType::InternalKeyValueStore => Err(TypedNativeEventError::NotANativeBlueprint(
185                event_type_identifier.clone(),
186            )),
187        },
188    }
189}
190
191define_structure! {
192    /* Native Packages */
193    AccessController => {
194        AccessController => [
195            // Original Events
196            InitiateRecoveryEvent,
197            InitiateBadgeWithdrawAttemptEvent,
198            RuleSetUpdateEvent,
199            BadgeWithdrawEvent,
200            CancelRecoveryProposalEvent,
201            CancelBadgeWithdrawAttemptEvent,
202            LockPrimaryRoleEvent,
203            UnlockPrimaryRoleEvent,
204            StopTimedRecoveryEvent,
205            // Bottlenose Events
206            DepositRecoveryXrdEvent,
207            WithdrawRecoveryXrdEvent,
208        ],
209    },
210    Account => {
211        Account => [
212            AccountWithdrawEvent,
213            AccountDepositEvent,
214            AccountRejectedDepositEvent,
215            AccountSetResourcePreferenceEvent,
216            AccountRemoveResourcePreferenceEvent,
217            AccountSetDefaultDepositRuleEvent,
218            AccountAddAuthorizedDepositorEvent,
219            AccountRemoveAuthorizedDepositorEvent
220        ]
221    },
222    Identity => {
223        Identity => []
224    },
225    Package => {
226        Package => []
227    },
228    ConsensusManager => {
229        ConsensusManager => [
230            RoundChangeEvent,
231            EpochChangeEvent
232        ],
233        Validator => [
234            RegisterValidatorEvent,
235            UnregisterValidatorEvent,
236            StakeEvent,
237            UnstakeEvent,
238            ClaimXrdEvent,
239            UpdateAcceptingStakeDelegationStateEvent,
240            ProtocolUpdateReadinessSignalEvent,
241            ValidatorEmissionAppliedEvent,
242            ValidatorRewardAppliedEvent,
243        ],
244    },
245    Pool => {
246        OneResourcePool => [
247            OneResourcePoolContributionEvent,
248            OneResourcePoolRedemptionEvent,
249            OneResourcePoolWithdrawEvent,
250            OneResourcePoolDepositEvent,
251        ],
252        TwoResourcePool => [
253            TwoResourcePoolContributionEvent,
254            TwoResourcePoolRedemptionEvent,
255            TwoResourcePoolWithdrawEvent,
256            TwoResourcePoolDepositEvent,
257        ],
258        MultiResourcePool => [
259            MultiResourcePoolContributionEvent,
260            MultiResourcePoolRedemptionEvent,
261            MultiResourcePoolWithdrawEvent,
262            MultiResourcePoolDepositEvent,
263        ],
264    },
265    Resource => {
266        FungibleVault => [
267            FungibleVaultLockFeeEvent,
268            FungibleVaultPayFeeEvent,
269            FungibleVaultWithdrawEvent,
270            FungibleVaultDepositEvent,
271            FungibleVaultRecallEvent
272        ],
273        NonFungibleVault => [
274            NonFungibleVaultWithdrawEvent,
275            NonFungibleVaultDepositEvent,
276            NonFungibleVaultRecallEvent
277        ],
278        FungibleResourceManager => [
279            VaultCreationEvent,
280            MintFungibleResourceEvent,
281            BurnFungibleResourceEvent,
282        ],
283        NonFungibleResourceManager => [
284            VaultCreationEvent,
285            MintNonFungibleResourceEvent,
286            BurnNonFungibleResourceEvent,
287        ]
288    },
289    TransactionProcessor => {
290        TransactionProcessor => []
291    },
292    TransactionTracker => {
293        TransactionTracker => []
294    },
295    Locker => {
296        AccountLocker => [
297            StoreEvent,
298            RecoverEvent,
299            ClaimEvent
300        ]
301    },
302
303    /* Node Module Packages */
304    RoleAssignment => {
305        RoleAssignment => [
306            SetRoleEvent,
307            SetOwnerRoleEvent,
308            LockOwnerRoleEvent,
309        ]
310    },
311    Metadata => {
312        Metadata => [
313            SetMetadataEvent,
314            RemoveMetadataEvent,
315        ]
316    },
317    Royalty => {
318        ComponentRoyalty => []
319    },
320}
321
322// Type aliases for events with the same name in order not to cause use collision issues.
323type OneResourcePoolContributionEvent = pool_events::one_resource_pool::ContributionEvent;
324type OneResourcePoolRedemptionEvent = pool_events::one_resource_pool::RedemptionEvent;
325type OneResourcePoolWithdrawEvent = pool_events::one_resource_pool::WithdrawEvent;
326type OneResourcePoolDepositEvent = pool_events::one_resource_pool::DepositEvent;
327
328type TwoResourcePoolContributionEvent = pool_events::two_resource_pool::ContributionEvent;
329type TwoResourcePoolRedemptionEvent = pool_events::two_resource_pool::RedemptionEvent;
330type TwoResourcePoolWithdrawEvent = pool_events::two_resource_pool::WithdrawEvent;
331type TwoResourcePoolDepositEvent = pool_events::two_resource_pool::DepositEvent;
332
333type MultiResourcePoolContributionEvent = pool_events::multi_resource_pool::ContributionEvent;
334type MultiResourcePoolRedemptionEvent = pool_events::multi_resource_pool::RedemptionEvent;
335type MultiResourcePoolWithdrawEvent = pool_events::multi_resource_pool::WithdrawEvent;
336type MultiResourcePoolDepositEvent = pool_events::multi_resource_pool::DepositEvent;
337
338type FungibleVaultLockFeeEvent = fungible_vault::LockFeeEvent;
339type FungibleVaultPayFeeEvent = fungible_vault::PayFeeEvent;
340type FungibleVaultWithdrawEvent = fungible_vault::WithdrawEvent;
341type FungibleVaultDepositEvent = fungible_vault::DepositEvent;
342type FungibleVaultRecallEvent = fungible_vault::RecallEvent;
343
344type NonFungibleVaultWithdrawEvent = non_fungible_vault::WithdrawEvent;
345type NonFungibleVaultDepositEvent = non_fungible_vault::DepositEvent;
346type NonFungibleVaultRecallEvent = non_fungible_vault::RecallEvent;
347
348type AccountWithdrawEvent = account::WithdrawEvent;
349type AccountDepositEvent = account::DepositEvent;
350type AccountRejectedDepositEvent = account::RejectedDepositEvent;
351type AccountSetResourcePreferenceEvent = account::SetResourcePreferenceEvent;
352type AccountRemoveResourcePreferenceEvent = account::RemoveResourcePreferenceEvent;
353type AccountSetDefaultDepositRuleEvent = account::SetDefaultDepositRuleEvent;
354type AccountAddAuthorizedDepositorEvent = account::AddAuthorizedDepositorEvent;
355type AccountRemoveAuthorizedDepositorEvent = account::RemoveAuthorizedDepositorEvent;
356
357/// This enum uses some special syntax to define the structure of events. This makes the code for
358/// model definitions very compact, allows for very easy addition of more packages, blueprints or
359/// events in the future, keeps various models all in sync, and implements various functions and
360/// methods on appropriate types.
361///
362/// The syntax allowed for by this macro looks like the following:
363/// ```ignore
364/// define_structure! {
365///     package_name1 => {
366///         blueprint_name1 => [
367///             Event1,
368///             Event2,
369///             Event3,
370///         ],
371///         blueprint_name2 => [
372///             Event1,
373///         ]
374///     },
375///     package_name2 => {
376///         blueprint_name1 => [
377///             Event1,
378///         ],
379///         blueprint_name2 => [
380///             Event1,
381///             Event2,
382///         ]
383///     }
384/// }
385/// ```
386macro_rules! define_structure {
387    (
388        $(
389            $package_ident: ident => {
390                $(
391                    $blueprint_ident: ident => [
392                        $($event_ty: ty),* $(,)?
393                    ]
394                ),* $(,)?
395            }
396        ),* $(,)?
397    ) => {
398        paste::paste! {
399            // Defining the top-level type which will be of all of the packages and their blueprints.
400            #[derive(Debug)]
401            pub enum TypedNativeEvent {
402                $(
403                    $package_ident([< Typed $package_ident PackageEvent >]),
404                )*
405            }
406
407            // Define a type for the package - this should be an enum of all of the blueprints that
408            // the package has.
409            $(
410                #[derive(Debug)]
411                pub enum [< Typed $package_ident PackageEvent >] {
412                    $(
413                        $blueprint_ident([< Typed $blueprint_ident BlueprintEvent >]),
414                    )*
415                }
416
417                $(
418                    #[derive(Debug)]
419                    pub enum [< Typed $blueprint_ident BlueprintEvent >] {
420                        $(
421                            $event_ty ($event_ty),
422                        )*
423                    }
424                )*
425            )*
426
427            // Defining the event key types which are the same as above but do not have any event
428            // data inside of them.
429            pub enum TypedNativeEventKey {
430                $(
431                    $package_ident([< Typed $package_ident PackageEventKey >]),
432                )*
433            }
434
435            $(
436                pub enum [< Typed $package_ident PackageEventKey >] {
437                    $(
438                        $blueprint_ident([< Typed $blueprint_ident BlueprintEventKey >]),
439                    )*
440                }
441
442                $(
443                    #[derive(radix_common::prelude::ScryptoSbor)]
444                    pub enum [< Typed $blueprint_ident BlueprintEventKey >] {
445                        $(
446                            $event_ty,
447                        )*
448                    }
449
450                    impl sbor::prelude::FromStr for [< Typed $blueprint_ident BlueprintEventKey >] {
451                        type Err = TypedNativeEventError;
452
453                        fn from_str(s: &str) -> Result<Self, Self::Err> {
454                            match s {
455                                $(
456                                    _ if <$event_ty as radix_common::traits::ScryptoEvent>::EVENT_NAME == s => Ok(Self::$event_ty),
457                                )*
458                                _ => Err(Self::Err::BlueprintEventKeyParseError {
459                                    blueprint_event_key: stringify!([< Typed $blueprint_ident BlueprintEventKey >]).to_string(),
460                                    event_name: s.to_string()
461                                })
462                            }
463                        }
464                    }
465                )*
466            )*
467
468            $(
469                $(
470                    impl From<[< Typed $blueprint_ident BlueprintEventKey >]> for TypedNativeEventKey {
471                        fn from(value: [< Typed $blueprint_ident BlueprintEventKey >]) -> Self {
472                            Self::$package_ident(
473                                [< Typed $package_ident PackageEventKey >]::$blueprint_ident(value)
474                            )
475                        }
476                    }
477
478                    impl [< Typed $blueprint_ident BlueprintEventKey >] {
479                        pub fn new(
480                            name: &String,
481                        ) -> Result<Self, TypedNativeEventError> {
482                            Self::from_str(name)
483                        }
484
485                        #[allow(unused_mut)]
486                        pub fn registered_events() -> sbor::prelude::HashSet<String> {
487                            let mut set = sbor::prelude::HashSet::default();
488                            $(
489                                set.insert(<$event_ty as radix_common::traits::ScryptoEvent>::EVENT_NAME.to_owned());
490                            )*
491                            set
492                        }
493                    }
494                )*
495            )*
496
497            $(
498                impl From<[< Typed $package_ident PackageEventKey >]> for TypedNativeEventKey {
499                    fn from(value: [< Typed $package_ident PackageEventKey >]) -> Self {
500                        Self::$package_ident(value)
501                    }
502                }
503
504                impl [< Typed $package_ident PackageEventKey >] {
505                    pub fn new(
506                        package_definition: &PackageDefinition,
507                        blueprint_ident: &str,
508                        event_name: &String,
509                    ) -> Result<Self, TypedNativeEventError> {
510                        match blueprint_ident {
511                            $(
512                                stringify!($blueprint_ident) => Ok(Self::$blueprint_ident([< Typed $blueprint_ident BlueprintEventKey >]::new(
513                                    event_name)?
514                                )),
515                            )*
516                            _ => Err(TypedNativeEventError::BlueprintNotFound {
517                                package_definition: package_definition.clone(),
518                                blueprint_name: blueprint_ident.to_owned(),
519                            })
520                        }
521                    }
522
523                    pub fn registered_events() -> sbor::prelude::HashMap<String, sbor::prelude::HashSet<String>> {
524                        let mut map = sbor::prelude::HashMap::<String, sbor::prelude::HashSet<String>>::default();
525                        $(
526                            map.insert(
527                                stringify!($blueprint_ident).to_owned(),
528                                [< Typed $blueprint_ident BlueprintEventKey >]::registered_events()
529                            );
530                        )*
531                        map
532                    }
533                }
534            )*
535
536            impl TypedNativeEvent {
537                pub fn registered_events() -> sbor::prelude::HashMap<String, sbor::prelude::HashMap<String, sbor::prelude::HashSet<String>>> {
538                    let mut map = sbor::prelude::HashMap::<String, sbor::prelude::HashMap<String, sbor::prelude::HashSet<String>>>::default();
539                    $(
540                        map.insert(stringify!($package_ident).to_owned(), [< Typed $package_ident PackageEventKey >]::registered_events());
541                    )*
542                    map
543                }
544            }
545
546            // The implementation of a function that converts any `TypedNativeEventKey` + raw SBOR
547            // bytes to the appropriate typed event type.
548            fn to_typed_event_with_event_key(
549                event_key: &TypedNativeEventKey,
550                data: &[u8]
551            ) -> Result<TypedNativeEvent, TypedNativeEventError> {
552                match event_key {
553                    $(
554                        $(
555                            $(
556                                TypedNativeEventKey::$package_ident(
557                                    [< Typed $package_ident PackageEventKey >]::$blueprint_ident(
558                                        [< Typed $blueprint_ident BlueprintEventKey >]::$event_ty
559                                    )
560                                ) => Ok(TypedNativeEvent::$package_ident(
561                                    [< Typed $package_ident PackageEvent >]::$blueprint_ident(
562                                        [< Typed $blueprint_ident BlueprintEvent >]::$event_ty(
563                                            radix_common::prelude::scrypto_decode(data)?
564                                        )
565                                    )
566                                )),
567                            )*
568                        )*
569                    )*
570
571                    // The following panic needs to be included to allow blueprints with no events
572                    // to work with no issues. It's impossible for us to get to this point here!
573                    _ => panic!("Illegal State! Matching over enum was not exhaustive.")
574                }
575            }
576        }
577    };
578}
579use define_structure;
580
581#[derive(Debug)]
582pub enum TypedNativeEventError {
583    BlueprintEventKeyParseError {
584        blueprint_event_key: String,
585        event_name: String,
586    },
587    BlueprintNotFound {
588        package_definition: PackageDefinition,
589        blueprint_name: String,
590    },
591    TypeHasNoName {
592        package_definition: PackageDefinition,
593        blueprint_name: String,
594        local_type_id: LocalTypeId,
595    },
596    NotANativeBlueprint(EventTypeIdentifier),
597    DecodeError(DecodeError),
598    GenericTypePointer,
599}
600
601impl From<DecodeError> for TypedNativeEventError {
602    fn from(value: DecodeError) -> Self {
603        Self::DecodeError(value)
604    }
605}