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,
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        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    #[allow(clippy::type_complexity)]
359    pub fn init_system_struct(
360        owner_role: OwnerRoleEntry,
361        roles: IndexMap<ModuleId, RoleAssignmentInit>,
362    ) -> Result<
363        (
364            IndexMap<u8, FieldValue>,
365            IndexMap<u8, IndexMap<Vec<u8>, KVEntry>>,
366        ),
367        RoleAssignmentError,
368    > {
369        if roles.contains_key(&ModuleId::RoleAssignment) {
370            return Err(RoleAssignmentError::UsedReservedSpace);
371        }
372
373        Self::verify_access_rule(&owner_role.rule)?;
374
375        let owner_role_substate = OwnerRoleSubstate {
376            owner_role_entry: owner_role.clone(),
377        };
378
379        let owner_role_field = match owner_role.updater {
380            OwnerRoleUpdater::None => FieldValue::immutable(
381                RoleAssignmentOwnerFieldPayload::from_content_source(owner_role_substate),
382            ),
383            OwnerRoleUpdater::Owner | OwnerRoleUpdater::Object => FieldValue::new(
384                RoleAssignmentOwnerFieldPayload::from_content_source(owner_role_substate),
385            ),
386        };
387
388        let mut role_entries = index_map_new();
389
390        for (module, roles) in roles {
391            if roles.data.len() > MAX_ROLES {
392                return Err(RoleAssignmentError::ExceededMaxRoles);
393            }
394
395            for (role_key, role_def) in roles.data {
396                if Self::is_role_key_reserved(&role_key) {
397                    return Err(RoleAssignmentError::UsedReservedRole(
398                        role_key.key.to_string(),
399                    ));
400                }
401                check_name(&role_key.key).map_err(RoleAssignmentError::InvalidName)?;
402
403                if role_key.key.len() > MAX_ROLE_NAME_LEN {
404                    return Err(RoleAssignmentError::ExceededMaxRoleNameLen {
405                        limit: MAX_ROLE_NAME_LEN,
406                        actual: role_key.key.len(),
407                    });
408                }
409
410                let module_role_key = ModuleRoleKey::new(module, role_key);
411
412                if let Some(access_rule) = &role_def {
413                    Self::verify_access_rule(access_rule)?;
414                }
415
416                let value = role_def.map(|rule| {
417                    scrypto_encode(&RoleAssignmentAccessRuleEntryPayload::from_content_source(
418                        rule,
419                    ))
420                    .unwrap()
421                });
422
423                let kv_entry = KVEntry {
424                    value,
425                    locked: false,
426                };
427
428                role_entries.insert(scrypto_encode(&module_role_key).unwrap(), kv_entry);
429            }
430        }
431
432        Ok((
433            indexmap!(RoleAssignmentField::Owner.field_index() => owner_role_field),
434            indexmap!(RoleAssignmentCollection::AccessRuleKeyValue.collection_index() => role_entries),
435        ))
436    }
437
438    pub(crate) fn create<Y: SystemApi<RuntimeError>>(
439        owner_role: OwnerRoleEntry,
440        roles: IndexMap<ModuleId, RoleAssignmentInit>,
441        api: &mut Y,
442    ) -> Result<Own, RuntimeError> {
443        let (fields, kv_entries) = Self::init_system_struct(owner_role, roles).map_err(|e| {
444            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
445        })?;
446
447        let component_id = api.new_object(
448            ROLE_ASSIGNMENT_BLUEPRINT,
449            vec![],
450            GenericArgs::default(),
451            fields,
452            kv_entries,
453        )?;
454
455        Ok(Own(component_id))
456    }
457
458    fn set_owner_role<Y: SystemApi<RuntimeError>>(
459        rule: AccessRule,
460        api: &mut Y,
461    ) -> Result<(), RuntimeError> {
462        Self::verify_access_rule(&rule).map_err(|e| {
463            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
464        })?;
465
466        let handle = api.actor_open_field(ACTOR_STATE_SELF, 0u8, LockFlags::MUTABLE)?;
467
468        let mut owner_role = api
469            .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
470            .fully_update_and_into_latest_version();
471        owner_role.owner_role_entry.rule = rule.clone();
472        api.field_write_typed(
473            handle,
474            &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role),
475        )?;
476        api.field_close(handle)?;
477
478        Runtime::emit_event(api, SetOwnerRoleEvent { rule })?;
479
480        Ok(())
481    }
482
483    fn lock_owner_role<Y: SystemApi<RuntimeError>>(api: &mut Y) -> Result<(), RuntimeError> {
484        let handle = api.actor_open_field(ACTOR_STATE_SELF, 0u8, LockFlags::MUTABLE)?;
485        let mut owner_role = api
486            .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
487            .fully_update_and_into_latest_version();
488        owner_role.owner_role_entry.updater = OwnerRoleUpdater::None;
489        api.field_write_typed(
490            handle,
491            &RoleAssignmentOwnerFieldPayload::from_content_source(owner_role),
492        )?;
493        api.field_lock(handle)?;
494        api.field_close(handle)?;
495
496        Runtime::emit_event(api, LockOwnerRoleEvent {})?;
497
498        Ok(())
499    }
500
501    fn set_role<Y: SystemApi<RuntimeError>>(
502        module: ModuleId,
503        role_key: RoleKey,
504        rule: AccessRule,
505        api: &mut Y,
506    ) -> Result<(), RuntimeError> {
507        if module.eq(&ModuleId::RoleAssignment) {
508            return Err(RuntimeError::ApplicationError(
509                ApplicationError::RoleAssignmentError(RoleAssignmentError::UsedReservedSpace),
510            ));
511        }
512        if Self::is_role_key_reserved(&role_key) {
513            return Err(RuntimeError::ApplicationError(
514                ApplicationError::RoleAssignmentError(RoleAssignmentError::UsedReservedRole(
515                    role_key.key.to_string(),
516                )),
517            ));
518        }
519        if role_key.key.len() > MAX_ROLE_NAME_LEN {
520            return Err(RuntimeError::ApplicationError(
521                ApplicationError::RoleAssignmentError(
522                    RoleAssignmentError::ExceededMaxRoleNameLen {
523                        limit: MAX_ROLE_NAME_LEN,
524                        actual: role_key.key.len(),
525                    },
526                ),
527            ));
528        }
529        check_name(&role_key.key).map_err(|error| {
530            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(
531                RoleAssignmentError::InvalidName(error),
532            ))
533        })?;
534
535        let module_role_key = ModuleRoleKey::new(module, role_key.clone());
536
537        Self::verify_access_rule(&rule).map_err(|e| {
538            RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(e))
539        })?;
540
541        // Only allow this method to be called on attached role assignment modules.
542        // This is currently implemented to prevent unbounded number of roles from
543        // being created.
544        api.actor_get_node_id(ACTOR_REF_GLOBAL)
545            .map_err(|e| match e {
546                RuntimeError::SystemError(SystemError::GlobalAddressDoesNotExist) => {
547                    RuntimeError::ApplicationError(ApplicationError::RoleAssignmentError(
548                        RoleAssignmentError::CannotSetRoleIfNotAttached,
549                    ))
550                }
551                _ => e,
552            })?;
553
554        let handle = api.actor_open_key_value_entry(
555            ACTOR_STATE_SELF,
556            RoleAssignmentCollection::AccessRuleKeyValue.collection_index(),
557            &scrypto_encode(&module_role_key).unwrap(),
558            LockFlags::MUTABLE,
559        )?;
560
561        // Overwrite whatever access rule (or empty) is there
562        api.key_value_entry_set_typed(
563            handle,
564            RoleAssignmentAccessRuleEntryPayload::from_content_source(rule.clone()),
565        )?;
566        api.key_value_entry_close(handle)?;
567
568        Runtime::emit_event(api, SetRoleEvent { role_key, rule })?;
569
570        Ok(())
571    }
572
573    pub(crate) fn get_role<Y: SystemApi<RuntimeError>>(
574        module: ModuleId,
575        role_key: RoleKey,
576        api: &mut Y,
577    ) -> Result<Option<AccessRule>, RuntimeError> {
578        let module_role_key = ModuleRoleKey::new(module, role_key);
579
580        let handle = api.actor_open_key_value_entry(
581            ACTOR_STATE_SELF,
582            RoleAssignmentCollection::AccessRuleKeyValue.collection_index(),
583            &scrypto_encode(&module_role_key).unwrap(),
584            LockFlags::read_only(),
585        )?;
586
587        let rule = api.key_value_entry_get_typed::<RoleAssignmentAccessRuleEntryPayload>(handle)?;
588
589        api.key_value_entry_close(handle)?;
590
591        Ok(rule.map(|v| v.fully_update_and_into_latest_version()))
592    }
593}
594
595pub struct RoleAssignmentBottlenoseExtension;
596
597impl RoleAssignmentBottlenoseExtension {
598    pub fn added_functions_schema() -> (
599        IndexMap<String, FunctionSchemaInit>,
600        VersionedSchema<ScryptoCustomSchema>,
601    ) {
602        let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
603        let mut functions = index_map_new();
604        functions.insert(
605            ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT.to_string(),
606            FunctionSchemaInit {
607                receiver: Some(ReceiverInfo::normal_ref()),
608                input: TypeRef::Static(
609                    aggregator.add_child_type_and_descendents::<RoleAssignmentGetOwnerRoleInput>(),
610                ),
611                output: TypeRef::Static(
612                    aggregator.add_child_type_and_descendents::<RoleAssignmentGetOwnerRoleOutput>(),
613                ),
614                export: ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT.to_string(),
615            },
616        );
617        let schema = generate_full_schema(aggregator);
618        (functions, schema)
619    }
620
621    pub fn invoke_export<Y: SystemApi<RuntimeError>>(
622        export_name: &str,
623        input: &IndexedScryptoValue,
624        api: &mut Y,
625    ) -> Result<IndexedScryptoValue, RuntimeError> {
626        match export_name {
627            ROLE_ASSIGNMENT_GET_OWNER_ROLE_IDENT => {
628                input
629                    .as_typed::<RoleAssignmentGetOwnerRoleInput>()
630                    .map_err(|e| {
631                        RuntimeError::ApplicationError(ApplicationError::InputDecodeError(e))
632                    })?;
633
634                let rtn = Self::get_owner_role(api)?;
635                Ok(IndexedScryptoValue::from_typed(&rtn))
636            }
637            _ => Err(RuntimeError::ApplicationError(
638                ApplicationError::ExportDoesNotExist(export_name.to_string()),
639            )),
640        }
641    }
642
643    pub(crate) fn get_owner_role<Y: SystemApi<RuntimeError>>(
644        api: &mut Y,
645    ) -> Result<OwnerRoleEntry, RuntimeError> {
646        let handle = api.actor_open_field(
647            ACTOR_STATE_SELF,
648            RoleAssignmentField::Owner.field_index(),
649            LockFlags::read_only(),
650        )?;
651        let owner_role_entry = api
652            .field_read_typed::<RoleAssignmentOwnerFieldPayload>(handle)?
653            .fully_update_and_into_latest_version()
654            .owner_role_entry;
655        api.field_close(handle)?;
656
657        Ok(owner_role_entry)
658    }
659}