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, },
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 pub fn is_role_key_reserved(role_key: &RoleKey) -> bool {
254 role_key.key.starts_with("_")
255 }
256
257 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 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 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 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}