@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,20 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: contracts/common-macros/src/tests/auth.rs
|
|
3
|
+
assertion_line: 36
|
|
3
4
|
expression: combined
|
|
4
5
|
---
|
|
5
6
|
// === Unit struct ===
|
|
6
7
|
|
|
7
8
|
pub struct MyContract;
|
|
8
|
-
use utils::{
|
|
9
|
-
auth::Auth as _, option_ext::OptionExt as _,
|
|
10
|
-
ownable::{Ownable as _, OwnableInitializer as _},
|
|
11
|
-
};
|
|
9
|
+
use utils::{auth::Auth as _, ownable::{Ownable as _, OwnableInitializer as _}};
|
|
12
10
|
impl utils::ownable::OwnableInitializer for MyContract {}
|
|
13
11
|
#[common_macros::contract_impl]
|
|
14
12
|
impl utils::auth::Auth for MyContract {
|
|
15
|
-
fn authorizer(env: &soroban_sdk::Env) -> soroban_sdk::Address {
|
|
13
|
+
fn authorizer(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
16
14
|
<Self as utils::ownable::Ownable>::owner(env)
|
|
17
|
-
.unwrap_or_panic(env, utils::errors::OwnableError::OwnerNotSet)
|
|
18
15
|
}
|
|
19
16
|
}
|
|
20
17
|
#[common_macros::contract_impl(contracttrait)]
|
|
@@ -30,16 +27,12 @@ where
|
|
|
30
27
|
{
|
|
31
28
|
pub value: T,
|
|
32
29
|
}
|
|
33
|
-
use utils::{
|
|
34
|
-
auth::Auth as _, option_ext::OptionExt as _,
|
|
35
|
-
ownable::{Ownable as _, OwnableInitializer as _},
|
|
36
|
-
};
|
|
30
|
+
use utils::{auth::Auth as _, ownable::{Ownable as _, OwnableInitializer as _}};
|
|
37
31
|
impl utils::ownable::OwnableInitializer for MyContract {}
|
|
38
32
|
#[common_macros::contract_impl]
|
|
39
33
|
impl utils::auth::Auth for MyContract {
|
|
40
|
-
fn authorizer(env: &soroban_sdk::Env) -> soroban_sdk::Address {
|
|
34
|
+
fn authorizer(env: &soroban_sdk::Env) -> Option<soroban_sdk::Address> {
|
|
41
35
|
<Self as utils::ownable::Ownable>::owner(env)
|
|
42
|
-
.unwrap_or_panic(env, utils::errors::OwnableError::OwnerNotSet)
|
|
43
36
|
}
|
|
44
37
|
}
|
|
45
38
|
#[common_macros::contract_impl(contracttrait)]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
source: contracts/common-macros/src/tests/rbac.rs
|
|
3
|
+
expression: combined
|
|
4
|
+
---
|
|
5
|
+
// === has_role ===
|
|
6
|
+
|
|
7
|
+
pub fn mint(env: Env, caller: Address, amount: i128) {
|
|
8
|
+
utils::rbac::ensure_role(&env, &soroban_sdk::Symbol::new(&env, "minter"), &caller);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
// === only_role ===
|
|
13
|
+
|
|
14
|
+
pub fn mint(env: Env, caller: Address, amount: i128) {
|
|
15
|
+
utils::rbac::ensure_role(&env, &soroban_sdk::Symbol::new(&env, "minter"), &caller);
|
|
16
|
+
caller.require_auth();
|
|
17
|
+
}
|
|
@@ -27,7 +27,7 @@ fn exposes_ttl_and_ownable_features() {
|
|
|
27
27
|
// Ownable helper works.
|
|
28
28
|
let owner = Address::generate(&env);
|
|
29
29
|
client.init(&owner);
|
|
30
|
-
assert_eq!(client.authorizer(), owner);
|
|
30
|
+
assert_eq!(client.authorizer(), Some(owner));
|
|
31
31
|
|
|
32
32
|
// TTL-configurable read methods exist.
|
|
33
33
|
let _cfg = client.ttl_configs();
|
|
@@ -16,7 +16,7 @@ fn uses_self_owning_auth_and_exposes_ttl() {
|
|
|
16
16
|
|
|
17
17
|
// MultiSig auth => authorizer should be the contract address, without any init.
|
|
18
18
|
let expected = env.as_contract(&contract_id, || env.current_contract_address());
|
|
19
|
-
assert_eq!(client.authorizer(), expected);
|
|
19
|
+
assert_eq!(client.authorizer(), Some(expected));
|
|
20
20
|
|
|
21
21
|
// TTL-configurable read methods exist.
|
|
22
22
|
let _cfg = client.ttl_configs();
|
package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig_upgradeable.rs
CHANGED
|
@@ -30,7 +30,7 @@ fn self_auth_can_migrate_when_flag_set() {
|
|
|
30
30
|
|
|
31
31
|
// MultiSig auth => authorizer should be the contract address, without any init.
|
|
32
32
|
let expected = env.as_contract(&contract_id, || env.current_contract_address());
|
|
33
|
-
assert_eq!(client.authorizer(), expected);
|
|
33
|
+
assert_eq!(client.authorizer(), Some(expected));
|
|
34
34
|
|
|
35
35
|
// Unauthorized migrate should fail.
|
|
36
36
|
let unauthorized = client.try_migrate(&migration_data);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
use super::{TestContract, TestContractClient};
|
|
9
9
|
use soroban_sdk::{testutils::Address as _, Address, Env};
|
|
10
|
-
use utils::errors::OwnableError;
|
|
10
|
+
use utils::errors::{AuthError, OwnableError};
|
|
11
11
|
|
|
12
12
|
#[test]
|
|
13
13
|
fn init_and_query() {
|
|
@@ -52,9 +52,12 @@ fn uninitialized_returns_none() {
|
|
|
52
52
|
// No init() call - owner should be None
|
|
53
53
|
assert_eq!(client.owner(), None);
|
|
54
54
|
|
|
55
|
-
//
|
|
56
|
-
assert_eq!(client.
|
|
57
|
-
|
|
55
|
+
// authorizer() returns None when owner is not set (no panic)
|
|
56
|
+
assert_eq!(client.authorizer(), None);
|
|
57
|
+
|
|
58
|
+
// guarded() uses require_auth -> AuthorizerNotFound when authorizer is None
|
|
59
|
+
assert_eq!(client.try_guarded().unwrap_err().unwrap(), AuthError::AuthorizerNotFound.into());
|
|
60
|
+
// transfer/renounce use enforce_owner_auth -> OwnerNotSet when owner is None
|
|
58
61
|
assert_eq!(
|
|
59
62
|
client.try_transfer_ownership(&Address::generate(&env)).unwrap_err().unwrap(),
|
|
60
63
|
OwnableError::OwnerNotSet.into()
|
|
@@ -71,5 +74,5 @@ fn authorizer_returns_owner() {
|
|
|
71
74
|
let owner = Address::generate(&env);
|
|
72
75
|
client.init(&owner);
|
|
73
76
|
|
|
74
|
-
assert_eq!(client.authorizer(), owner);
|
|
77
|
+
assert_eq!(client.authorizer(), Some(owner));
|
|
75
78
|
}
|
|
@@ -10,7 +10,7 @@ use soroban_sdk::{
|
|
|
10
10
|
xdr::{ScErrorCode, ScErrorType},
|
|
11
11
|
Address, Env, Error, IntoVal,
|
|
12
12
|
};
|
|
13
|
-
use utils::errors::OwnableError;
|
|
13
|
+
use utils::errors::{AuthError, OwnableError};
|
|
14
14
|
use utils::ownable::{OwnershipRenounced, OwnershipTransferred};
|
|
15
15
|
use utils::testing_utils::assert_eq_event;
|
|
16
16
|
|
|
@@ -161,7 +161,7 @@ fn renounce_clears_owner() {
|
|
|
161
161
|
},
|
|
162
162
|
}])
|
|
163
163
|
.try_guarded();
|
|
164
|
-
assert_eq!(guarded_result.unwrap_err().unwrap(),
|
|
164
|
+
assert_eq!(guarded_result.unwrap_err().unwrap(), AuthError::AuthorizerNotFound.into());
|
|
165
165
|
|
|
166
166
|
assert_eq!(
|
|
167
167
|
client.try_transfer_ownership(&Address::generate(&env)).unwrap_err().unwrap(),
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
use super::{TestContract, TestContractClient};
|
|
2
|
+
use soroban_sdk::{
|
|
3
|
+
testutils::{Address as _, MockAuth, MockAuthInvoke},
|
|
4
|
+
xdr::{ScErrorCode, ScErrorType},
|
|
5
|
+
Address, Env, Error, IntoVal,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
#[test]
|
|
9
|
+
fn has_role_allows_member_and_rejects_non_member() {
|
|
10
|
+
let env = Env::default();
|
|
11
|
+
let contract_id = env.register(TestContract, ());
|
|
12
|
+
let client = TestContractClient::new(&env, &contract_id);
|
|
13
|
+
|
|
14
|
+
let admin = Address::generate(&env);
|
|
15
|
+
let minter = Address::generate(&env);
|
|
16
|
+
let other = Address::generate(&env);
|
|
17
|
+
|
|
18
|
+
client.init(&admin, &minter);
|
|
19
|
+
|
|
20
|
+
// Member call should succeed.
|
|
21
|
+
client.has_role_guarded(&minter);
|
|
22
|
+
|
|
23
|
+
// Non-member call should fail with RBAC Unauthorized.
|
|
24
|
+
let res = client.try_has_role_guarded(&other);
|
|
25
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), utils::errors::RbacError::Unauthorized.into());
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[test]
|
|
29
|
+
fn only_role_enforces_require_auth_and_role_membership() {
|
|
30
|
+
let env = Env::default();
|
|
31
|
+
let contract_id = env.register(TestContract, ());
|
|
32
|
+
let client = TestContractClient::new(&env, &contract_id);
|
|
33
|
+
|
|
34
|
+
let admin = Address::generate(&env);
|
|
35
|
+
let minter = Address::generate(&env);
|
|
36
|
+
let other = Address::generate(&env);
|
|
37
|
+
|
|
38
|
+
client.init(&admin, &minter);
|
|
39
|
+
|
|
40
|
+
// 1) Role holder without auth should fail at `require_auth()`.
|
|
41
|
+
let no_auth = client.try_only_role_guarded(&minter);
|
|
42
|
+
assert_eq!(
|
|
43
|
+
no_auth.unwrap_err().unwrap(),
|
|
44
|
+
Error::from_type_and_code(ScErrorType::Context, ScErrorCode::InvalidAction)
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// 2) With auth but role missing, should fail with RBAC Unauthorized.
|
|
48
|
+
let missing_role_with_auth = client
|
|
49
|
+
.mock_auths(&[MockAuth {
|
|
50
|
+
address: &other,
|
|
51
|
+
invoke: &MockAuthInvoke {
|
|
52
|
+
contract: &contract_id,
|
|
53
|
+
fn_name: "only_role_guarded",
|
|
54
|
+
args: (&other,).into_val(&env),
|
|
55
|
+
sub_invokes: &[],
|
|
56
|
+
},
|
|
57
|
+
}])
|
|
58
|
+
.try_only_role_guarded(&other);
|
|
59
|
+
assert_eq!(missing_role_with_auth.err().unwrap().ok().unwrap(), utils::errors::RbacError::Unauthorized.into());
|
|
60
|
+
|
|
61
|
+
// 3) With auth + role, should succeed.
|
|
62
|
+
client
|
|
63
|
+
.mock_auths(&[MockAuth {
|
|
64
|
+
address: &minter,
|
|
65
|
+
invoke: &MockAuthInvoke {
|
|
66
|
+
contract: &contract_id,
|
|
67
|
+
fn_name: "only_role_guarded",
|
|
68
|
+
args: (&minter,).into_val(&env),
|
|
69
|
+
sub_invokes: &[],
|
|
70
|
+
},
|
|
71
|
+
}])
|
|
72
|
+
.only_role_guarded(&minter);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#[test]
|
|
76
|
+
fn only_role_checks_role_before_require_auth() {
|
|
77
|
+
let env = Env::default();
|
|
78
|
+
let contract_id = env.register(TestContract, ());
|
|
79
|
+
let client = TestContractClient::new(&env, &contract_id);
|
|
80
|
+
|
|
81
|
+
let admin = Address::generate(&env);
|
|
82
|
+
let minter = Address::generate(&env);
|
|
83
|
+
let other = Address::generate(&env);
|
|
84
|
+
|
|
85
|
+
client.init(&admin, &minter);
|
|
86
|
+
|
|
87
|
+
// No auth, no role: current macro expansion checks role first, so this should
|
|
88
|
+
// return RBAC Unauthorized (not an auth error).
|
|
89
|
+
let res = client.try_only_role_guarded(&other);
|
|
90
|
+
assert_eq!(res.err().unwrap().ok().unwrap(), utils::errors::RbacError::Unauthorized.into());
|
|
91
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
use soroban_sdk::{contract, contractimpl, Address, Env, Symbol};
|
|
2
|
+
|
|
3
|
+
mod guard_behavior;
|
|
4
|
+
|
|
5
|
+
const MINTER_ROLE: &str = "minter";
|
|
6
|
+
|
|
7
|
+
#[contract]
|
|
8
|
+
pub struct TestContract;
|
|
9
|
+
|
|
10
|
+
#[contractimpl]
|
|
11
|
+
impl TestContract {
|
|
12
|
+
/// Test helper to deterministically grant the minter role to `minter`.
|
|
13
|
+
///
|
|
14
|
+
/// This is intentionally unguarded; it is only used in integration tests.
|
|
15
|
+
pub fn init(env: Env, admin: Address, minter: Address) {
|
|
16
|
+
let role = Symbol::new(&env, MINTER_ROLE);
|
|
17
|
+
utils::rbac::grant_role_no_auth(&env, &minter, &role, &admin);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[common_macros::has_role(caller, MINTER_ROLE)]
|
|
21
|
+
pub fn has_role_guarded(env: &Env, caller: Address) {
|
|
22
|
+
let _ = (env, caller);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[common_macros::only_role(caller, MINTER_ROLE)]
|
|
26
|
+
pub fn only_role_guarded(env: &Env, caller: Address) {
|
|
27
|
+
let _ = (env, caller);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
@@ -14,7 +14,7 @@ use soroban_sdk::{
|
|
|
14
14
|
};
|
|
15
15
|
use utils::testing_utils::assert_eq_event;
|
|
16
16
|
use utils::ttl_configurable::TtlConfigsSet;
|
|
17
|
-
use utils::{errors::{
|
|
17
|
+
use utils::{errors::{AuthError, TtlConfigurableError}, ttl_configurable::TtlConfig};
|
|
18
18
|
|
|
19
19
|
#[contract]
|
|
20
20
|
#[ttl_configurable]
|
|
@@ -98,7 +98,7 @@ fn set_before_init_fails_with_owner_not_set() {
|
|
|
98
98
|
let instance = Some(TtlConfig::new(1, 2));
|
|
99
99
|
let persistent = None::<TtlConfig>;
|
|
100
100
|
let err = client.try_set_ttl_configs(&instance, &persistent).unwrap_err().unwrap();
|
|
101
|
-
assert_eq!(err,
|
|
101
|
+
assert_eq!(err, AuthError::AuthorizerNotFound.into());
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
#[test]
|
package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs
CHANGED
|
@@ -14,7 +14,7 @@ use soroban_sdk::{
|
|
|
14
14
|
Address, Bytes, BytesN, Env, Error, IntoVal, Val,
|
|
15
15
|
};
|
|
16
16
|
use utils::upgradeable::{UpgradeableInternal, UpgradeableStorage};
|
|
17
|
-
use utils::errors::
|
|
17
|
+
use utils::errors::AuthError;
|
|
18
18
|
|
|
19
19
|
// A small, known-good contract WASM used for upgrade() testing.
|
|
20
20
|
// Sourced from the `upgrader` crate test fixtures.
|
|
@@ -192,10 +192,10 @@ fn upgrade_and_migrate_fail_before_owner_init() {
|
|
|
192
192
|
let contract_id = env.register(TestContract, ());
|
|
193
193
|
let client = TestContractClient::new(&env, &contract_id);
|
|
194
194
|
|
|
195
|
-
// Without owner initialization, authorizer lookup fails (
|
|
195
|
+
// Without owner initialization, authorizer lookup fails (AuthError::AuthorizerNotFound),
|
|
196
196
|
// which should surface as a contract error (not Context/InvalidAction).
|
|
197
197
|
let hash = BytesN::<32>::from_array(&env, &[7u8; 32]);
|
|
198
|
-
assert_eq!(client.try_upgrade(&hash).unwrap_err().unwrap(),
|
|
198
|
+
assert_eq!(client.try_upgrade(&hash).unwrap_err().unwrap(), AuthError::AuthorizerNotFound.into());
|
|
199
199
|
|
|
200
200
|
// Even if migrating is set, migrate() still fails before init because auth can't resolve authorizer.
|
|
201
201
|
env.as_contract(&contract_id, || {
|
|
@@ -204,7 +204,7 @@ fn upgrade_and_migrate_fail_before_owner_init() {
|
|
|
204
204
|
let migration_data = 1u32.to_xdr(&env);
|
|
205
205
|
assert_eq!(
|
|
206
206
|
client.try_migrate(&migration_data).unwrap_err().unwrap(),
|
|
207
|
-
|
|
207
|
+
AuthError::AuthorizerNotFound.into()
|
|
208
208
|
);
|
|
209
209
|
}
|
|
210
210
|
|
|
@@ -20,7 +20,7 @@ impl MyContract {
|
|
|
20
20
|
|
|
21
21
|
pub fn smoke(env: Env) {
|
|
22
22
|
// Auth impl exists (provided by ownable/multisig, here: ownable).
|
|
23
|
-
let _authorizer: Address = <Self as utils::auth::Auth>::authorizer(&env);
|
|
23
|
+
let _authorizer: Option<Address> = <Self as utils::auth::Auth>::authorizer(&env);
|
|
24
24
|
let _owner: Option<Address> = <Self as utils::ownable::Ownable>::owner(&env);
|
|
25
25
|
|
|
26
26
|
let _cfg: (Option<TtlConfig>, Option<TtlConfig>) = Self::ttl_configs(&env);
|
|
@@ -22,7 +22,7 @@ impl MyContract {
|
|
|
22
22
|
<Self as utils::ownable::OwnableInitializer>::init_owner(&env, &owner);
|
|
23
23
|
|
|
24
24
|
// Auth impl exists (type-check only).
|
|
25
|
-
let _authorizer: Address = <Self as utils::auth::Auth>::authorizer(&env);
|
|
25
|
+
let _authorizer: Option<Address> = <Self as utils::auth::Auth>::authorizer(&env);
|
|
26
26
|
|
|
27
27
|
// Ownable trait impl exists (type-check only).
|
|
28
28
|
let _owner: Option<Address> = <Self as utils::ownable::Ownable>::owner(&env);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// UI (trybuild) negative test: `#[has_role]` requires an `Env` parameter.
|
|
2
|
+
|
|
3
|
+
use soroban_sdk::{contract, contractimpl, Address};
|
|
4
|
+
|
|
5
|
+
#[contract]
|
|
6
|
+
pub struct MyContract;
|
|
7
|
+
|
|
8
|
+
#[contractimpl]
|
|
9
|
+
impl MyContract {
|
|
10
|
+
// Intentionally missing `Env`: should fail during macro expansion.
|
|
11
|
+
#[common_macros::has_role(caller, "minter")]
|
|
12
|
+
pub fn bad(caller: Address) {
|
|
13
|
+
let _ = caller;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn main() {}
|
|
18
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
error: custom attribute panicked
|
|
2
|
+
--> tests/ui/rbac/fail/missing_env.rs:11:5
|
|
3
|
+
|
|
|
4
|
+
11 | #[common_macros::has_role(caller, "minter")]
|
|
5
|
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
6
|
+
|
|
|
7
|
+
= help: message: function must have an Env argument
|
|
8
|
+
|
|
9
|
+
error[E0599]: no function or associated item named `bad` found for struct `MyContract` in the current scope
|
|
10
|
+
--> tests/ui/rbac/fail/missing_env.rs:12:12
|
|
11
|
+
|
|
|
12
|
+
6 | pub struct MyContract;
|
|
13
|
+
| --------------------- function or associated item `bad` not found for this struct
|
|
14
|
+
...
|
|
15
|
+
12 | pub fn bad(caller: Address) {
|
|
16
|
+
| ^^^ function or associated item not found in `MyContract`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// UI (trybuild) negative test: `#[has_role]` requires the named parameter to be `Address` or `&Address`.
|
|
2
|
+
|
|
3
|
+
use soroban_sdk::{contract, contractimpl, Env};
|
|
4
|
+
|
|
5
|
+
#[contract]
|
|
6
|
+
pub struct MyContract;
|
|
7
|
+
|
|
8
|
+
#[contractimpl]
|
|
9
|
+
impl MyContract {
|
|
10
|
+
// `caller` exists but is not an Address type.
|
|
11
|
+
#[common_macros::has_role(caller, "minter")]
|
|
12
|
+
pub fn bad(env: Env, caller: u32) {
|
|
13
|
+
let _ = (env, caller);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn main() {}
|
|
18
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
error: custom attribute panicked
|
|
2
|
+
--> tests/ui/rbac/fail/param_not_address.rs:11:5
|
|
3
|
+
|
|
|
4
|
+
11 | #[common_macros::has_role(caller, "minter")]
|
|
5
|
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
6
|
+
|
|
|
7
|
+
= help: message: Parameter `caller` must be of type `Address` or `&Address`
|
|
8
|
+
|
|
9
|
+
warning: unused import: `Env`
|
|
10
|
+
--> tests/ui/rbac/fail/param_not_address.rs:3:43
|
|
11
|
+
|
|
|
12
|
+
3 | use soroban_sdk::{contract, contractimpl, Env};
|
|
13
|
+
| ^^^
|
|
14
|
+
|
|
|
15
|
+
= note: `#[warn(unused_imports)]` on by default
|
|
16
|
+
|
|
17
|
+
error[E0599]: no function or associated item named `bad` found for struct `MyContract` in the current scope
|
|
18
|
+
--> tests/ui/rbac/fail/param_not_address.rs:12:12
|
|
19
|
+
|
|
|
20
|
+
6 | pub struct MyContract;
|
|
21
|
+
| --------------------- function or associated item `bad` not found for this struct
|
|
22
|
+
...
|
|
23
|
+
12 | pub fn bad(env: Env, caller: u32) {
|
|
24
|
+
| ^^^ function or associated item not found in `MyContract`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// UI (trybuild) negative test: `#[has_role]` requires the first arg to name a parameter in the signature.
|
|
2
|
+
|
|
3
|
+
use soroban_sdk::{contract, contractimpl, Address, Env};
|
|
4
|
+
|
|
5
|
+
#[contract]
|
|
6
|
+
pub struct MyContract;
|
|
7
|
+
|
|
8
|
+
#[contractimpl]
|
|
9
|
+
impl MyContract {
|
|
10
|
+
// Macro names `caller` but the signature uses `account`.
|
|
11
|
+
#[common_macros::has_role(caller, "minter")]
|
|
12
|
+
pub fn bad(env: Env, account: Address) {
|
|
13
|
+
let _ = (env, account);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn main() {}
|
|
18
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
error: custom attribute panicked
|
|
2
|
+
--> tests/ui/rbac/fail/param_not_found.rs:11:5
|
|
3
|
+
|
|
|
4
|
+
11 | #[common_macros::has_role(caller, "minter")]
|
|
5
|
+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
6
|
+
|
|
|
7
|
+
= help: message: Parameter `caller` not found in function signature
|
|
8
|
+
|
|
9
|
+
warning: unused import: `Env`
|
|
10
|
+
--> tests/ui/rbac/fail/param_not_found.rs:3:52
|
|
11
|
+
|
|
|
12
|
+
3 | use soroban_sdk::{contract, contractimpl, Address, Env};
|
|
13
|
+
| ^^^
|
|
14
|
+
|
|
|
15
|
+
= note: `#[warn(unused_imports)]` on by default
|
|
16
|
+
|
|
17
|
+
error[E0599]: no function or associated item named `bad` found for struct `MyContract` in the current scope
|
|
18
|
+
--> tests/ui/rbac/fail/param_not_found.rs:12:12
|
|
19
|
+
|
|
|
20
|
+
6 | pub struct MyContract;
|
|
21
|
+
| --------------------- function or associated item `bad` not found for this struct
|
|
22
|
+
...
|
|
23
|
+
12 | pub fn bad(env: Env, account: Address) {
|
|
24
|
+
| ^^^ function or associated item not found in `MyContract`
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// UI (trybuild) test: `#[has_role]` and `#[only_role]` compile for common signatures.
|
|
2
|
+
//
|
|
3
|
+
// Purpose:
|
|
4
|
+
// - Verifies the RBAC attribute macros can locate an `Env` argument anywhere in the signature.
|
|
5
|
+
// - Verifies both `Address` and `&Address` parameters are accepted.
|
|
6
|
+
// - Verifies role argument can be a literal or const expression.
|
|
7
|
+
|
|
8
|
+
use soroban_sdk::{contract, Address, Env};
|
|
9
|
+
|
|
10
|
+
const MINTER_ROLE: &str = "minter";
|
|
11
|
+
|
|
12
|
+
#[contract]
|
|
13
|
+
pub struct MyContract;
|
|
14
|
+
|
|
15
|
+
impl MyContract {
|
|
16
|
+
// Env by reference, Address by value, role literal.
|
|
17
|
+
#[common_macros::has_role(caller, "minter")]
|
|
18
|
+
pub fn f1(env: &Env, caller: Address) {
|
|
19
|
+
let _ = (env, caller);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Env by value, Address by value, role const expr.
|
|
23
|
+
#[common_macros::has_role(caller, MINTER_ROLE)]
|
|
24
|
+
pub fn f2(env: Env, caller: Address) {
|
|
25
|
+
let _ = (env, caller);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Env not first param, Address by value.
|
|
29
|
+
#[common_macros::has_role(caller, "minter")]
|
|
30
|
+
pub fn f3(x: u32, env: &Env, caller: Address) {
|
|
31
|
+
let _ = (x, env, caller);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// &Address param is accepted (forwarded without extra borrow).
|
|
35
|
+
#[common_macros::has_role(caller, "minter")]
|
|
36
|
+
pub fn f4(env: &Env, caller: &Address) {
|
|
37
|
+
let _ = (env, caller);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// only_role also injects `require_auth()`.
|
|
41
|
+
#[common_macros::only_role(caller, "minter")]
|
|
42
|
+
pub fn f5(env: &Env, caller: Address) {
|
|
43
|
+
let _ = (env, caller);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// only_role also injects `require_auth()`.
|
|
47
|
+
#[common_macros::only_role(caller, MINTER_ROLE)]
|
|
48
|
+
pub fn f6(env: &Env, caller: Address) {
|
|
49
|
+
let _ = (env, caller);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Env not first param (only_role).
|
|
53
|
+
#[common_macros::only_role(caller, "minter")]
|
|
54
|
+
pub fn f7(x: u32, env: &Env, caller: Address) {
|
|
55
|
+
let _ = (x, env, caller);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Qualified Env + Address types are accepted.
|
|
59
|
+
#[common_macros::has_role(caller, "minter")]
|
|
60
|
+
pub fn f8(env: &soroban_sdk::Env, caller: soroban_sdk::Address) {
|
|
61
|
+
let _ = (env, caller);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Fully-qualified Env path + qualified &Address.
|
|
65
|
+
#[common_macros::only_role(caller, MINTER_ROLE)]
|
|
66
|
+
pub fn f9(x: u32, env: ::soroban_sdk::Env, caller: &soroban_sdk::Address) {
|
|
67
|
+
let _ = (x, env, caller);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn main() {}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#[test]
|
|
2
|
+
fn ui_rbac() {
|
|
3
|
+
// Important: set this before trybuild::TestCases::new() so each shard has
|
|
4
|
+
// its own trybuild project directory + lock + artifacts.
|
|
5
|
+
let target_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("target/trybuild-shards/ui_rbac");
|
|
6
|
+
std::env::set_var("CARGO_TARGET_DIR", target_dir.as_os_str());
|
|
7
|
+
|
|
8
|
+
let t = trybuild::TestCases::new();
|
|
9
|
+
t.pass("tests/ui/rbac/**/pass/*.rs");
|
|
10
|
+
t.compile_fail("tests/ui/rbac/**/fail/*.rs");
|
|
11
|
+
}
|
|
12
|
+
|
|
@@ -8,7 +8,7 @@ use soroban_sdk::{contractclient, Address, Env};
|
|
|
8
8
|
/// for crediting; the OFT calls the token (SAC) directly for burn on debit.
|
|
9
9
|
#[contractclient(name = "MintableClient")]
|
|
10
10
|
pub trait Mintable {
|
|
11
|
-
/// Mints `amount` tokens to `to`. The `
|
|
11
|
+
/// Mints `amount` tokens to `to`. The `operator` address is the caller (e.g. OFT)
|
|
12
12
|
/// requesting the mint, for use by SAC wrappers that enforce authorization.
|
|
13
|
-
fn mint(env: &Env, to: &Address, amount: i128,
|
|
13
|
+
fn mint(env: &Env, to: &Address, amount: i128, operator: &Address);
|
|
14
14
|
}
|
|
@@ -17,8 +17,8 @@ use utils::auth::Auth;
|
|
|
17
17
|
struct FeeTestContract;
|
|
18
18
|
|
|
19
19
|
impl Auth for FeeTestContract {
|
|
20
|
-
fn authorizer(env: &Env) -> Address {
|
|
21
|
-
env.current_contract_address()
|
|
20
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
21
|
+
Some(env.current_contract_address())
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -12,8 +12,8 @@ use utils::auth::Auth;
|
|
|
12
12
|
struct PausableTestContract;
|
|
13
13
|
|
|
14
14
|
impl Auth for PausableTestContract {
|
|
15
|
-
fn authorizer(env: &Env) -> Address {
|
|
16
|
-
env.current_contract_address()
|
|
15
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
16
|
+
Some(env.current_contract_address())
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -15,8 +15,8 @@ use utils::auth::Auth;
|
|
|
15
15
|
struct RateLimiterTestContract;
|
|
16
16
|
|
|
17
17
|
impl Auth for RateLimiterTestContract {
|
|
18
|
-
fn authorizer(env: &Env) -> Address {
|
|
19
|
-
env.current_contract_address()
|
|
18
|
+
fn authorizer(env: &Env) -> Option<Address> {
|
|
19
|
+
Some(env.current_contract_address())
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -17,7 +17,6 @@ soroban-sdk = { workspace = true }
|
|
|
17
17
|
utils = { workspace = true }
|
|
18
18
|
common-macros = { workspace = true }
|
|
19
19
|
cfg-if = { workspace = true }
|
|
20
|
-
oft = { workspace = true, features = ["library"] }
|
|
21
20
|
|
|
22
21
|
[dev-dependencies]
|
|
23
22
|
soroban-sdk = { workspace = true, features = ["testutils"] }
|