1use super::internal_prelude::*;
2use crate::errors::*;
3use crate::internal_prelude::*;
4use radix_engine_interface::api::field_api::*;
5use radix_engine_interface::api::object_api::*;
6use radix_engine_interface::api::*;
7use radix_engine_interface::blueprints::access_controller::*;
8use radix_engine_interface::blueprints::resource::*;
9use radix_engine_interface::object_modules::metadata::*;
10use radix_engine_interface::*;
11use radix_native_sdk::modules::metadata::*;
12use radix_native_sdk::modules::role_assignment::*;
13use radix_native_sdk::resource::*;
14use radix_native_sdk::runtime::*;
15use sbor::rust::prelude::*;
16
17pub struct AccessControllerV2Blueprint;
18
19impl AccessControllerV2Blueprint {
20 pub fn invoke_export<Y: SystemApi<RuntimeError>>(
21 export_name: &str,
22 input: &IndexedScryptoValue,
23 api: &mut Y,
24 ) -> Result<IndexedScryptoValue, RuntimeError> {
25 dispatch! {
26 IDENT,
27 export_name,
28 input,
29 api,
30 AccessController,
31 [
32 create,
34 create_proof,
35 initiate_recovery_as_primary,
36 initiate_recovery_as_recovery,
37 initiate_badge_withdraw_attempt_as_primary,
38 initiate_badge_withdraw_attempt_as_recovery,
39 quick_confirm_primary_role_recovery_proposal,
40 quick_confirm_recovery_role_recovery_proposal,
41 quick_confirm_primary_role_badge_withdraw_attempt,
42 quick_confirm_recovery_role_badge_withdraw_attempt,
43 timed_confirm_recovery,
44 cancel_primary_role_recovery_proposal,
45 cancel_recovery_role_recovery_proposal,
46 cancel_primary_role_badge_withdraw_attempt,
47 cancel_recovery_role_badge_withdraw_attempt,
48 lock_primary_role,
49 unlock_primary_role,
50 stop_timed_recovery,
51 mint_recovery_badges,
52 lock_recovery_fee,
54 withdraw_recovery_fee,
55 contribute_recovery_fee,
56 ]
57 }
58 }
59
60 pub fn create<Y: SystemApi<RuntimeError>>(
61 AccessControllerCreateInput {
62 controlled_asset,
63 rule_set,
64 timed_recovery_delay_in_minutes,
65 address_reservation,
66 }: AccessControllerCreateInput,
67 api: &mut Y,
68 ) -> Result<AccessControllerCreateOutput, RuntimeError> {
69 let (address_reservation, address) = {
72 if let Some(address_reservation) = address_reservation {
73 let address = api.get_reservation_address(address_reservation.0.as_node_id())?;
74 (address_reservation, address)
75 } else {
76 api.allocate_global_address(BlueprintId {
77 package_address: ACCESS_CONTROLLER_PACKAGE,
78 blueprint_name: ACCESS_CONTROLLER_BLUEPRINT.to_string(),
79 })?
80 }
81 };
82
83 let vault = {
85 let mut vault = controlled_asset
86 .resource_address(api)
87 .and_then(|resource_address| Vault::create(resource_address, api))?;
88 vault.put(controlled_asset, api)?;
89
90 vault
91 };
92
93 let recovery_badge_resource = {
95 let global_component_caller_badge =
96 NonFungibleGlobalId::global_caller_badge(GlobalCaller::GlobalObject(address));
97
98 let resource_address = {
99 let non_fungible_schema =
100 NonFungibleDataSchema::new_local_without_self_package_replacement::<()>();
101
102 let result = api.call_function(
103 RESOURCE_PACKAGE,
104 NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
105 NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
106 scrypto_encode(&NonFungibleResourceManagerCreateInput {
107 owner_role: OwnerRole::Fixed(rule!(require(global_component_caller_badge.clone()))),
108 id_type: NonFungibleIdType::Integer,
109 track_total_supply: true,
110 non_fungible_schema,
111 resource_roles: NonFungibleResourceRoles {
112 mint_roles: mint_roles! {
113 minter => rule!(require(global_component_caller_badge.clone()));
114 minter_updater => rule!(deny_all);
115 },
116 burn_roles: burn_roles! {
117 burner => rule!(allow_all);
118 burner_updater => rule!(allow_all);
119 },
120 withdraw_roles: withdraw_roles! {
121 withdrawer => rule!(deny_all);
122 withdrawer_updater => rule!(deny_all);
123 },
124 ..Default::default()
125 },
126 metadata: metadata! {
127 roles {
128 metadata_setter => AccessRule::DenyAll;
129 metadata_setter_updater => AccessRule::DenyAll;
130 metadata_locker => AccessRule::DenyAll;
131 metadata_locker_updater => AccessRule::DenyAll;
132 },
133 init {
134 "name" => "Recovery Badge".to_owned(), locked;
135 "icon_url" => UncheckedUrl::of("https://assets.radixdlt.com/icons/icon-recovery_badge.png"), locked;
136 "access_controller" => address, locked;
137 }
138 },
139 address_reservation: None,
140 })
141 .unwrap(),
142 )?;
143 scrypto_decode::<ResourceAddress>(result.as_slice()).unwrap()
144 };
145
146 resource_address
147 };
148
149 let substate = AccessControllerV2Substate::new(
150 vault,
151 None,
152 timed_recovery_delay_in_minutes,
153 recovery_badge_resource,
154 );
155
156 let object_id = api.new_simple_object(
157 ACCESS_CONTROLLER_BLUEPRINT,
158 indexmap! {
159 AccessControllerV2Field::State.field_index() => FieldValue::new(
160 AccessControllerV2StateFieldPayload::from_content_source(substate)
161 ),
162 },
163 )?;
164
165 let roles = init_roles_from_rule_set(rule_set);
166 let roles = indexmap!(ModuleId::Main => roles);
167 let role_assignment = RoleAssignment::create(OwnerRole::None, roles, api)?.0;
168
169 let metadata = Metadata::create_with_data(
170 metadata_init! {
171 "recovery_badge" => GlobalAddress::from(recovery_badge_resource), locked;
172 },
173 api,
174 )?;
175
176 api.globalize(
178 object_id,
179 indexmap!(
180 AttachedModuleId::RoleAssignment => role_assignment.0,
181 AttachedModuleId::Metadata => metadata.0,
182 ),
183 Some(address_reservation),
184 )?;
185
186 Ok(Global::new(ComponentAddress::try_from(address).unwrap()))
187 }
188
189 pub fn create_proof<Y: SystemApi<RuntimeError>>(
190 _: AccessControllerCreateProofInput,
191 api: &mut Y,
192 ) -> Result<AccessControllerCreateProofOutput, RuntimeError> {
193 transition(api, AccessControllerCreateProofStateMachineInput)
194 }
195
196 pub fn initiate_recovery_as_primary<Y: SystemApi<RuntimeError>>(
197 AccessControllerInitiateRecoveryAsPrimaryInput {
198 rule_set,
199 timed_recovery_delay_in_minutes,
200 }: AccessControllerInitiateRecoveryAsPrimaryInput,
201 api: &mut Y,
202 ) -> Result<AccessControllerInitiateRecoveryAsPrimaryOutput, RuntimeError> {
203 let proposal = RecoveryProposal {
204 rule_set,
205 timed_recovery_delay_in_minutes,
206 };
207
208 transition_mut(
209 api,
210 AccessControllerInitiateRecoveryAsPrimaryStateMachineInput {
211 proposal: proposal.clone(),
212 },
213 )?;
214
215 Runtime::emit_event(
216 api,
217 InitiateRecoveryEvent {
218 proposal,
219 proposer: Proposer::Primary,
220 },
221 )?;
222
223 Ok(())
224 }
225
226 pub fn initiate_recovery_as_recovery<Y: SystemApi<RuntimeError>>(
227 AccessControllerInitiateRecoveryAsRecoveryInput {
228 rule_set,
229 timed_recovery_delay_in_minutes,
230 }: AccessControllerInitiateRecoveryAsRecoveryInput,
231 api: &mut Y,
232 ) -> Result<AccessControllerInitiateRecoveryAsRecoveryOutput, RuntimeError> {
233 let proposal = RecoveryProposal {
234 rule_set,
235 timed_recovery_delay_in_minutes,
236 };
237
238 transition_mut(
239 api,
240 AccessControllerInitiateRecoveryAsRecoveryStateMachineInput {
241 proposal: proposal.clone(),
242 },
243 )?;
244
245 Runtime::emit_event(
246 api,
247 InitiateRecoveryEvent {
248 proposal,
249 proposer: Proposer::Recovery,
250 },
251 )?;
252
253 Ok(())
254 }
255
256 pub fn initiate_badge_withdraw_attempt_as_primary<Y: SystemApi<RuntimeError>>(
257 AccessControllerInitiateBadgeWithdrawAttemptAsPrimaryInput { .. }: AccessControllerInitiateBadgeWithdrawAttemptAsPrimaryInput,
258 api: &mut Y,
259 ) -> Result<AccessControllerInitiateBadgeWithdrawAttemptAsPrimaryOutput, RuntimeError> {
260 transition_mut(
261 api,
262 AccessControllerInitiateBadgeWithdrawAttemptAsPrimaryStateMachineInput,
263 )?;
264
265 Runtime::emit_event(
266 api,
267 InitiateBadgeWithdrawAttemptEvent {
268 proposer: Proposer::Primary,
269 },
270 )?;
271
272 Ok(())
273 }
274
275 pub fn initiate_badge_withdraw_attempt_as_recovery<Y: SystemApi<RuntimeError>>(
276 _: AccessControllerInitiateBadgeWithdrawAttemptAsRecoveryInput,
277 api: &mut Y,
278 ) -> Result<AccessControllerInitiateBadgeWithdrawAttemptAsRecoveryOutput, RuntimeError> {
279 transition_mut(
280 api,
281 AccessControllerInitiateBadgeWithdrawAttemptAsRecoveryStateMachineInput,
282 )?;
283
284 Runtime::emit_event(
285 api,
286 InitiateBadgeWithdrawAttemptEvent {
287 proposer: Proposer::Recovery,
288 },
289 )?;
290
291 Ok(())
292 }
293
294 pub fn quick_confirm_primary_role_recovery_proposal<Y: SystemApi<RuntimeError>>(
295 AccessControllerQuickConfirmPrimaryRoleRecoveryProposalInput {
296 rule_set,
297 timed_recovery_delay_in_minutes,
298 }: AccessControllerQuickConfirmPrimaryRoleRecoveryProposalInput,
299 api: &mut Y,
300 ) -> Result<AccessControllerQuickConfirmPrimaryRoleRecoveryProposalOutput, RuntimeError> {
301 let proposal = RecoveryProposal {
302 rule_set,
303 timed_recovery_delay_in_minutes,
304 };
305
306 let recovery_proposal = transition_mut(
307 api,
308 AccessControllerQuickConfirmPrimaryRoleRecoveryProposalStateMachineInput {
309 proposal_to_confirm: proposal.clone(),
310 },
311 )?;
312
313 let receiver = Runtime::get_node_id(api)?;
314 update_role_assignment(api, &receiver, recovery_proposal.rule_set)?;
315
316 Runtime::emit_event(
317 api,
318 RuleSetUpdateEvent {
319 proposal,
320 proposer: Proposer::Primary,
321 },
322 )?;
323
324 Ok(())
325 }
326
327 pub fn quick_confirm_recovery_role_recovery_proposal<Y: SystemApi<RuntimeError>>(
328 AccessControllerQuickConfirmRecoveryRoleRecoveryProposalInput {
329 rule_set,
330 timed_recovery_delay_in_minutes,
331 }: AccessControllerQuickConfirmRecoveryRoleRecoveryProposalInput,
332 api: &mut Y,
333 ) -> Result<AccessControllerQuickConfirmRecoveryRoleRecoveryProposalOutput, RuntimeError> {
334 let proposal = RecoveryProposal {
335 rule_set,
336 timed_recovery_delay_in_minutes,
337 };
338
339 let recovery_proposal = transition_mut(
340 api,
341 AccessControllerQuickConfirmRecoveryRoleRecoveryProposalStateMachineInput {
342 proposal_to_confirm: proposal.clone(),
343 },
344 )?;
345
346 let receiver = Runtime::get_node_id(api)?;
347 update_role_assignment(api, &receiver, recovery_proposal.rule_set)?;
348
349 Runtime::emit_event(
350 api,
351 RuleSetUpdateEvent {
352 proposal,
353 proposer: Proposer::Recovery,
354 },
355 )?;
356
357 Ok(())
358 }
359
360 pub fn quick_confirm_primary_role_badge_withdraw_attempt<Y: SystemApi<RuntimeError>>(
361 _: AccessControllerQuickConfirmPrimaryRoleBadgeWithdrawAttemptInput,
362 api: &mut Y,
363 ) -> Result<AccessControllerQuickConfirmPrimaryRoleBadgeWithdrawAttemptOutput, RuntimeError>
364 {
365 let bucket = transition_mut(
366 api,
367 AccessControllerQuickConfirmPrimaryRoleBadgeWithdrawAttemptStateMachineInput,
368 )?;
369
370 let receiver = Runtime::get_node_id(api)?;
371 update_role_assignment(api, &receiver, locked_role_assignment())?;
372
373 Runtime::emit_event(
374 api,
375 BadgeWithdrawEvent {
376 proposer: Proposer::Primary,
377 },
378 )?;
379
380 Ok(bucket)
381 }
382
383 pub fn quick_confirm_recovery_role_badge_withdraw_attempt<Y: SystemApi<RuntimeError>>(
384 _: AccessControllerQuickConfirmRecoveryRoleBadgeWithdrawAttemptInput,
385 api: &mut Y,
386 ) -> Result<AccessControllerQuickConfirmRecoveryRoleBadgeWithdrawAttemptOutput, RuntimeError>
387 {
388 let bucket = transition_mut(
389 api,
390 AccessControllerQuickConfirmRecoveryRoleBadgeWithdrawAttemptStateMachineInput,
391 )?;
392
393 let receiver = Runtime::get_node_id(api)?;
394 update_role_assignment(api, &receiver, locked_role_assignment())?;
395
396 Runtime::emit_event(
397 api,
398 BadgeWithdrawEvent {
399 proposer: Proposer::Recovery,
400 },
401 )?;
402
403 Ok(bucket)
404 }
405
406 pub fn timed_confirm_recovery<Y: SystemApi<RuntimeError>>(
407 AccessControllerTimedConfirmRecoveryInput {
408 rule_set,
409 timed_recovery_delay_in_minutes,
410 }: AccessControllerTimedConfirmRecoveryInput,
411 api: &mut Y,
412 ) -> Result<AccessControllerTimedConfirmRecoveryOutput, RuntimeError> {
413 let proposal = RecoveryProposal {
414 rule_set,
415 timed_recovery_delay_in_minutes,
416 };
417
418 let recovery_proposal = transition_mut(
419 api,
420 AccessControllerTimedConfirmRecoveryStateMachineInput {
421 proposal_to_confirm: proposal.clone(),
422 },
423 )?;
424
425 let receiver = Runtime::get_node_id(api)?;
427 update_role_assignment(api, &receiver, recovery_proposal.rule_set)?;
428
429 Runtime::emit_event(
430 api,
431 RuleSetUpdateEvent {
432 proposal,
433 proposer: Proposer::Recovery,
434 },
435 )?;
436
437 Ok(())
438 }
439
440 pub fn cancel_primary_role_recovery_proposal<Y: SystemApi<RuntimeError>>(
441 AccessControllerCancelPrimaryRoleRecoveryProposalInput { .. }: AccessControllerCancelPrimaryRoleRecoveryProposalInput,
442 api: &mut Y,
443 ) -> Result<AccessControllerCancelPrimaryRoleRecoveryProposalOutput, RuntimeError> {
444 transition_mut(
445 api,
446 AccessControllerCancelPrimaryRoleRecoveryProposalStateMachineInput,
447 )?;
448
449 Runtime::emit_event(
450 api,
451 CancelRecoveryProposalEvent {
452 proposer: Proposer::Primary,
453 },
454 )?;
455
456 Ok(())
457 }
458
459 pub fn cancel_recovery_role_recovery_proposal<Y: SystemApi<RuntimeError>>(
460 AccessControllerCancelRecoveryRoleRecoveryProposalInput { .. }: AccessControllerCancelRecoveryRoleRecoveryProposalInput,
461 api: &mut Y,
462 ) -> Result<AccessControllerCancelRecoveryRoleRecoveryProposalOutput, RuntimeError> {
463 transition_mut(
464 api,
465 AccessControllerCancelRecoveryRoleRecoveryProposalStateMachineInput,
466 )?;
467
468 Runtime::emit_event(
469 api,
470 CancelRecoveryProposalEvent {
471 proposer: Proposer::Recovery,
472 },
473 )?;
474
475 Ok(())
476 }
477
478 pub fn cancel_primary_role_badge_withdraw_attempt<Y: SystemApi<RuntimeError>>(
479 AccessControllerCancelPrimaryRoleBadgeWithdrawAttemptInput { .. }: AccessControllerCancelPrimaryRoleBadgeWithdrawAttemptInput,
480 api: &mut Y,
481 ) -> Result<AccessControllerCancelPrimaryRoleBadgeWithdrawAttemptOutput, RuntimeError> {
482 transition_mut(
483 api,
484 AccessControllerCancelPrimaryRoleBadgeWithdrawAttemptStateMachineInput,
485 )?;
486
487 Runtime::emit_event(
488 api,
489 CancelBadgeWithdrawAttemptEvent {
490 proposer: Proposer::Primary,
491 },
492 )?;
493
494 Ok(())
495 }
496
497 pub fn cancel_recovery_role_badge_withdraw_attempt<Y: SystemApi<RuntimeError>>(
498 AccessControllerCancelRecoveryRoleBadgeWithdrawAttemptInput { .. }: AccessControllerCancelRecoveryRoleBadgeWithdrawAttemptInput,
499 api: &mut Y,
500 ) -> Result<AccessControllerCancelRecoveryRoleBadgeWithdrawAttemptOutput, RuntimeError> {
501 transition_mut(
502 api,
503 AccessControllerCancelRecoveryRoleBadgeWithdrawAttemptStateMachineInput,
504 )?;
505
506 Runtime::emit_event(
507 api,
508 CancelBadgeWithdrawAttemptEvent {
509 proposer: Proposer::Recovery,
510 },
511 )?;
512
513 Ok(())
514 }
515
516 pub fn lock_primary_role<Y: SystemApi<RuntimeError>>(
517 AccessControllerLockPrimaryRoleInput { .. }: AccessControllerLockPrimaryRoleInput,
518 api: &mut Y,
519 ) -> Result<AccessControllerLockPrimaryRoleOutput, RuntimeError> {
520 transition_mut(api, AccessControllerLockPrimaryRoleStateMachineInput)?;
521 Runtime::emit_event(api, LockPrimaryRoleEvent {})?;
522
523 Ok(())
524 }
525
526 pub fn unlock_primary_role<Y: SystemApi<RuntimeError>>(
527 _: AccessControllerUnlockPrimaryRoleInput,
528 api: &mut Y,
529 ) -> Result<AccessControllerUnlockPrimaryRoleOutput, RuntimeError> {
530 transition_mut(api, AccessControllerUnlockPrimaryRoleStateMachineInput)?;
531 Runtime::emit_event(api, UnlockPrimaryRoleEvent {})?;
532
533 Ok(())
534 }
535
536 pub fn stop_timed_recovery<Y: SystemApi<RuntimeError>>(
537 AccessControllerStopTimedRecoveryInput {
538 rule_set,
539 timed_recovery_delay_in_minutes,
540 }: AccessControllerStopTimedRecoveryInput,
541 api: &mut Y,
542 ) -> Result<AccessControllerStopTimedRecoveryOutput, RuntimeError> {
543 transition_mut(
544 api,
545 AccessControllerStopTimedRecoveryStateMachineInput {
546 proposal: RecoveryProposal {
547 rule_set,
548 timed_recovery_delay_in_minutes,
549 },
550 },
551 )?;
552 Runtime::emit_event(api, StopTimedRecoveryEvent)?;
553
554 Ok(())
555 }
556
557 pub fn mint_recovery_badges<Y: SystemApi<RuntimeError>>(
558 AccessControllerMintRecoveryBadgesInput {
559 non_fungible_local_ids,
560 }: AccessControllerMintRecoveryBadgesInput,
561 api: &mut Y,
562 ) -> Result<AccessControllerMintRecoveryBadgesOutput, RuntimeError> {
563 Self::with_state(api, |state, api| {
564 api.call_method(
565 state.recovery_badge.as_node_id(),
566 NON_FUNGIBLE_RESOURCE_MANAGER_MINT_IDENT,
567 scrypto_encode(&NonFungibleResourceManagerMintInput {
568 entries: non_fungible_local_ids
569 .into_iter()
570 .map(|local_id| {
571 (
572 local_id,
573 (scrypto_decode(&scrypto_encode(&()).unwrap()).unwrap(),),
574 )
575 })
576 .collect(),
577 })
578 .unwrap(),
579 )
580 .map(|buffer| scrypto_decode::<NonFungibleResourceManagerMintOutput>(&buffer).unwrap())
581 })
582 }
583
584 pub fn lock_recovery_fee<Y: SystemApi<RuntimeError>>(
585 AccessControllerLockRecoveryFeeInput { amount }: AccessControllerLockRecoveryFeeInput,
586 api: &mut Y,
587 ) -> Result<AccessControllerLockRecoveryFeeOutput, RuntimeError> {
588 Self::with_state_mut(api, |state, api| {
589 let vault = state
590 .xrd_fee_vault
591 .as_mut()
592 .ok_or(AccessControllerError::NoXrdFeeVault)?;
593 vault.lock_fee(api, amount)
594 })
595 }
596
597 pub fn withdraw_recovery_fee<Y: SystemApi<RuntimeError>>(
598 AccessControllerWithdrawRecoveryFeeInput { amount }: AccessControllerWithdrawRecoveryFeeInput,
599 api: &mut Y,
600 ) -> Result<AccessControllerWithdrawRecoveryFeeOutput, RuntimeError> {
601 Runtime::emit_event(api, WithdrawRecoveryXrdEvent { amount })?;
602
603 Self::with_state_mut(api, |state, api| {
604 let vault = state
605 .xrd_fee_vault
606 .as_mut()
607 .ok_or(AccessControllerError::NoXrdFeeVault)?;
608 vault.take(amount, api)
609 })
610 }
611
612 pub fn contribute_recovery_fee<Y: SystemApi<RuntimeError>>(
613 AccessControllerContributeRecoveryFeeInput { bucket }: AccessControllerContributeRecoveryFeeInput,
614 api: &mut Y,
615 ) -> Result<AccessControllerContributeRecoveryFeeOutput, RuntimeError> {
616 bucket
617 .amount(api)
618 .and_then(|amount| Runtime::emit_event(api, DepositRecoveryXrdEvent { amount }))?;
619
620 Self::with_state_mut(api, |state, api| {
621 let vault = match state.xrd_fee_vault {
622 Some(ref mut vault) => vault,
623 None => {
624 state.xrd_fee_vault = Some(Vault::create(XRD, api)?);
625 state.xrd_fee_vault.as_mut().unwrap()
626 }
627 };
628 vault.put(bucket, api)
629 })
630 }
631
632 fn with_state<Y: SystemApi<RuntimeError>, O>(
635 api: &mut Y,
636 callback: impl FnOnce(&mut AccessControllerV2Substate, &mut Y) -> Result<O, RuntimeError>,
637 ) -> Result<O, RuntimeError> {
638 let handle = api.actor_open_field(
640 ACTOR_STATE_SELF,
641 AccessControllerV2Field::State.field_index(),
642 LockFlags::read_only(),
643 )?;
644
645 let access_controller_state = api
647 .field_read_typed::<AccessControllerV2StateFieldPayload>(handle)?
648 .into_content();
649
650 let (mut access_controller_state, handle) = if !access_controller_state.is_fully_updated() {
657 let access_controller_fully_updated_state = access_controller_state.fully_update();
659
660 api.field_close(handle)?;
662 let handle = api.actor_open_field(
663 ACTOR_STATE_SELF,
664 AccessControllerV2Field::State.field_index(),
665 LockFlags::MUTABLE,
666 )?;
667
668 api.field_write_typed(handle, &access_controller_fully_updated_state)?;
670
671 (
673 access_controller_fully_updated_state.fully_update_and_into_latest_version(),
674 handle,
675 )
676 }
677 else {
679 (
680 access_controller_state.fully_update_and_into_latest_version(),
681 handle,
682 )
683 };
684
685 let rtn = callback(&mut access_controller_state, api)?;
687
688 api.field_close(handle)?;
690
691 Ok(rtn)
693 }
694
695 fn with_state_mut<Y: SystemApi<RuntimeError>, O>(
698 api: &mut Y,
699 callback: impl FnOnce(&mut AccessControllerV2Substate, &mut Y) -> Result<O, RuntimeError>,
700 ) -> Result<O, RuntimeError> {
701 let handle = api.actor_open_field(
703 ACTOR_STATE_SELF,
704 AccessControllerV2Field::State.field_index(),
705 LockFlags::MUTABLE,
706 )?;
707
708 let access_controller_state = api
710 .field_read_typed::<AccessControllerV2StateFieldPayload>(handle)?
711 .into_content();
712
713 let mut access_controller_state = if !access_controller_state.is_fully_updated() {
718 let access_controller_fully_updated_state = access_controller_state.fully_update();
720
721 api.field_write_typed(handle, &access_controller_fully_updated_state)?;
723
724 access_controller_fully_updated_state.fully_update_and_into_latest_version()
726 }
727 else {
729 access_controller_state.fully_update_and_into_latest_version()
730 };
731
732 let rtn = callback(&mut access_controller_state, api)?;
734
735 api.field_write_typed(
738 handle,
739 &VersionedAccessControllerV2State::from(AccessControllerV2StateVersions::from(
740 access_controller_state,
741 )),
742 )?;
743
744 api.field_close(handle)?;
746
747 Ok(rtn)
749 }
750}
751
752fn locked_role_assignment() -> RuleSet {
757 RuleSet {
758 primary_role: AccessRule::DenyAll,
759 recovery_role: AccessRule::DenyAll,
760 confirmation_role: AccessRule::DenyAll,
761 }
762}
763
764fn init_roles_from_rule_set(rule_set: RuleSet) -> RoleAssignmentInit {
765 roles2! {
766 "primary" => rule_set.primary_role, updatable;
767 "recovery" => rule_set.recovery_role, updatable;
768 "confirmation" => rule_set.confirmation_role, updatable;
769 }
770}
771
772fn transition<Y: SystemApi<RuntimeError>, I>(
773 api: &mut Y,
774 input: I,
775) -> Result<<AccessControllerV2Substate as Transition<I>>::Output, RuntimeError>
776where
777 AccessControllerV2Substate: Transition<I>,
778{
779 AccessControllerV2Blueprint::with_state(api, |state, api| state.transition(api, input))
780}
781
782fn transition_mut<Y: SystemApi<RuntimeError>, I>(
783 api: &mut Y,
784 input: I,
785) -> Result<<AccessControllerV2Substate as TransitionMut<I>>::Output, RuntimeError>
786where
787 AccessControllerV2Substate: TransitionMut<I>,
788{
789 AccessControllerV2Blueprint::with_state_mut(api, |state, api| state.transition_mut(api, input))
790}
791
792fn update_role_assignment<Y: SystemApi<RuntimeError>>(
793 api: &mut Y,
794 receiver: &NodeId,
795 rule_set: RuleSet,
796) -> Result<(), RuntimeError> {
797 let attached = AttachedRoleAssignment(*receiver);
798 attached.set_role(
799 ModuleId::Main,
800 RoleKey::new("primary"),
801 rule_set.primary_role.clone(),
802 api,
803 )?;
804 attached.set_role(
805 ModuleId::Main,
806 RoleKey::new("recovery"),
807 rule_set.recovery_role.clone(),
808 api,
809 )?;
810 attached.set_role(
811 ModuleId::Main,
812 RoleKey::new("confirmation"),
813 rule_set.confirmation_role.clone(),
814 api,
815 )?;
816
817 Ok(())
818}