radix_engine/object_modules/role_assignment/
package.rs

1use crate::blueprints::models::*;
2use crate::blueprints::package::PackageAuthNativeBlueprint;
3use crate::blueprints::util::*;
4use crate::internal_prelude::*;
5use crate::kernel::kernel_api::KernelSubstateApi;
6use crate::object_modules::role_assignment::{LockOwnerRoleEvent, SetOwnerRoleEvent};
7use crate::system::system::SystemService;
8use crate::system::system_callback::*;
9use crate::system::system_modules::auth::{AuthError, ResolvedPermission};
10use crate::system::system_substates::FieldSubstate;
11use crate::{errors::*, event_schema};
12use radix_blueprint_schema_init::*;
13use radix_engine_interface::api::field_api::LockFlags;
14use radix_engine_interface::api::*;
15use radix_engine_interface::blueprints::package::*;
16use radix_engine_interface::blueprints::resource::*;
17use radix_engine_interface::object_modules::role_assignment::*;
18use radix_engine_interface::types::*;
19use radix_native_sdk::runtime::Runtime;
20
21use super::*;
22
23#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
24pub enum RoleAssignmentError {
25    UsedReservedRole(String),
26    UsedReservedSpace,
27    ExceededMaxRoleNameLen { limit: usize, actual: usize },
28    ExceededMaxAccessRuleDepth,
29    ExceededMaxAccessRuleNodes,
30    InvalidName(InvalidNameError),
31    ExceededMaxRoles,
32    CannotSetRoleIfNotAttached,
33}
34
35pub struct RoleAssignmentNativePackage;
36
37impl RoleAssignmentNativePackage {
38    pub fn definition() -> PackageDefinition {
39        let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
40
41        let state = RoleAssignmentStateSchemaInit::create_schema_init(&mut aggregator);
42
43        let mut functions = index_map_new();
44        functions.insert(
45            ROLE_ASSIGNMENT_CREATE_IDENT.to_string(),
46            FunctionSchemaInit {
47                receiver: None,
48                input: TypeRef::Static(
49                    aggregator.add_child_type_and_descendents::<RoleAssignmentCreateInput>(),
50                ),
51                output: TypeRef::Static(
52                    aggregator.add_child_type_and_descendents::<RoleAssignmentCreateOutput>(),
53                ),
54                export: ROLE_ASSIGNMENT_CREATE_IDENT.to_string(),
55            },
56        );
57        functions.insert(
58            ROLE_ASSIGNMENT_SET_OWNER_IDENT.to_string(),
59            FunctionSchemaInit {
60                receiver: Some(ReceiverInfo::normal_ref_mut()),
61                input: TypeRef::Static(
62                    aggregator.add_child_type_and_descendents::<RoleAssignmentSetOwnerInput>(),
63                ),
64                output: TypeRef::Static(
65                    aggregator.add_child_type_and_descendents::<RoleAssignmentSetOwnerOutput>(),
66                ),
67                export: ROLE_ASSIGNMENT_SET_OWNER_IDENT.to_string(),
68            },
69        );
70        functions.insert(
71            ROLE_ASSIGNMENT_LOCK_OWNER_IDENT.to_string(),
72            FunctionSchemaInit {
73                receiver: Some(ReceiverInfo::normal_ref_mut()),
74                input: TypeRef::Static(
75                    aggregator.add_child_type_and_descendents::<RoleAssignmentLockOwnerInput>(),
76                ),
77                output: TypeRef::Static(
78                    aggregator.add_child_type_and_descendents::<RoleAssignmentLockOwnerOutput>(),
79                ),
80                export: ROLE_ASSIGNMENT_LOCK_OWNER_IDENT.to_string(),
81            },
82        );
83        functions.insert(
84            ROLE_ASSIGNMENT_SET_IDENT.to_string(),
85            FunctionSchemaInit {
86                receiver: Some(ReceiverInfo::normal_ref_mut()),
87                input: TypeRef::Static(
88                    aggregator.add_child_type_and_descendents::<RoleAssignmentSetInput>(),
89                ),
90                output: TypeRef::Static(
91                    aggregator.add_child_type_and_descendents::<RoleAssignmentSetOutput>(),
92                ),
93                export: ROLE_ASSIGNMENT_SET_IDENT.to_string(),
94            },
95        );
96        functions.insert(
97            ROLE_ASSIGNMENT_GET_IDENT.to_string(),
98            FunctionSchemaInit {
99                receiver: Some(ReceiverInfo::normal_ref_mut()),
100                input: TypeRef::Static(
101                    aggregator.add_child_type_and_descendents::<RoleAssignmentGetInput>(),
102                ),
103                output: TypeRef::Static(
104                    aggregator.add_child_type_and_descendents::<RoleAssignmentGetOutput>(),
105                ),
106                export: ROLE_ASSIGNMENT_GET_IDENT.to_string(),
107            },
108        );
109
110        let events = event_schema! {
111            aggregator,
112            [
113                SetOwnerRoleEvent,
114                SetRoleEvent,
115                LockOwnerRoleEvent
116            ]
117        };
118
119        let schema = generate_full_schema(aggregator);
120        let blueprints = indexmap!(
121            ROLE_ASSIGNMENT_BLUEPRINT.to_string() => BlueprintDefinitionInit {
122                blueprint_type: BlueprintType::default(),
123                is_transient: true,
124                feature_set: indexset!(),
125                dependencies: indexset!(),
126
127                schema: BlueprintSchemaInit {
128                    generics: vec![],
129                    schema,
130                    state,
131                    events,
132                    types: BlueprintTypeSchemaInit::default(),
133                    functions: BlueprintFunctionsSchemaInit {
134                        functions,
135                    },
136                    hooks: BlueprintHooksInit::default(),
137                },
138
139                royalty_config: PackageRoyaltyConfig::default(),
140                auth_config: AuthConfig {
141                    function_auth: FunctionAuth::AllowAll,
142                    method_auth: MethodAuthTemplate::AllowAll, // Mocked
143                },
144            }
145        );
146
147        PackageDefinition { blueprints }
148    }
149
150    pub fn authorization<Y: SystemBasedKernelApi>(
151        global_address: &GlobalAddress,
152        ident: &str,
153        input: &IndexedScryptoValue,
154        api: &mut SystemService<Y>,
155    ) -> Result<ResolvedPermission, RuntimeError> {
156        let permission = match ident {
157            ROLE_ASSIGNMENT_SET_IDENT => {
158                let input: RoleAssignmentSetInput = input.as_typed().map_err(|e| {
159                    RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
160                })?;
161                let role_list = Self::resolve_update_role_method_permission(
162                    global_address.as_node_id(),
163                    input.module,
164                    &input.role_key,
165                    api,
166                )?;
167                ResolvedPermission::RoleList {
168                    role_assignment_of: global_address.clone(),
169                    role_list,
170                    module_id: input.module,
171                }
172            }
173            ROLE_ASSIGNMENT_SET_OWNER_IDENT => {
174                Self::resolve_update_owner_role_method_permission(global_address.as_node_id(), api)?
175            }
176            ROLE_ASSIGNMENT_LOCK_OWNER_IDENT => {
177                Self::resolve_update_owner_role_method_permission(global_address.as_node_id(), api)?
178            }
179            ROLE_ASSIGNMENT_GET_IDENT | ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT => {
180                ResolvedPermission::AllowAll
181            }
182            _ => {
183                return Err(RuntimeError::SystemModuleError(
184                    SystemModuleError::AuthError(AuthError::NoMethodMapping(FnIdentifier {
185                        blueprint_id: BlueprintId::new(
186                            &ROLE_ASSIGNMENT_MODULE_PACKAGE,
187                            ROLE_ASSIGNMENT_BLUEPRINT,
188                        ),
189                        ident: ident.to_string(),
190                    })),
191                ));
192            }
193        };
194
195        Ok(permission)
196    }
197
198    pub fn invoke_export<Y: SystemApi<RuntimeError>>(
199        export_name: &str,
200        input: &IndexedScryptoValue,
201        api: &mut Y,
202    ) -> Result<IndexedScryptoValue, RuntimeError> {
203        match export_name {
204            ROLE_ASSIGNMENT_CREATE_IDENT => {
205                let input: RoleAssignmentCreateInput = input.as_typed().map_err(|e| {
206                    RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
207                })?;
208
209                let rtn = Self::create(input.owner_role, input.roles, api)?;
210                Ok(IndexedScryptoValue::from_typed(&rtn))
211            }
212            ROLE_ASSIGNMENT_SET_OWNER_IDENT => {
213                let input: RoleAssignmentSetOwnerInput = input.as_typed().map_err(|e| {
214                    RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
215                })?;
216
217                let rtn = Self::set_owner_role(input.rule, api)?;
218                Ok(IndexedScryptoValue::from_typed(&rtn))
219            }
220            ROLE_ASSIGNMENT_LOCK_OWNER_IDENT => {
221                let _input: RoleAssignmentLockOwnerInput = input.as_typed().map_err(|e| {
222                    RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
223                })?;
224
225                let rtn = Self::lock_owner_role(api)?;
226                Ok(IndexedScryptoValue::from_typed(&rtn))
227            }
228            ROLE_ASSIGNMENT_SET_IDENT => {
229                let input: RoleAssignmentSetInput = input.as_typed().map_err(|e| {
230                    RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
231                })?;
232
233                let rtn = Self::set_role(input.module, input.role_key, input.rule, api)?;
234                Ok(IndexedScryptoValue::from_typed(&rtn))
235            }
236            ROLE_ASSIGNMENT_GET_IDENT => {
237                let input: RoleAssignmentGetInput = input.as_typed().map_err(|e| {
238                    RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
239                })?;
240
241                let rtn = Self::get_role(input.module, input.role_key, api)?;
242                Ok(IndexedScryptoValue::from_typed(&rtn))
243            }
244            _ => Err(RuntimeError::ApplicationError(
245                ApplicationError::ExportDoesNotExist(export_name.to_string()),
246            )),
247        }
248    }
249
250    /// Checks if a role key is a reserved.
251    ///
252    /// The system has reserved all role keys starting with `_`.
253    pub fn is_role_key_reserved(role_key: &RoleKey) -> bool {
254        return role_key.key.starts_with("_");
255    }
256
257    /// Checks if a role key is a reserved and has been defined.
258    ///
259    /// Currently there are only two such roles, i.e. `OWNER_ROLE` and `SELF_ROLE`, which can be referenced in role list.
260    pub fn is_role_key_reserved_and_defined(role_key: &RoleKey) -> bool {
261        Self::is_role_key_reserved(role_key)
262            && (role_key.key.eq(OWNER_ROLE) || role_key.key.eq(SELF_ROLE))
263    }
264
265    pub fn verify_access_rule(access_rule: &AccessRule) -> Result<(), RoleAssignmentError> {
266        pub struct AccessRuleVerifier(usize);
267        impl AccessRuleVisitor for AccessRuleVerifier {
268            type Error = RoleAssignmentError;
269            fn visit(
270                &mut self,
271                _node: &CompositeRequirement,
272                depth: usize,
273            ) -> Result<(), Self::Error> {
274                // This is to protect unbounded native stack usage during authorization
275                if depth > MAX_ACCESS_RULE_DEPTH {
276                    return Err(RoleAssignmentError::ExceededMaxAccessRuleDepth);
277                }
278
279                self.0 += 1;
280
281                if self.0 > MAX_COMPOSITE_REQUIREMENTS {
282                    return Err(RoleAssignmentError::ExceededMaxAccessRuleNodes);
283                }
284
285                Ok(())
286            }
287        }
288
289        access_rule.dfs_traverse_nodes(&mut AccessRuleVerifier(0))
290    }
291
292    fn resolve_update_owner_role_method_permission<Y: SystemBasedKernelApi>(
293        receiver: &NodeId,
294        api: &mut SystemService<Y>,
295    ) -> Result<ResolvedPermission, RuntimeError> {
296        let handle = api.kernel_open_substate(
297            receiver,
298            ROLE_ASSIGNMENT_BASE_PARTITION
299                .at_offset(ROLE_ASSIGNMENT_FIELDS_PARTITION_OFFSET)
300                .unwrap(),
301            &SubstateKey::Field(0u8),
302            LockFlags::read_only(),
303            SystemLockData::default(),
304        )?;
305
306        let owner_role_substate: FieldSubstate<RoleAssignmentOwnerFieldPayload> =
307            api.kernel_read_substate(handle)?.as_typed().unwrap();
308        api.kernel_close_substate(handle)?;
309
310        let owner_role = owner_role_substate
311            .into_payload()
312            .fully_update_and_into_latest_version();
313
314        let rule = match owner_role.owner_role_entry.updater {
315            OwnerRoleUpdater::None => AccessRule::DenyAll,
316            OwnerRoleUpdater::Owner => owner_role.owner_role_entry.rule,
317            OwnerRoleUpdater::Object => rule!(require(global_caller(GlobalAddress::new_or_panic(
318                receiver.0
319            )))),
320        };
321
322        Ok(ResolvedPermission::AccessRule(rule))
323    }
324
325    fn resolve_update_role_method_permission<Y: SystemBasedKernelApi>(
326        receiver: &NodeId,
327        module: ModuleId,
328        role_key: &RoleKey,
329        service: &mut SystemService<Y>,
330    ) -> Result<RoleList, RuntimeError> {
331        if Self::is_role_key_reserved(&role_key) || module.eq(&ModuleId::RoleAssignment) {
332            return Ok(RoleList::none());
333        }
334
335        let blueprint_id = service
336            .get_blueprint_info(receiver, module.into())?
337            .blueprint_id;
338
339        let auth_template = PackageAuthNativeBlueprint::get_bp_auth_template(
340            blueprint_id.package_address.as_node_id(),
341            &BlueprintVersionKey::new_default(blueprint_id.blueprint_name.as_str()),
342            service.api(),
343        )?
344        .method_auth;
345
346        match auth_template {
347            MethodAuthTemplate::AllowAll => Ok(RoleList::none()),
348            MethodAuthTemplate::StaticRoleDefinition(roles) => match roles.roles {
349                RoleSpecification::Normal(roles) => match roles.get(role_key) {
350                    Some(role_list) => Ok(role_list.clone()),
351                    None => Ok(RoleList::none()),
352                },
353                RoleSpecification::UseOuter => Ok(RoleList::none()),
354            },
355        }
356    }
357
358    pub fn init_system_struct(
359        owner_role: OwnerRoleEntry,
360        roles: IndexMap<ModuleId, RoleAssignmentInit>,
361    ) -> Result<
362        (
363            IndexMap<u8, FieldValue>,
364            IndexMap<u8, IndexMap<Vec<u8>, KVEntry>>,
365        ),
366        RoleAssignmentError,
367    > {
368        if roles.contains_key(&ModuleId::RoleAssignment) {
369            return Err(RoleAssignmentError::UsedReservedSpace);
370        }
371
372        Self::verify_access_rule(&owner_role.rule)?;
373
374        let owner_role_substate = OwnerRoleSubstate {
375            owner_role_entry: owner_role.clone(),
376        };
377
378        let owner_role_field = match owner_role.updater {
379            OwnerRoleUpdater::None => FieldValue::immutable(
380                &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role_substate),
381            ),
382            OwnerRoleUpdater::Owner | OwnerRoleUpdater::Object => FieldValue::new(
383                &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role_substate),
384            ),
385        };
386
387        let mut role_entries = index_map_new();
388
389        for (module, roles) in roles {
390            if roles.data.len() > MAX_ROLES {
391                return Err(RoleAssignmentError::ExceededMaxRoles);
392            }
393
394            for (role_key, role_def) in roles.data {
395                if Self::is_role_key_reserved(&role_key) {
396                    return Err(RoleAssignmentError::UsedReservedRole(
397                        role_key.key.to_string(),
398                    ));
399                }
400                check_name(&role_key.key).map_err(RoleAssignmentError::InvalidName)?;
401
402                if role_key.key.len() > MAX_ROLE_NAME_LEN {
403                    return Err(RoleAssignmentError::ExceededMaxRoleNameLen {
404                        limit: MAX_ROLE_NAME_LEN,
405                        actual: role_key.key.len(),
406                    });
407                }
408
409                let module_role_key = ModuleRoleKey::new(module, role_key);
410
411                if let Some(access_rule) = &role_def {
412                    Self::verify_access_rule(access_rule)?;
413                }
414
415                let value = role_def.map(|rule| {
416                    scrypto_encode(&RoleAssignmentAccessRuleEntryPayload::from_content_source(
417                        rule,
418                    ))
419                    .unwrap()
420                });
421
422                let kv_entry = KVEntry {
423                    value,
424                    locked: false,
425                };
426
427                role_entries.insert(scrypto_encode(&module_role_key).unwrap(), kv_entry);
428            }
429        }
430
431        Ok((
432            indexmap!(RoleAssignmentField::Owner.field_index() => owner_role_field),
433            indexmap!(RoleAssignmentCollection::AccessRuleKeyValue.collection_index() => role_entries),
434        ))
435    }
436
437    pub(crate) fn create<Y: SystemApi<RuntimeError>>(
438        owner_role: OwnerRoleEntry,
439        roles: IndexMap<ModuleId, RoleAssignmentInit>,
440        api: &mut Y,
441    ) -> Result<Own, RuntimeError> {
442        let (fields, kv_entries) = Self::init_system_struct(owner_role, roles).map_err(|e| {
443            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
444        })?;
445
446        let component_id = api.new_object(
447            ROLE_ASSIGNMENT_BLUEPRINT,
448            vec![],
449            GenericArgs::default(),
450            fields,
451            kv_entries,
452        )?;
453
454        Ok(Own(component_id))
455    }
456
457    fn set_owner_role<Y: SystemApi<RuntimeError>>(
458        rule: AccessRule,
459        api: &mut Y,
460    ) -> Result<(), RuntimeError> {
461        Self::verify_access_rule(&rule).map_err(|e| {
462            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
463        })?;
464
465        let handle = api.actor_open_field(ACTOR_STATE_SELF, 0u8, LockFlags::MUTABLE)?;
466
467        let mut owner_role = api
468            .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
469            .fully_update_and_into_latest_version();
470        owner_role.owner_role_entry.rule = rule.clone();
471        api.field_write_typed(
472            handle,
473            &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role),
474        )?;
475        api.field_close(handle)?;
476
477        Runtime::emit_event(api, SetOwnerRoleEvent { rule })?;
478
479        Ok(())
480    }
481
482    fn lock_owner_role<Y: SystemApi<RuntimeError>>(api: &mut Y) -> Result<(), RuntimeError> {
483        let handle = api.actor_open_field(ACTOR_STATE_SELF, 0u8, LockFlags::MUTABLE)?;
484        let mut owner_role = api
485            .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
486            .fully_update_and_into_latest_version();
487        owner_role.owner_role_entry.updater = OwnerRoleUpdater::None;
488        api.field_write_typed(
489            handle,
490            &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role),
491        )?;
492        api.field_lock(handle)?;
493        api.field_close(handle)?;
494
495        Runtime::emit_event(api, LockOwnerRoleEvent {})?;
496
497        Ok(())
498    }
499
500    fn set_role<Y: SystemApi<RuntimeError>>(
501        module: ModuleId,
502        role_key: RoleKey,
503        rule: AccessRule,
504        api: &mut Y,
505    ) -> Result<(), RuntimeError> {
506        if module.eq(&ModuleId::RoleAssignment) {
507            return Err(RuntimeError::ApplicationError(
508                ApplicationError::RoleAssignmentError(RoleAssignmentError::UsedReservedSpace),
509            ));
510        }
511        if Self::is_role_key_reserved(&role_key) {
512            return Err(RuntimeError::ApplicationError(
513                ApplicationError::RoleAssignmentError(RoleAssignmentError::UsedReservedRole(
514                    role_key.key.to_string(),
515                )),
516            ));
517        }
518        if role_key.key.len() > MAX_ROLE_NAME_LEN {
519            return Err(RuntimeError::ApplicationError(
520                ApplicationError::RoleAssignmentError(
521                    RoleAssignmentError::ExceededMaxRoleNameLen {
522                        limit: MAX_ROLE_NAME_LEN,
523                        actual: role_key.key.len(),
524                    },
525                ),
526            ));
527        }
528        check_name(&role_key.key).map_err(|error| {
529            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(
530                RoleAssignmentError::InvalidName(error),
531            ))
532        })?;
533
534        let module_role_key = ModuleRoleKey::new(module, role_key.clone());
535
536        Self::verify_access_rule(&rule).map_err(|e| {
537            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
538        })?;
539
540        // Only allow this method to be called on attached role assignment modules.
541        // This is currently implemented to prevent unbounded number of roles from
542        // being created.
543        api.actor_get_node_id(ACTOR_REF_GLOBAL)
544            .map_err(|e| match e {
545                RuntimeError::SystemError(SystemError::GlobalAddressDoesNotExist) => {
546                    RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(
547                        RoleAssignmentError::CannotSetRoleIfNotAttached,
548                    ))
549                }
550                _ => e,
551            })?;
552
553        let handle = api.actor_open_key_value_entry(
554            ACTOR_STATE_SELF,
555            RoleAssignmentCollection::AccessRuleKeyValue.collection_index(),
556            &scrypto_encode(&module_role_key).unwrap(),
557            LockFlags::MUTABLE,
558        )?;
559
560        // Overwrite whatever access rule (or empty) is there
561        api.key_value_entry_set_typed(
562            handle,
563            RoleAssignmentAccessRuleEntryPayload::from_content_source(rule.clone()),
564        )?;
565        api.key_value_entry_close(handle)?;
566
567        Runtime::emit_event(api, SetRoleEvent { role_key, rule })?;
568
569        Ok(())
570    }
571
572    pub(crate) fn get_role<Y: SystemApi<RuntimeError>>(
573        module: ModuleId,
574        role_key: RoleKey,
575        api: &mut Y,
576    ) -> Result<Option<AccessRule>, RuntimeError> {
577        let module_role_key = ModuleRoleKey::new(module, role_key);
578
579        let handle = api.actor_open_key_value_entry(
580            ACTOR_STATE_SELF,
581            RoleAssignmentCollection::AccessRuleKeyValue.collection_index(),
582            &scrypto_encode(&module_role_key).unwrap(),
583            LockFlags::read_only(),
584        )?;
585
586        let rule = api.key_value_entry_get_typed::<RoleAssignmentAccessRuleEntryPayload>(handle)?;
587
588        api.key_value_entry_close(handle)?;
589
590        Ok(rule.map(|v| v.fully_update_and_into_latest_version()))
591    }
592}
593
594pub struct RoleAssignmentBottlenoseExtension;
595
596impl RoleAssignmentBottlenoseExtension {
597    pub fn added_functions_schema() -> (
598        IndexMap<String, FunctionSchemaInit>,
599        VersionedSchema<ScryptoCustomSchema>,
600    ) {
601        let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
602        let mut functions = index_map_new();
603        functions.insert(
604            ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT.to_string(),
605            FunctionSchemaInit {
606                receiver: Some(ReceiverInfo::normal_ref()),
607                input: TypeRef::Static(
608                    aggregator.add_child_type_and_descendents::<RoleAssignmentGetOwnerRoleInput>(),
609                ),
610                output: TypeRef::Static(
611                    aggregator.add_child_type_and_descendents::<RoleAssignmentGetOwnerRoleOutput>(),
612                ),
613                export: ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT.to_string(),
614            },
615        );
616        let schema = generate_full_schema(aggregator);
617        (functions, schema)
618    }
619
620    pub fn invoke_export<Y: SystemApi<RuntimeError>>(
621        export_name: &str,
622        input: &IndexedScryptoValue,
623        api: &mut Y,
624    ) -> Result<IndexedScryptoValue, RuntimeError> {
625        match export_name {
626            ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT => {
627                input
628                    .as_typed::<RoleAssignmentGetOwnerRoleInput>()
629                    .map_err(|e| {
630                        RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
631                    })?;
632
633                let rtn = Self::get_owner_role(api)?;
634                Ok(IndexedScryptoValue::from_typed(&rtn))
635            }
636            _ => Err(RuntimeError::ApplicationError(
637                ApplicationError::ExportDoesNotExist(export_name.to_string()),
638            )),
639        }
640    }
641
642    pub(crate) fn get_owner_role<Y: SystemApi<RuntimeError>>(
643        api: &mut Y,
644    ) -> Result<OwnerRoleEntry, RuntimeError> {
645        let handle = api.actor_open_field(
646            ACTOR_STATE_SELF,
647            RoleAssignmentField::Owner.field_index(),
648            LockFlags::read_only(),
649        )?;
650        let owner_role_entry = api
651            .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
652            .fully_update_and_into_latest_version()
653            .owner_role_entry;
654        api.field_close(handle)?;
655
656        Ok(owner_role_entry)
657    }
658}