@layerzerolabs/protocol-stellar-v2 0.2.35 → 0.2.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +274 -268
- package/.turbo/turbo-lint.log +216 -213
- package/.turbo/turbo-test.log +1735 -1994
- package/contracts/common-macros/src/auth.rs +5 -5
- package/contracts/common-macros/src/lib.rs +69 -0
- package/contracts/common-macros/src/rbac.rs +90 -0
- package/contracts/common-macros/src/tests/lz_contract.rs +5 -7
- package/contracts/common-macros/src/tests/mod.rs +1 -0
- package/contracts/common-macros/src/tests/rbac.rs +420 -0
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +4 -4
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +5 -12
- package/contracts/common-macros/src/tests/snapshots/common_macros__tests__rbac__snapshot_preserve_function_signature.snap +17 -0
- package/contracts/common-macros/src/tests/storage/parse_name.rs +0 -1
- package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_default.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig_upgradeable.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/multisig/self_auth.rs +1 -1
- package/contracts/macro-integration-tests/tests/runtime/ownable/initialization.rs +8 -5
- package/contracts/macro-integration-tests/tests/runtime/ownable/ownership_transfer.rs +2 -2
- package/contracts/macro-integration-tests/tests/runtime/rbac/guard_behavior.rs +91 -0
- package/contracts/macro-integration-tests/tests/runtime/rbac/mod.rs +30 -0
- package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/configuration.rs +2 -2
- package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +4 -4
- package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/basic.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.rs +18 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.stderr +16 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.rs +18 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.stderr +24 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.rs +18 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.stderr +24 -0
- package/contracts/macro-integration-tests/tests/ui/rbac/pass/basic.rs +71 -0
- package/contracts/macro-integration-tests/tests/ui_rbac.rs +12 -0
- package/contracts/oapps/oft/src/interfaces/mintable.rs +2 -2
- package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +2 -2
- package/contracts/oapps/oft/src/tests/extensions/pausable.rs +2 -2
- package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +2 -2
- package/contracts/oapps/sac-manager/Cargo.toml +0 -1
- package/contracts/oapps/sac-manager/src/interfaces/mod.rs +3 -0
- package/contracts/oapps/sac-manager/src/interfaces/sac_admin_wrapper.rs +49 -0
- package/contracts/oapps/sac-manager/src/lib.rs +3 -3
- package/contracts/oapps/sac-manager/src/sac_manager.rs +45 -73
- package/contracts/oapps/sac-manager/src/storage.rs +2 -9
- package/contracts/oapps/sac-manager/src/tests/sac_manager/clawback.rs +8 -10
- package/contracts/oapps/sac-manager/src/tests/sac_manager/mint.rs +13 -18
- package/contracts/oapps/sac-manager/src/tests/sac_manager/mod.rs +0 -1
- package/contracts/oapps/sac-manager/src/tests/sac_manager/set_admin.rs +22 -12
- package/contracts/oapps/sac-manager/src/tests/sac_manager/set_authorized.rs +19 -9
- package/contracts/oapps/sac-manager/src/tests/sac_manager/test_helper.rs +27 -10
- package/contracts/oapps/sac-manager/src/tests/sac_manager/view_functions.rs +0 -15
- package/contracts/oapps/sac-manager/src/tests/test_helper.rs +19 -28
- package/contracts/upgrader/src/lib.rs +5 -2
- package/contracts/utils/src/auth.rs +6 -2
- package/contracts/utils/src/errors.rs +18 -0
- package/contracts/utils/src/lib.rs +1 -0
- package/contracts/utils/src/multisig.rs +5 -1
- package/contracts/utils/src/ownable.rs +1 -1
- package/contracts/utils/src/rbac.rs +428 -0
- package/contracts/utils/src/tests/auth.rs +2 -2
- package/contracts/utils/src/tests/mod.rs +1 -0
- package/contracts/utils/src/tests/multisig.rs +2 -2
- package/contracts/utils/src/tests/ownable.rs +4 -5
- package/contracts/utils/src/tests/rbac.rs +559 -0
- package/contracts/utils/src/tests/ttl_configurable.rs +5 -6
- package/contracts/utils/src/tests/upgradeable.rs +4 -5
- package/contracts/workers/worker/src/worker.rs +1 -1
- package/package.json +3 -3
- package/sdk/.turbo/turbo-test.log +368 -366
- package/sdk/dist/generated/bml.d.ts +53 -3
- package/sdk/dist/generated/bml.js +27 -3
- package/sdk/dist/generated/counter.d.ts +55 -5
- package/sdk/dist/generated/counter.js +28 -4
- package/sdk/dist/generated/dvn.d.ts +55 -5
- package/sdk/dist/generated/dvn.js +28 -4
- package/sdk/dist/generated/dvn_fee_lib.d.ts +55 -5
- package/sdk/dist/generated/dvn_fee_lib.js +28 -4
- package/sdk/dist/generated/endpoint.d.ts +55 -5
- package/sdk/dist/generated/endpoint.js +28 -4
- package/sdk/dist/generated/executor.d.ts +55 -5
- package/sdk/dist/generated/executor.js +28 -4
- package/sdk/dist/generated/executor_fee_lib.d.ts +55 -5
- package/sdk/dist/generated/executor_fee_lib.js +28 -4
- package/sdk/dist/generated/executor_helper.d.ts +53 -3
- package/sdk/dist/generated/executor_helper.js +27 -3
- package/sdk/dist/generated/layerzero_view.d.ts +55 -5
- package/sdk/dist/generated/layerzero_view.js +28 -4
- package/sdk/dist/generated/oft.d.ts +55 -5
- package/sdk/dist/generated/oft.js +28 -4
- package/sdk/dist/generated/price_feed.d.ts +55 -5
- package/sdk/dist/generated/price_feed.js +28 -4
- package/sdk/dist/generated/sac_manager.d.ts +213 -687
- package/sdk/dist/generated/sac_manager.js +57 -239
- package/sdk/dist/generated/sml.d.ts +55 -5
- package/sdk/dist/generated/sml.js +28 -4
- package/sdk/dist/generated/treasury.d.ts +55 -5
- package/sdk/dist/generated/treasury.js +28 -4
- package/sdk/dist/generated/uln302.d.ts +55 -5
- package/sdk/dist/generated/uln302.js +28 -4
- package/sdk/dist/generated/upgrader.d.ts +53 -3
- package/sdk/dist/generated/upgrader.js +27 -3
- package/sdk/package.json +1 -1
- package/sdk/test/oft-sml.test.ts +10 -9
- package/sdk/test/{sac-manager-redistribution.test.ts → sac-manager.test.ts} +49 -25
- package/contracts/oapps/sac-manager/src/errors.rs +0 -14
- package/contracts/oapps/sac-manager/src/tests/sac_manager/set_minter.rs +0 -69
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
use crate::{
|
|
2
2
|
auth::Auth,
|
|
3
3
|
errors::OwnableError,
|
|
4
|
-
option_ext::OptionExt,
|
|
5
4
|
ownable::{
|
|
6
5
|
self, Ownable, OwnableInitializer, OwnableStorage, OwnershipRenounced, OwnershipTransferred,
|
|
7
6
|
OwnershipTransferring,
|
|
@@ -40,8 +39,8 @@ impl Contract {
|
|
|
40
39
|
/// Auth implementation for the test contract - uses stored owner as authorizer.
|
|
41
40
|
#[contractimpl]
|
|
42
41
|
impl Auth for Contract {
|
|
43
|
-
fn authorizer(env: &Env) -> Address {
|
|
44
|
-
<Self as Ownable>::owner(env)
|
|
42
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
43
|
+
<Self as Ownable>::owner(env)
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
|
|
@@ -130,7 +129,7 @@ fn transfer_after_renounce_fails() {
|
|
|
130
129
|
mock_auth(&env, &contract, &owner, "renounce_ownership", ());
|
|
131
130
|
client.renounce_ownership();
|
|
132
131
|
|
|
133
|
-
// Try to transfer after renounce - should fail with
|
|
132
|
+
// Try to transfer after renounce - should fail with AuthorizerNotFound
|
|
134
133
|
mock_auth(&env, &contract, &owner, "transfer_ownership", (&new_owner,));
|
|
135
134
|
let result = client.try_transfer_ownership(&new_owner);
|
|
136
135
|
assert_eq!(result.err().unwrap().ok().unwrap(), OwnableError::OwnerNotSet.into());
|
|
@@ -598,7 +597,7 @@ fn renounce_after_renounce_fails() {
|
|
|
598
597
|
mock_auth(&env, &contract, &owner, "renounce_ownership", ());
|
|
599
598
|
client.renounce_ownership();
|
|
600
599
|
|
|
601
|
-
// Try to renounce again - should fail with
|
|
600
|
+
// Try to renounce again - should fail with AuthorizerNotFound
|
|
602
601
|
mock_auth(&env, &contract, &owner, "renounce_ownership", ());
|
|
603
602
|
let result = client.try_renounce_ownership();
|
|
604
603
|
assert_eq!(result.err().unwrap().ok().unwrap(), OwnableError::OwnerNotSet.into());
|
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
extern crate std;
|
|
2
|
+
|
|
3
|
+
use crate::{
|
|
4
|
+
auth::Auth,
|
|
5
|
+
errors::RbacError,
|
|
6
|
+
rbac::{
|
|
7
|
+
ensure_role, grant_role_no_auth, remove_role_admin_no_auth, revoke_role_no_auth, RbacStorage, RoleAdminChanged,
|
|
8
|
+
RoleBasedAccessControl, RoleGranted, RoleRevoked, MAX_ROLES,
|
|
9
|
+
},
|
|
10
|
+
testing_utils::{assert_eq_event, assert_eq_events},
|
|
11
|
+
tests::test_helper::mock_auth,
|
|
12
|
+
};
|
|
13
|
+
use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, Env, Symbol, Vec};
|
|
14
|
+
|
|
15
|
+
// ============================================
|
|
16
|
+
// Test Contract
|
|
17
|
+
// ============================================
|
|
18
|
+
|
|
19
|
+
#[contract]
|
|
20
|
+
pub struct RbacTestContract;
|
|
21
|
+
|
|
22
|
+
fn authorizer_key(env: &Env) -> Symbol {
|
|
23
|
+
Symbol::new(env, "authorizer")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#[contractimpl]
|
|
27
|
+
impl RbacTestContract {
|
|
28
|
+
/// Test-only helper to set the authorizer in instance storage.
|
|
29
|
+
///
|
|
30
|
+
/// NOTE: This is intentionally *not* protected by auth, since it's only used in unit tests.
|
|
31
|
+
pub fn set_authorizer_for_test(env: &Env, authorizer: Address) {
|
|
32
|
+
env.storage().instance().set(&authorizer_key(env), &authorizer);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ----------------------------
|
|
36
|
+
// Public helper wrappers
|
|
37
|
+
// ----------------------------
|
|
38
|
+
|
|
39
|
+
pub fn rbac_ensure_role(env: &Env, role: Symbol, caller: Address) {
|
|
40
|
+
ensure_role(env, &role, &caller);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
pub fn rbac_rm_role_admin_no_auth(env: &Env, role: Symbol) {
|
|
44
|
+
remove_role_admin_no_auth(env, &role);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ----------------------------
|
|
48
|
+
// Raw storage setters (test-only)
|
|
49
|
+
// ----------------------------
|
|
50
|
+
|
|
51
|
+
pub fn raw_set_existing_roles(env: &Env, roles: Vec<Symbol>) {
|
|
52
|
+
RbacStorage::set_existing_roles(env, &roles);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn raw_set_role_accounts_count(env: &Env, role: Symbol, count: u32) {
|
|
56
|
+
RbacStorage::set_role_accounts_count(env, &role, &count);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn raw_set_role_account_to_index(env: &Env, role: Symbol, account: Address, index: u32) {
|
|
60
|
+
RbacStorage::set_role_account_to_index(env, &role, &account, &index);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fn raw_set_role_index_to_account(env: &Env, role: Symbol, index: u32, account: Address) {
|
|
64
|
+
RbacStorage::set_role_index_to_account(env, &role, index, &account);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/// `Auth` implementation for the test contract - uses a stored address as the authorizer.
|
|
69
|
+
impl Auth for RbacTestContract {
|
|
70
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
71
|
+
env.storage().instance().get(&authorizer_key(env))
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Expose `RoleBasedAccessControl` default methods as Soroban entrypoints.
|
|
76
|
+
#[contractimpl(contracttrait)]
|
|
77
|
+
impl RoleBasedAccessControl for RbacTestContract {}
|
|
78
|
+
|
|
79
|
+
fn setup_contract() -> (Env, Address, Address, RbacTestContractClient<'static>) {
|
|
80
|
+
let env = Env::default();
|
|
81
|
+
let contract_id = env.register(RbacTestContract, ());
|
|
82
|
+
let client = RbacTestContractClient::new(&env, &contract_id);
|
|
83
|
+
|
|
84
|
+
let authorizer = Address::generate(&env);
|
|
85
|
+
client.set_authorizer_for_test(&authorizer);
|
|
86
|
+
|
|
87
|
+
(env, contract_id, authorizer, client)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ============================================
|
|
91
|
+
// Views + basic errors
|
|
92
|
+
// ============================================
|
|
93
|
+
|
|
94
|
+
#[test]
|
|
95
|
+
fn views_default_and_index_out_of_bounds_error_code() {
|
|
96
|
+
let (env, _contract_id, _authorizer, client) = setup_contract();
|
|
97
|
+
|
|
98
|
+
let role = Symbol::new(&env, "ROLE");
|
|
99
|
+
let acct = Address::generate(&env);
|
|
100
|
+
|
|
101
|
+
assert_eq!(client.get_existing_roles(), Vec::<Symbol>::new(&env));
|
|
102
|
+
assert_eq!(client.get_role_admin(&role), None);
|
|
103
|
+
assert_eq!(client.get_role_member_count(&role), 0);
|
|
104
|
+
assert_eq!(client.has_role(&acct, &role), None);
|
|
105
|
+
|
|
106
|
+
// Ensure-role should fail when the caller is unauthorized.
|
|
107
|
+
let res = client.try_rbac_ensure_role(&role, &acct);
|
|
108
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::Unauthorized.into());
|
|
109
|
+
|
|
110
|
+
// Member lookup out of bounds should return IndexOutOfBounds.
|
|
111
|
+
let res = client.try_get_role_member(&role, &0u32);
|
|
112
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::IndexOutOfBounds.into());
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ============================================
|
|
116
|
+
// grant_role / grant_role_no_auth
|
|
117
|
+
// ============================================
|
|
118
|
+
|
|
119
|
+
#[test]
|
|
120
|
+
fn grant_role_authorizer_emits_event_and_enumerates() {
|
|
121
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
122
|
+
|
|
123
|
+
let role = Symbol::new(&env, "ROLE1");
|
|
124
|
+
let acct = Address::generate(&env);
|
|
125
|
+
|
|
126
|
+
mock_auth(&env, &contract_id, &authorizer, "grant_role", (acct.clone(), role.clone(), authorizer.clone()));
|
|
127
|
+
client.grant_role(&acct, &role, &authorizer);
|
|
128
|
+
|
|
129
|
+
assert_eq_event(
|
|
130
|
+
&env,
|
|
131
|
+
&contract_id,
|
|
132
|
+
RoleGranted { role: role.clone(), account: acct.clone(), caller: authorizer.clone() },
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
assert_eq!(client.get_role_member_count(&role), 1);
|
|
136
|
+
assert_eq!(client.has_role(&acct, &role), Some(0));
|
|
137
|
+
assert_eq!(client.get_role_member(&role, &0), acct.clone());
|
|
138
|
+
|
|
139
|
+
let roles = client.get_existing_roles();
|
|
140
|
+
assert_eq!(roles.len(), 1);
|
|
141
|
+
assert_eq!(roles.get(0).unwrap(), role);
|
|
142
|
+
|
|
143
|
+
// ensure_role succeeds for a held role.
|
|
144
|
+
client.rbac_ensure_role(&Symbol::new(&env, "ROLE1"), &acct);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[test]
|
|
148
|
+
fn authorizer_can_revoke_role() {
|
|
149
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
150
|
+
|
|
151
|
+
let role = Symbol::new(&env, "ROLE_AUTHZ_REVOKE");
|
|
152
|
+
let user = Address::generate(&env);
|
|
153
|
+
|
|
154
|
+
// Step 1: authorizer grants role to user.
|
|
155
|
+
mock_auth(&env, &contract_id, &authorizer, "grant_role", (user.clone(), role.clone(), authorizer.clone()));
|
|
156
|
+
client.grant_role(&user, &role, &authorizer);
|
|
157
|
+
assert_eq_event(
|
|
158
|
+
&env,
|
|
159
|
+
&contract_id,
|
|
160
|
+
RoleGranted { role: role.clone(), account: user.clone(), caller: authorizer.clone() },
|
|
161
|
+
);
|
|
162
|
+
assert_eq!(client.has_role(&user, &role), Some(0));
|
|
163
|
+
assert_eq!(client.get_role_member_count(&role), 1);
|
|
164
|
+
|
|
165
|
+
// Step 2: authorizer revokes role from user.
|
|
166
|
+
mock_auth(&env, &contract_id, &authorizer, "revoke_role", (user.clone(), role.clone(), authorizer.clone()));
|
|
167
|
+
client.revoke_role(&user, &role, &authorizer);
|
|
168
|
+
assert_eq_event(&env, &contract_id, RoleRevoked { role: role.clone(), account: user.clone(), caller: authorizer });
|
|
169
|
+
assert_eq!(client.has_role(&user, &role), None);
|
|
170
|
+
assert_eq!(client.get_role_member_count(&role), 0);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
#[test]
|
|
174
|
+
fn grant_role_no_auth_is_idempotent_and_emits_once() {
|
|
175
|
+
let (env, contract_id, _authorizer, client) = setup_contract();
|
|
176
|
+
|
|
177
|
+
let role = Symbol::new(&env, "ROLE2");
|
|
178
|
+
let acct = Address::generate(&env);
|
|
179
|
+
let caller = Address::generate(&env);
|
|
180
|
+
|
|
181
|
+
env.as_contract(&contract_id, || {
|
|
182
|
+
grant_role_no_auth(&env, &acct, &role, &caller);
|
|
183
|
+
// Second call should hit the early-return branch and emit no event.
|
|
184
|
+
grant_role_no_auth(&env, &acct, &role, &caller);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Only the first grant should emit.
|
|
188
|
+
assert_eq_event(&env, &contract_id, RoleGranted { role: role.clone(), account: acct.clone(), caller });
|
|
189
|
+
|
|
190
|
+
assert_eq!(client.get_role_member_count(&role), 1);
|
|
191
|
+
assert_eq!(client.has_role(&acct, &role), Some(0));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
#[test]
|
|
195
|
+
fn grant_role_unauthorized_returns_error_code() {
|
|
196
|
+
let (env, contract_id, _authorizer, client) = setup_contract();
|
|
197
|
+
|
|
198
|
+
let role = Symbol::new(&env, "ROLE3");
|
|
199
|
+
let acct = Address::generate(&env);
|
|
200
|
+
let caller = Address::generate(&env);
|
|
201
|
+
|
|
202
|
+
// Provide auth so we reach the RBAC Unauthorized check (not Auth::InvalidAction).
|
|
203
|
+
mock_auth(&env, &contract_id, &caller, "grant_role", (acct.clone(), role.clone(), caller.clone()));
|
|
204
|
+
let res = client.try_grant_role(&acct, &role, &caller);
|
|
205
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::Unauthorized.into());
|
|
206
|
+
|
|
207
|
+
assert_eq!(client.get_role_member_count(&role), 0);
|
|
208
|
+
assert_eq!(client.get_existing_roles(), Vec::<Symbol>::new(&env));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#[test]
|
|
212
|
+
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
213
|
+
fn grant_role_requires_auth() {
|
|
214
|
+
let (env, _contract_id, authorizer, client) = setup_contract();
|
|
215
|
+
|
|
216
|
+
let role = Symbol::new(&env, "ROLE_AUTH");
|
|
217
|
+
let acct = Address::generate(&env);
|
|
218
|
+
|
|
219
|
+
// No mock_auth -> caller.require_auth() must fail.
|
|
220
|
+
client.grant_role(&acct, &role, &authorizer);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ============================================
|
|
224
|
+
// set_role_admin
|
|
225
|
+
// ============================================
|
|
226
|
+
|
|
227
|
+
#[test]
|
|
228
|
+
fn set_role_admin_emits_event_with_previous_admin_values() {
|
|
229
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
230
|
+
|
|
231
|
+
let role = Symbol::new(&env, "ROLE_ADMIN_TEST");
|
|
232
|
+
let admin1 = Symbol::new(&env, "ADMIN1");
|
|
233
|
+
let admin2 = Symbol::new(&env, "ADMIN2");
|
|
234
|
+
|
|
235
|
+
mock_auth(&env, &contract_id, &authorizer, "set_role_admin", (role.clone(), admin1.clone()));
|
|
236
|
+
client.set_role_admin(&role, &admin1);
|
|
237
|
+
|
|
238
|
+
assert_eq_event(
|
|
239
|
+
&env,
|
|
240
|
+
&contract_id,
|
|
241
|
+
RoleAdminChanged { role: role.clone(), previous_admin_role: None, new_admin_role: Some(admin1.clone()) },
|
|
242
|
+
);
|
|
243
|
+
assert_eq!(client.get_role_admin(&role), Some(admin1.clone()));
|
|
244
|
+
|
|
245
|
+
mock_auth(&env, &contract_id, &authorizer, "set_role_admin", (role.clone(), admin2.clone()));
|
|
246
|
+
client.set_role_admin(&role, &admin2);
|
|
247
|
+
|
|
248
|
+
assert_eq_event(
|
|
249
|
+
&env,
|
|
250
|
+
&contract_id,
|
|
251
|
+
RoleAdminChanged {
|
|
252
|
+
role: role.clone(),
|
|
253
|
+
previous_admin_role: Some(admin1),
|
|
254
|
+
new_admin_role: Some(admin2.clone()),
|
|
255
|
+
},
|
|
256
|
+
);
|
|
257
|
+
assert_eq!(client.get_role_admin(&role), Some(admin2));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#[test]
|
|
261
|
+
fn remove_role_admin_errors_and_success() {
|
|
262
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
263
|
+
|
|
264
|
+
let role = Symbol::new(&env, "ROLE_ADMIN_REMOVE");
|
|
265
|
+
let admin = Symbol::new(&env, "ADMIN_REMOVE");
|
|
266
|
+
|
|
267
|
+
// If no admin role is set, removing should fail with AdminRoleNotFound.
|
|
268
|
+
mock_auth(&env, &contract_id, &authorizer, "remove_role_admin", (role.clone(),));
|
|
269
|
+
let res = client.try_remove_role_admin(&role);
|
|
270
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::AdminRoleNotFound.into());
|
|
271
|
+
|
|
272
|
+
// Set admin role (requires authorizer auth).
|
|
273
|
+
mock_auth(&env, &contract_id, &authorizer, "set_role_admin", (role.clone(), admin.clone()));
|
|
274
|
+
client.set_role_admin(&role, &admin);
|
|
275
|
+
assert_eq!(client.get_role_admin(&role), Some(admin));
|
|
276
|
+
|
|
277
|
+
// Now removal should succeed and clear the admin role.
|
|
278
|
+
mock_auth(&env, &contract_id, &authorizer, "remove_role_admin", (role.clone(),));
|
|
279
|
+
client.remove_role_admin(&role);
|
|
280
|
+
assert_eq!(client.get_role_admin(&role), None);
|
|
281
|
+
|
|
282
|
+
// Removing again should fail with AdminRoleNotFound.
|
|
283
|
+
mock_auth(&env, &contract_id, &authorizer, "remove_role_admin", (role.clone(),));
|
|
284
|
+
let res = client.try_remove_role_admin(&role);
|
|
285
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::AdminRoleNotFound.into());
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
#[test]
|
|
289
|
+
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
290
|
+
fn set_role_admin_requires_auth() {
|
|
291
|
+
let (env, _contract_id, _authorizer, client) = setup_contract();
|
|
292
|
+
let role = Symbol::new(&env, "ROLE_ADMIN_AUTH");
|
|
293
|
+
let admin = Symbol::new(&env, "ADMIN");
|
|
294
|
+
|
|
295
|
+
// No mock_auth -> only_auth/authorizer.require_auth() must fail.
|
|
296
|
+
client.set_role_admin(&role, &admin);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// ============================================
|
|
300
|
+
// Admin-role pathway + revoke + renounce
|
|
301
|
+
// ============================================
|
|
302
|
+
|
|
303
|
+
#[test]
|
|
304
|
+
fn admin_role_holder_can_grant_revoke_and_renounce_emits_events() {
|
|
305
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
306
|
+
|
|
307
|
+
let role = Symbol::new(&env, "ROLE4");
|
|
308
|
+
let admin_role = Symbol::new(&env, "ADMIN_ROLE");
|
|
309
|
+
let admin = Address::generate(&env);
|
|
310
|
+
let user = Address::generate(&env);
|
|
311
|
+
|
|
312
|
+
// Authorizer sets admin role for `role`.
|
|
313
|
+
mock_auth(&env, &contract_id, &authorizer, "set_role_admin", (role.clone(), admin_role.clone()));
|
|
314
|
+
client.set_role_admin(&role, &admin_role);
|
|
315
|
+
assert_eq_event(
|
|
316
|
+
&env,
|
|
317
|
+
&contract_id,
|
|
318
|
+
RoleAdminChanged { role: role.clone(), previous_admin_role: None, new_admin_role: Some(admin_role.clone()) },
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
// Authorizer grants the admin role to `admin`.
|
|
322
|
+
mock_auth(&env, &contract_id, &authorizer, "grant_role", (admin.clone(), admin_role.clone(), authorizer.clone()));
|
|
323
|
+
client.grant_role(&admin, &admin_role, &authorizer);
|
|
324
|
+
assert_eq_event(
|
|
325
|
+
&env,
|
|
326
|
+
&contract_id,
|
|
327
|
+
RoleGranted { role: admin_role.clone(), account: admin.clone(), caller: authorizer.clone() },
|
|
328
|
+
);
|
|
329
|
+
assert_eq!(client.has_role(&admin, &admin_role), Some(0));
|
|
330
|
+
assert_eq!(client.get_role_member_count(&admin_role), 1);
|
|
331
|
+
|
|
332
|
+
// Admin grants `role` to `user` (admin-role pathway).
|
|
333
|
+
mock_auth(&env, &contract_id, &admin, "grant_role", (user.clone(), role.clone(), admin.clone()));
|
|
334
|
+
client.grant_role(&user, &role, &admin);
|
|
335
|
+
assert_eq_event(
|
|
336
|
+
&env,
|
|
337
|
+
&contract_id,
|
|
338
|
+
RoleGranted { role: role.clone(), account: user.clone(), caller: admin.clone() },
|
|
339
|
+
);
|
|
340
|
+
assert_eq!(client.has_role(&user, &role), Some(0));
|
|
341
|
+
assert_eq!(client.get_role_member_count(&role), 1);
|
|
342
|
+
|
|
343
|
+
// Admin revokes `role` from `user`.
|
|
344
|
+
mock_auth(&env, &contract_id, &admin, "revoke_role", (user.clone(), role.clone(), admin.clone()));
|
|
345
|
+
client.revoke_role(&user, &role, &admin);
|
|
346
|
+
assert_eq_event(
|
|
347
|
+
&env,
|
|
348
|
+
&contract_id,
|
|
349
|
+
RoleRevoked { role: role.clone(), account: user.clone(), caller: admin.clone() },
|
|
350
|
+
);
|
|
351
|
+
assert_eq!(client.has_role(&user, &role), None);
|
|
352
|
+
assert_eq!(client.get_role_member_count(&role), 0);
|
|
353
|
+
// Admin should still hold the admin role.
|
|
354
|
+
assert_eq!(client.has_role(&admin, &admin_role), Some(0));
|
|
355
|
+
|
|
356
|
+
// Admin grants again, then user renounces.
|
|
357
|
+
mock_auth(&env, &contract_id, &admin, "grant_role", (user.clone(), role.clone(), admin.clone()));
|
|
358
|
+
client.grant_role(&user, &role, &admin);
|
|
359
|
+
assert_eq_event(&env, &contract_id, RoleGranted { role: role.clone(), account: user.clone(), caller: admin });
|
|
360
|
+
assert_eq!(client.has_role(&user, &role), Some(0));
|
|
361
|
+
|
|
362
|
+
mock_auth(&env, &contract_id, &user, "renounce_role", (role.clone(), user.clone()));
|
|
363
|
+
client.renounce_role(&role, &user);
|
|
364
|
+
assert_eq_event(&env, &contract_id, RoleRevoked { role, account: user.clone(), caller: user.clone() });
|
|
365
|
+
assert_eq!(client.has_role(&user, &Symbol::new(&env, "ROLE4")), None);
|
|
366
|
+
assert_eq!(client.get_role_member_count(&Symbol::new(&env, "ROLE4")), 0);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
#[test]
|
|
370
|
+
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
371
|
+
fn revoke_role_requires_auth() {
|
|
372
|
+
let (env, _contract_id, authorizer, client) = setup_contract();
|
|
373
|
+
let role = Symbol::new(&env, "ROLE_REVOKE_AUTH");
|
|
374
|
+
let acct = Address::generate(&env);
|
|
375
|
+
|
|
376
|
+
// No mock_auth -> caller.require_auth() must fail.
|
|
377
|
+
client.revoke_role(&acct, &role, &authorizer);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
#[test]
|
|
381
|
+
#[should_panic(expected = "Error(Auth, InvalidAction)")]
|
|
382
|
+
fn renounce_role_requires_auth() {
|
|
383
|
+
let (env, _contract_id, _authorizer, client) = setup_contract();
|
|
384
|
+
let role = Symbol::new(&env, "ROLE_RENOUNCE_AUTH");
|
|
385
|
+
let caller = Address::generate(&env);
|
|
386
|
+
|
|
387
|
+
// No mock_auth -> caller.require_auth() must fail.
|
|
388
|
+
client.renounce_role(&role, &caller);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ============================================
|
|
392
|
+
// revoke_role_no_auth + enumeration branches
|
|
393
|
+
// ============================================
|
|
394
|
+
|
|
395
|
+
#[test]
|
|
396
|
+
fn swap_remove_updates_indices_and_existing_roles_removed_on_last_member() {
|
|
397
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
398
|
+
|
|
399
|
+
let role = Symbol::new(&env, "ROLE6");
|
|
400
|
+
let a1 = Address::generate(&env);
|
|
401
|
+
let a2 = Address::generate(&env);
|
|
402
|
+
let caller = Address::generate(&env);
|
|
403
|
+
|
|
404
|
+
// Single contract context emits 3 events and hits the swap-remove branch.
|
|
405
|
+
env.as_contract(&contract_id, || {
|
|
406
|
+
grant_role_no_auth(&env, &a1, &role, &caller);
|
|
407
|
+
grant_role_no_auth(&env, &a2, &role, &caller);
|
|
408
|
+
revoke_role_no_auth(&env, &a1, &role, &caller);
|
|
409
|
+
});
|
|
410
|
+
assert_eq_events(
|
|
411
|
+
&env,
|
|
412
|
+
&contract_id,
|
|
413
|
+
&[
|
|
414
|
+
&RoleGranted { role: role.clone(), account: a1.clone(), caller: caller.clone() },
|
|
415
|
+
&RoleGranted { role: role.clone(), account: a2.clone(), caller: caller.clone() },
|
|
416
|
+
&RoleRevoked { role: role.clone(), account: a1.clone(), caller: caller.clone() },
|
|
417
|
+
],
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
// After swap-remove, only a2 should remain at index 0.
|
|
421
|
+
assert_eq!(client.get_role_member_count(&role), 1);
|
|
422
|
+
assert_eq!(client.has_role(&a2, &role), Some(0));
|
|
423
|
+
assert_eq!(client.has_role(&a1, &role), None);
|
|
424
|
+
assert_eq!(client.get_role_member(&role, &0), a2.clone());
|
|
425
|
+
assert_eq!(client.get_existing_roles().len(), 1);
|
|
426
|
+
|
|
427
|
+
// Remove last remaining member; role should be removed from existing roles.
|
|
428
|
+
mock_auth(&env, &contract_id, &authorizer, "revoke_role", (a2.clone(), role.clone(), authorizer.clone()));
|
|
429
|
+
client.revoke_role(&a2, &role, &authorizer);
|
|
430
|
+
assert_eq_event(&env, &contract_id, RoleRevoked { role: role.clone(), account: a2, caller: authorizer });
|
|
431
|
+
assert_eq!(client.get_existing_roles(), Vec::<Symbol>::new(&env));
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
#[test]
|
|
435
|
+
fn revoke_last_member_of_two_no_swap_branch() {
|
|
436
|
+
let (env, contract_id, _authorizer, client) = setup_contract();
|
|
437
|
+
|
|
438
|
+
let role = Symbol::new(&env, "ROLE_NO_SWAP");
|
|
439
|
+
let a1 = Address::generate(&env);
|
|
440
|
+
let a2 = Address::generate(&env);
|
|
441
|
+
let caller = Address::generate(&env);
|
|
442
|
+
|
|
443
|
+
// Emit 3 events in one contract context: grant a1, grant a2, revoke a2.
|
|
444
|
+
// This hits the `to_remove_idx == last_idx` branch with `count > 1`.
|
|
445
|
+
env.as_contract(&contract_id, || {
|
|
446
|
+
grant_role_no_auth(&env, &a1, &role, &caller);
|
|
447
|
+
grant_role_no_auth(&env, &a2, &role, &caller);
|
|
448
|
+
revoke_role_no_auth(&env, &a2, &role, &caller);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
assert_eq_events(
|
|
452
|
+
&env,
|
|
453
|
+
&contract_id,
|
|
454
|
+
&[
|
|
455
|
+
&RoleGranted { role: role.clone(), account: a1.clone(), caller: caller.clone() },
|
|
456
|
+
&RoleGranted { role: role.clone(), account: a2.clone(), caller: caller.clone() },
|
|
457
|
+
&RoleRevoked { role: role.clone(), account: a2.clone(), caller: caller.clone() },
|
|
458
|
+
],
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
assert_eq!(client.get_role_member_count(&role), 1);
|
|
462
|
+
assert_eq!(client.has_role(&a1, &role), Some(0));
|
|
463
|
+
assert_eq!(client.has_role(&a2, &role), None);
|
|
464
|
+
assert_eq!(client.get_role_member(&role, &0), a1);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// This test intentionally constructs an *inconsistent* RBAC storage state where a role has
|
|
468
|
+
// a member but the role is missing from `ExistingRoles`.
|
|
469
|
+
//
|
|
470
|
+
// The implementation detects this corruption on last-member removal: `remove_from_role_enumeration`
|
|
471
|
+
// calls `existing.first_index_of(role).unwrap_or_panic(..., RoleNotFound)`, which returns
|
|
472
|
+
// `RbacError::RoleNotFound` to the caller (it does not silently skip the removal).
|
|
473
|
+
#[test]
|
|
474
|
+
fn removing_last_member_when_role_missing_from_existing_roles_returns_role_not_found() {
|
|
475
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
476
|
+
|
|
477
|
+
let role = Symbol::new(&env, "ROLE7");
|
|
478
|
+
let acct = Address::generate(&env);
|
|
479
|
+
|
|
480
|
+
// Create a consistent single-member role, but *do not* include it in ExistingRoles.
|
|
481
|
+
client.raw_set_existing_roles(&Vec::<Symbol>::new(&env));
|
|
482
|
+
client.raw_set_role_accounts_count(&role, &1);
|
|
483
|
+
client.raw_set_role_account_to_index(&role, &acct, &0);
|
|
484
|
+
client.raw_set_role_index_to_account(&role, &0, &acct);
|
|
485
|
+
|
|
486
|
+
// Revoking should fail with RoleNotFound because the role is missing from ExistingRoles.
|
|
487
|
+
mock_auth(&env, &contract_id, &authorizer, "revoke_role", (acct.clone(), role.clone(), authorizer.clone()));
|
|
488
|
+
let res = client.try_revoke_role(&acct, &role, &authorizer);
|
|
489
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::RoleNotFound.into());
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// ============================================
|
|
493
|
+
// Remaining error codes: RoleIsEmpty, MaxRolesExceeded
|
|
494
|
+
// ============================================
|
|
495
|
+
|
|
496
|
+
#[test]
|
|
497
|
+
fn role_is_empty_error_code() {
|
|
498
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
499
|
+
|
|
500
|
+
let role = Symbol::new(&env, "ROLE8");
|
|
501
|
+
let acct = Address::generate(&env);
|
|
502
|
+
|
|
503
|
+
// Force: account appears to hold role (mapping exists), but count is 0 -> RoleIsEmpty.
|
|
504
|
+
client.raw_set_role_account_to_index(&role, &acct, &0);
|
|
505
|
+
|
|
506
|
+
mock_auth(&env, &contract_id, &authorizer, "revoke_role", (acct.clone(), role.clone(), authorizer.clone()));
|
|
507
|
+
let res = client.try_revoke_role(&acct, &role, &authorizer);
|
|
508
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::RoleIsEmpty.into());
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
#[test]
|
|
512
|
+
fn revoke_role_entrypoint_missing_role_returns_error_code() {
|
|
513
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
514
|
+
|
|
515
|
+
let role = Symbol::new(&env, "ROLE9");
|
|
516
|
+
let acct = Address::generate(&env);
|
|
517
|
+
|
|
518
|
+
// Provide auth so we reach the RoleNotHeld error (not Auth::InvalidAction).
|
|
519
|
+
mock_auth(&env, &contract_id, &authorizer, "revoke_role", (acct.clone(), role.clone(), authorizer.clone()));
|
|
520
|
+
let res = client.try_revoke_role(&acct, &role, &authorizer);
|
|
521
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::RoleNotHeld.into());
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
#[test]
|
|
525
|
+
fn revoke_role_entrypoint_unauthorized_returns_error_code() {
|
|
526
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
527
|
+
|
|
528
|
+
let role = Symbol::new(&env, "ROLE10");
|
|
529
|
+
let acct = Address::generate(&env);
|
|
530
|
+
let caller = Address::generate(&env);
|
|
531
|
+
|
|
532
|
+
// Role has an admin role, but caller has neither admin role nor is authorizer -> Unauthorized.
|
|
533
|
+
let admin_role = Symbol::new(&env, "ADMIN_X");
|
|
534
|
+
mock_auth(&env, &contract_id, &authorizer, "set_role_admin", (role.clone(), admin_role.clone()));
|
|
535
|
+
client.set_role_admin(&role, &admin_role);
|
|
536
|
+
|
|
537
|
+
mock_auth(&env, &contract_id, &caller, "revoke_role", (acct.clone(), role.clone(), caller.clone()));
|
|
538
|
+
let res = client.try_revoke_role(&acct, &role, &caller);
|
|
539
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::Unauthorized.into());
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
#[test]
|
|
543
|
+
fn max_roles_exceeded_error_code() {
|
|
544
|
+
let (env, contract_id, authorizer, client) = setup_contract();
|
|
545
|
+
|
|
546
|
+
let mut roles = Vec::<Symbol>::new(&env);
|
|
547
|
+
for i in 0..MAX_ROLES {
|
|
548
|
+
let s = std::format!("R{i}");
|
|
549
|
+
roles.push_back(Symbol::new(&env, &s));
|
|
550
|
+
}
|
|
551
|
+
client.raw_set_existing_roles(&roles);
|
|
552
|
+
|
|
553
|
+
let new_role = Symbol::new(&env, "NEW_ROLE");
|
|
554
|
+
let acct = Address::generate(&env);
|
|
555
|
+
|
|
556
|
+
mock_auth(&env, &contract_id, &authorizer, "grant_role", (acct.clone(), new_role.clone(), authorizer.clone()));
|
|
557
|
+
let res = client.try_grant_role(&acct, &new_role, &authorizer);
|
|
558
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), RbacError::MaxRolesExceeded.into());
|
|
559
|
+
}
|
|
@@ -2,8 +2,7 @@ extern crate std;
|
|
|
2
2
|
|
|
3
3
|
use crate::{
|
|
4
4
|
auth::Auth,
|
|
5
|
-
errors::{
|
|
6
|
-
option_ext::OptionExt,
|
|
5
|
+
errors::{AuthError, TtlConfigurableError},
|
|
7
6
|
ownable::{Ownable, OwnableInitializer},
|
|
8
7
|
testing_utils::assert_eq_event,
|
|
9
8
|
tests::test_helper::mock_auth,
|
|
@@ -103,8 +102,8 @@ impl TtlTestContract {
|
|
|
103
102
|
|
|
104
103
|
/// Auth implementation for test contract - uses the stored owner as authorizer.
|
|
105
104
|
impl Auth for TtlTestContract {
|
|
106
|
-
fn authorizer(env: &soroban_sdk::Env) -> Address {
|
|
107
|
-
<Self as Ownable>::owner(env)
|
|
105
|
+
fn authorizer(env: &soroban_sdk::Env) -> Option<Address> {
|
|
106
|
+
<Self as Ownable>::owner(env)
|
|
108
107
|
}
|
|
109
108
|
}
|
|
110
109
|
impl Ownable for TtlTestContract {}
|
|
@@ -437,7 +436,7 @@ fn test_default_ttl_configurable_freeze_when_owner_not_set() {
|
|
|
437
436
|
// Even with auth, `require_owner_auth` should fail because no owner is set in storage.
|
|
438
437
|
mock_auth(&env, &contract_id, &owner, "configurable_freeze_ttl_configs", ());
|
|
439
438
|
let res = client.try_configurable_freeze_ttl_configs();
|
|
440
|
-
assert_eq!(res.err().unwrap().ok().unwrap(),
|
|
439
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), AuthError::AuthorizerNotFound.into());
|
|
441
440
|
}
|
|
442
441
|
|
|
443
442
|
// ============================================
|
|
@@ -537,7 +536,7 @@ fn test_default_ttl_configurable_set_when_owner_not_set() {
|
|
|
537
536
|
// Even with auth, `require_owner_auth` should fail because no owner is set in storage.
|
|
538
537
|
mock_auth(&env, &contract_id, &owner, "configurable_set_ttl_configs", (&instance, &persistent));
|
|
539
538
|
let res = client.try_configurable_set_ttl_configs(&instance, &persistent);
|
|
540
|
-
assert_eq!(res.err().unwrap().ok().unwrap(),
|
|
539
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), AuthError::AuthorizerNotFound.into());
|
|
541
540
|
}
|
|
542
541
|
|
|
543
542
|
#[test]
|
|
@@ -316,9 +316,9 @@ use crate::auth::Auth;
|
|
|
316
316
|
|
|
317
317
|
// Implement Auth trait (required by Upgradeable) - self-owning pattern
|
|
318
318
|
impl Auth for DummyContract {
|
|
319
|
-
fn authorizer(env: &Env) -> Address {
|
|
319
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
320
320
|
// Return the contract's own address (self-owning pattern)
|
|
321
|
-
env.current_contract_address()
|
|
321
|
+
Some(env.current_contract_address())
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
@@ -341,8 +341,8 @@ impl Upgradeable for DummyContract {}
|
|
|
341
341
|
pub struct U32MigrationContract;
|
|
342
342
|
|
|
343
343
|
impl Auth for U32MigrationContract {
|
|
344
|
-
fn authorizer(env: &Env) -> Address {
|
|
345
|
-
env.current_contract_address()
|
|
344
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
345
|
+
Some(env.current_contract_address())
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
|
|
@@ -527,4 +527,3 @@ fn test_cannot_migrate_twice_without_upgrade() {
|
|
|
527
527
|
let result = client.try_migrate(&migration_data);
|
|
528
528
|
assert_eq!(result.err().unwrap().ok().unwrap(), UpgradeableError::MigrationNotAllowed.into());
|
|
529
529
|
}
|
|
530
|
-
|
|
@@ -32,7 +32,7 @@ pub trait Worker: Auth {
|
|
|
32
32
|
fn set_paused(env: &soroban_sdk::Env, paused: bool) {
|
|
33
33
|
assert_with_error!(env, Self::paused(env) != paused, WorkerError::PauseStatusUnchanged);
|
|
34
34
|
|
|
35
|
-
let authorizer = Self::authorizer(env);
|
|
35
|
+
let authorizer = Self::authorizer(env).unwrap();
|
|
36
36
|
WorkerStorage::set_paused(env, &paused);
|
|
37
37
|
if paused {
|
|
38
38
|
Paused { pauser: authorizer }.publish(env);
|