@@ -15,6 +15,7 @@ use std::type_name::{Self, TypeName};
1515use sui::address;
1616use sui::clock::Clock ;
1717use sui::coin::{Self , Coin , CoinMetadata , TreasuryCap };
18+ use sui::event;
1819use sui::package::UpgradeCap ;
1920
2021#[allow(lint(coin_field))]
@@ -30,13 +31,23 @@ public struct RebalancerCap has key, store {
3031 id: UID ,
3132}
3233
34+ public struct RebalancerSet has copy , drop {
35+ old_rebalancer_cap_id: ID ,
36+ new_rebalancer_cap_id: ID ,
37+ }
38+
3339const CLOCK_ADDRESS : address = @0x6 ;
3440
3541const EInvalidArguments : u64 = 1 ;
3642const ETokenPoolBalanceTooLow : u64 = 2 ;
3743const EInvalidOwnerCap : u64 = 3 ;
3844const EInvalidFunction : u64 = 4 ;
3945const EInvalidRebalancerCap : u64 = 5 ;
46+ const EMcmsRebalancerAlreadySet : u64 = 6 ;
47+ const ERebalancerCapIsInUse : u64 = 7 ;
48+ const ERebalancerCapNotTransferredOut : u64 = 8 ;
49+ const EInvalidRebalancer : u64 = 9 ;
50+ const ERebalancerCapDoesNotExist : u64 = 10 ;
4051
4152// ================================================================
4253// | Init |
@@ -515,6 +526,145 @@ public fun get_rebalancer<T>(state: &LockReleaseTokenPoolState<T>): address {
515526 object::id_to_address (&state.rebalancer_cap_id)
516527}
517528
529+ public struct McmsCap has key , store {
530+ id: UID ,
531+ owner_cap: OwnerCap ,
532+ rebalancer_cap: Option <RebalancerCap >,
533+ }
534+
535+ fun new_mcms_cap (
536+ owner_cap: OwnerCap ,
537+ rebalancer_cap: Option <RebalancerCap >,
538+ ctx: &mut TxContext ,
539+ ): McmsCap {
540+ McmsCap {
541+ id: object::new (ctx),
542+ owner_cap,
543+ rebalancer_cap,
544+ }
545+ }
546+
547+ public fun mcms_set_rebalancer <T >(
548+ state: &mut LockReleaseTokenPoolState <T >,
549+ registry: &mut Registry ,
550+ params: ExecutingCallbackParams ,
551+ ctx: &mut TxContext ,
552+ ) {
553+ let (mcms_cap, function, data) = mcms_registry::get_callback_params_with_caps <
554+ McmsCallback <T >,
555+ McmsCap ,
556+ >(
557+ registry,
558+ McmsCallback <T > {},
559+ params,
560+ );
561+ assert !(function == string::utf8 (b"set_rebalancer "), EInvalidFunction );
562+
563+ let mut stream = bcs_stream::new (data);
564+ bcs_stream::validate_obj_addrs (
565+ vector [object::id_address (state), object::id_address (&mcms_cap.owner_cap)],
566+ &mut stream,
567+ );
568+ let rebalancer = bcs_stream::deserialize_address (&mut stream);
569+ bcs_stream::assert_is_consumed (&stream);
570+
571+ if (rebalancer == mcms_registry::get_multisig_address ()) {
572+ assert !(mcms_cap.rebalancer_cap.is_none (), EMcmsRebalancerAlreadySet );
573+
574+ let new_rebalancer_cap = RebalancerCap {
575+ id: object::new (ctx),
576+ };
577+ let new_rebalancer_cap_id = object::id (&new_rebalancer_cap);
578+ mcms_cap.rebalancer_cap.fill (new_rebalancer_cap);
579+
580+ set_rebalancer_cap_id (state, &mcms_cap.owner_cap, new_rebalancer_cap_id, ctx);
581+ } else {
582+ set_rebalancer (state, &mcms_cap.owner_cap, rebalancer, ctx);
583+ // If MCMS previously owned the rebalancer cap, we destroy it now that MCMS no longer owns it
584+ if (mcms_cap.rebalancer_cap.is_some ()) {
585+ destroy_rebalancer_cap (state, mcms_cap.rebalancer_cap.extract (), ctx);
586+ }
587+ }
588+ }
589+
590+ public fun set_rebalancer <T >(
591+ state: &mut LockReleaseTokenPoolState <T >,
592+ owner_cap: &OwnerCap ,
593+ rebalancer: address ,
594+ ctx: &mut TxContext ,
595+ ) {
596+ assert !(rebalancer != mcms_registry::get_multisig_address (), EInvalidRebalancer );
597+
598+ let rebalancer_cap = RebalancerCap {
599+ id: object::new (ctx),
600+ };
601+
602+ // Update `LockReleaseTokenPoolState` before sending to rebalancer address
603+ set_rebalancer_cap_id (
604+ state,
605+ owner_cap,
606+ object::id (&rebalancer_cap),
607+ ctx,
608+ );
609+
610+ transfer::public_transfer (rebalancer_cap, rebalancer);
611+ }
612+
613+ /// Only owner can set rebalancer cap id
614+ fun set_rebalancer_cap_id <T >(
615+ state: &mut LockReleaseTokenPoolState <T >,
616+ owner_cap: &OwnerCap ,
617+ new_rebalancer_cap_id: ID ,
618+ _ctx: &mut TxContext ,
619+ ) {
620+ assert !(object::id (owner_cap) == ownable::owner_cap_id (&state.ownable_state), EInvalidOwnerCap );
621+
622+ let old_rebalancer_cap_id = state.rebalancer_cap_id;
623+ state.rebalancer_cap_id = new_rebalancer_cap_id;
624+
625+ event::emit (RebalancerSet { old_rebalancer_cap_id, new_rebalancer_cap_id });
626+ }
627+
628+ public fun mcms_destroy_mcms_cap <T >(
629+ state: &mut LockReleaseTokenPoolState <T >,
630+ registry: &mut Registry ,
631+ params: ExecutingCallbackParams ,
632+ ctx: &mut TxContext ,
633+ ) {
634+ let (mcms_cap, function, data) = mcms_registry::get_callback_params_with_caps <
635+ McmsCallback <T >,
636+ McmsCap ,
637+ >(
638+ registry,
639+ McmsCallback <T > {},
640+ params,
641+ );
642+ assert !(function == string::utf8 (b"destroy_mcms_cap "), EInvalidFunction );
643+ assert !(mcms_cap.rebalancer_cap.is_some (), ERebalancerCapDoesNotExist );
644+
645+ let mut stream = bcs_stream::new (data);
646+ bcs_stream::validate_obj_addrs (
647+ vector [object::id_address (state), object::id_address (mcms_cap.rebalancer_cap.borrow ())],
648+ &mut stream,
649+ );
650+ bcs_stream::assert_is_consumed (&stream);
651+
652+ let rebalancer_cap = mcms_cap.rebalancer_cap.extract ();
653+ destroy_rebalancer_cap (state, rebalancer_cap, ctx);
654+ }
655+
656+ /// Clean up old rebalancer caps not in use, anyone can call this function to clean up old rebalancer caps not in use.
657+ public fun destroy_rebalancer_cap <T >(
658+ state: &mut LockReleaseTokenPoolState <T >,
659+ rebalancer_cap: RebalancerCap ,
660+ _ctx: &mut TxContext ,
661+ ) {
662+ assert !(state.rebalancer_cap_id != object::id (&rebalancer_cap), ERebalancerCapIsInUse );
663+
664+ let RebalancerCap { id } = rebalancer_cap;
665+ object::delete (id);
666+ }
667+
518668#[test_only]
519669public fun create_fake_rebalancer_cap (ctx: &mut TxContext ): RebalancerCap {
520670 RebalancerCap {
@@ -597,17 +747,20 @@ public fun execute_ownership_transfer<T>(
597747 ownable::execute_ownership_transfer (owner_cap, &mut state.ownable_state, to, ctx);
598748}
599749
750+ /// Setting rebalancer cap should be called via `mcms_set_rebalancer`
600751public fun execute_ownership_transfer_to_mcms <T >(
601752 owner_cap: OwnerCap ,
602753 state: &mut LockReleaseTokenPoolState <T >,
603754 registry: &mut Registry ,
604755 to: address ,
605756 ctx: &mut TxContext ,
606757) {
607- ownable::execute_ownership_transfer_to_mcms (
608- owner_cap,
758+ assert !(object::id (&owner_cap) == state.ownable_state.owner_cap_id (), EInvalidOwnerCap );
759+
760+ ownable::execute_ownership_and_cap_transfer_to_mcms (
609761 &mut state.ownable_state,
610762 registry,
763+ new_mcms_cap (owner_cap, option::none (), ctx),
611764 to,
612765 McmsCallback <T > {},
613766 vector [b"lock_release_token_pool "],
@@ -946,9 +1099,9 @@ public fun mcms_transfer_ownership<T>(
9461099 params: ExecutingCallbackParams ,
9471100 ctx: &mut TxContext ,
9481101) {
949- let (owner_cap , function, data) = mcms_registry::get_callback_params_with_caps <
1102+ let (mcms_cap , function, data) = mcms_registry::get_callback_params_with_caps <
9501103 McmsCallback <T >,
951- OwnerCap ,
1104+ McmsCap ,
9521105 >(
9531106 registry,
9541107 McmsCallback <T > {},
@@ -958,14 +1111,14 @@ public fun mcms_transfer_ownership<T>(
9581111
9591112 let mut stream = bcs_stream::new (data);
9601113 bcs_stream::validate_obj_addrs (
961- vector [object::id_address (state), object::id_address (owner_cap)],
1114+ vector [object::id_address (state), object::id_address (&mcms_cap. owner_cap)],
9621115 &mut stream,
9631116 );
9641117
9651118 let to = bcs_stream::deserialize_address (&mut stream);
9661119 bcs_stream::assert_is_consumed (&stream);
9671120
968- transfer_ownership (state, owner_cap, to, ctx);
1121+ transfer_ownership (state, &mcms_cap. owner_cap, to, ctx);
9691122}
9701123
9711124public fun mcms_execute_ownership_transfer <T >(
@@ -974,9 +1127,9 @@ public fun mcms_execute_ownership_transfer<T>(
9741127 params: ExecutingCallbackParams ,
9751128 ctx: &mut TxContext ,
9761129) {
977- let (_owner_cap , function, data) = mcms_registry::get_callback_params_with_caps <
1130+ let (mcms_cap , function, data) = mcms_registry::get_callback_params_with_caps <
9781131 McmsCallback <T >,
979- OwnerCap ,
1132+ McmsCap ,
9801133 >(
9811134 registry,
9821135 McmsCallback <T > {},
@@ -986,14 +1139,22 @@ public fun mcms_execute_ownership_transfer<T>(
9861139
9871140 let mut stream = bcs_stream::new (data);
9881141 bcs_stream::validate_obj_addrs (
989- vector [object::id_address (_owner_cap ), object::id_address (state)],
1142+ vector [object::id_address (&mcms_cap.owner_cap ), object::id_address (state)],
9901143 &mut stream,
9911144 );
9921145
9931146 let to = bcs_stream::deserialize_address (&mut stream);
9941147 bcs_stream::assert_is_consumed (&stream);
9951148
996- let owner_cap = mcms_registry::release_cap (registry, McmsCallback <T > {});
1149+ let McmsCap { id, owner_cap, rebalancer_cap } = mcms_registry::release_cap (
1150+ registry,
1151+ McmsCallback <T > {},
1152+ );
1153+ assert !(rebalancer_cap.is_none (), ERebalancerCapNotTransferredOut );
1154+
1155+ rebalancer_cap.destroy_none ();
1156+ object::delete (id);
1157+
9971158 execute_ownership_transfer (owner_cap, state, to, ctx);
9981159}
9991160
@@ -1078,3 +1239,8 @@ public fun destroy_token_pool<T>(
10781239
10791240 reserve
10801241}
1242+
1243+ #[test_only]
1244+ public fun mcms_rebalancer_cap_address (mcms_cap: &McmsCap ): address {
1245+ object::id_address (mcms_cap.rebalancer_cap.borrow ())
1246+ }
0 commit comments