|
2 | 2 |
|
3 | 3 | use super::*; |
4 | 4 | use soroban_sdk::testutils::storage::Persistent as _; |
5 | | -use soroban_sdk::testutils::{Address as _, Ledger}; |
| 5 | +use soroban_sdk::testutils::{Address as _, Ledger, MockAuth, MockAuthInvoke}; |
| 6 | +use soroban_sdk::IntoVal; |
6 | 7 |
|
7 | 8 | const DEFAULT_BOND: i128 = 100; |
8 | 9 | const DEFAULT_CHALLENGE_WINDOW: u64 = 3600; |
@@ -2696,6 +2697,98 @@ fn test_set_paused_v2_blocks_new_assertions() { |
2696 | 2697 | f.client.assert_outcome(&asserter, &true); |
2697 | 2698 | } |
2698 | 2699 |
|
| 2700 | +#[test] |
| 2701 | +fn test_admin_rotation_updates_authority() { |
| 2702 | + let env = Env::default(); |
| 2703 | + let token_id = setup(&env); |
| 2704 | + let contract_id = env.register(TholosV2, ()); |
| 2705 | + let client = TholosV2Client::new(&env, &contract_id); |
| 2706 | + let old_admin = Address::generate(&env); |
| 2707 | + let new_admin = Address::generate(&env); |
| 2708 | + let arbitrary = Address::generate(&env); |
| 2709 | + |
| 2710 | + env.mock_auths(&[MockAuth { |
| 2711 | + address: &old_admin, |
| 2712 | + invoke: &MockAuthInvoke { |
| 2713 | + contract: &contract_id, |
| 2714 | + fn_name: "initialize", |
| 2715 | + args: ( |
| 2716 | + old_admin.clone(), |
| 2717 | + token_id.clone(), |
| 2718 | + DEFAULT_BOND, |
| 2719 | + DEFAULT_CHALLENGE_WINDOW, |
| 2720 | + DEFAULT_FINALIZE_REWARD_BPS, |
| 2721 | + DEFAULT_REGISTRATION_SECS, |
| 2722 | + DEFAULT_ANTI_SNIPE_EXT_SECS, |
| 2723 | + DEFAULT_ANTI_SNIPE_HARD_MAX_SECS, |
| 2724 | + DEFAULT_REVEAL_SECS, |
| 2725 | + DEFAULT_MAX_POSITION, |
| 2726 | + DEFAULT_MAX_TOTAL_WEIGHT, |
| 2727 | + ) |
| 2728 | + .into_val(&env), |
| 2729 | + sub_invokes: &[], |
| 2730 | + }, |
| 2731 | + }]); |
| 2732 | + init( |
| 2733 | + &client, |
| 2734 | + &old_admin, |
| 2735 | + &token_id, |
| 2736 | + DEFAULT_BOND, |
| 2737 | + DEFAULT_CHALLENGE_WINDOW, |
| 2738 | + DEFAULT_FINALIZE_REWARD_BPS, |
| 2739 | + ) |
| 2740 | + .unwrap() |
| 2741 | + .unwrap(); |
| 2742 | + |
| 2743 | + // An arbitrary address cannot authorize a rotation: set_admin always |
| 2744 | + // requires the admin currently stored by the contract. |
| 2745 | + env.mock_auths(&[MockAuth { |
| 2746 | + address: &arbitrary, |
| 2747 | + invoke: &MockAuthInvoke { |
| 2748 | + contract: &contract_id, |
| 2749 | + fn_name: "set_admin", |
| 2750 | + args: (new_admin.clone(),).into_val(&env), |
| 2751 | + sub_invokes: &[], |
| 2752 | + }, |
| 2753 | + }]); |
| 2754 | + assert!(client.try_set_admin(&new_admin).is_err()); |
| 2755 | + |
| 2756 | + env.mock_auths(&[MockAuth { |
| 2757 | + address: &old_admin, |
| 2758 | + invoke: &MockAuthInvoke { |
| 2759 | + contract: &contract_id, |
| 2760 | + fn_name: "set_admin", |
| 2761 | + args: (new_admin.clone(),).into_val(&env), |
| 2762 | + sub_invokes: &[], |
| 2763 | + }, |
| 2764 | + }]); |
| 2765 | + client.set_admin(&new_admin); |
| 2766 | + |
| 2767 | + // Rotation is immediate: the previous admin can no longer use an |
| 2768 | + // admin-only entrypoint, while the new admin can. |
| 2769 | + env.mock_auths(&[MockAuth { |
| 2770 | + address: &old_admin, |
| 2771 | + invoke: &MockAuthInvoke { |
| 2772 | + contract: &contract_id, |
| 2773 | + fn_name: "set_paused_v2", |
| 2774 | + args: (true,).into_val(&env), |
| 2775 | + sub_invokes: &[], |
| 2776 | + }, |
| 2777 | + }]); |
| 2778 | + assert!(client.try_set_paused_v2(&true).is_err()); |
| 2779 | + |
| 2780 | + env.mock_auths(&[MockAuth { |
| 2781 | + address: &new_admin, |
| 2782 | + invoke: &MockAuthInvoke { |
| 2783 | + contract: &contract_id, |
| 2784 | + fn_name: "set_paused_v2", |
| 2785 | + args: (true,).into_val(&env), |
| 2786 | + sub_invokes: &[], |
| 2787 | + }, |
| 2788 | + }]); |
| 2789 | + client.set_paused_v2(&true); |
| 2790 | +} |
| 2791 | + |
2699 | 2792 | #[test] |
2700 | 2793 | fn test_set_paused_v2_does_not_block_existing_round() { |
2701 | 2794 | // The narrower v2 pause only ever gates assert_outcome: an |
|
0 commit comments