@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.
Files changed (105) hide show
  1. package/.turbo/turbo-build.log +274 -268
  2. package/.turbo/turbo-lint.log +216 -213
  3. package/.turbo/turbo-test.log +1735 -1994
  4. package/contracts/common-macros/src/auth.rs +5 -5
  5. package/contracts/common-macros/src/lib.rs +69 -0
  6. package/contracts/common-macros/src/rbac.rs +90 -0
  7. package/contracts/common-macros/src/tests/lz_contract.rs +5 -7
  8. package/contracts/common-macros/src/tests/mod.rs +1 -0
  9. package/contracts/common-macros/src/tests/rbac.rs +420 -0
  10. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +4 -4
  11. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +5 -12
  12. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__rbac__snapshot_preserve_function_signature.snap +17 -0
  13. package/contracts/common-macros/src/tests/storage/parse_name.rs +0 -1
  14. package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_default.rs +1 -1
  15. package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig.rs +1 -1
  16. package/contracts/macro-integration-tests/tests/runtime/lz_contract/wrapper_multisig_upgradeable.rs +1 -1
  17. package/contracts/macro-integration-tests/tests/runtime/multisig/self_auth.rs +1 -1
  18. package/contracts/macro-integration-tests/tests/runtime/ownable/initialization.rs +8 -5
  19. package/contracts/macro-integration-tests/tests/runtime/ownable/ownership_transfer.rs +2 -2
  20. package/contracts/macro-integration-tests/tests/runtime/rbac/guard_behavior.rs +91 -0
  21. package/contracts/macro-integration-tests/tests/runtime/rbac/mod.rs +30 -0
  22. package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/configuration.rs +2 -2
  23. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +4 -4
  24. package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/basic.rs +1 -1
  25. package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
  26. package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.rs +18 -0
  27. package/contracts/macro-integration-tests/tests/ui/rbac/fail/missing_env.stderr +16 -0
  28. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.rs +18 -0
  29. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_address.stderr +24 -0
  30. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.rs +18 -0
  31. package/contracts/macro-integration-tests/tests/ui/rbac/fail/param_not_found.stderr +24 -0
  32. package/contracts/macro-integration-tests/tests/ui/rbac/pass/basic.rs +71 -0
  33. package/contracts/macro-integration-tests/tests/ui_rbac.rs +12 -0
  34. package/contracts/oapps/oft/src/interfaces/mintable.rs +2 -2
  35. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +2 -2
  36. package/contracts/oapps/oft/src/tests/extensions/pausable.rs +2 -2
  37. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +2 -2
  38. package/contracts/oapps/sac-manager/Cargo.toml +0 -1
  39. package/contracts/oapps/sac-manager/src/interfaces/mod.rs +3 -0
  40. package/contracts/oapps/sac-manager/src/interfaces/sac_admin_wrapper.rs +49 -0
  41. package/contracts/oapps/sac-manager/src/lib.rs +3 -3
  42. package/contracts/oapps/sac-manager/src/sac_manager.rs +45 -73
  43. package/contracts/oapps/sac-manager/src/storage.rs +2 -9
  44. package/contracts/oapps/sac-manager/src/tests/sac_manager/clawback.rs +8 -10
  45. package/contracts/oapps/sac-manager/src/tests/sac_manager/mint.rs +13 -18
  46. package/contracts/oapps/sac-manager/src/tests/sac_manager/mod.rs +0 -1
  47. package/contracts/oapps/sac-manager/src/tests/sac_manager/set_admin.rs +22 -12
  48. package/contracts/oapps/sac-manager/src/tests/sac_manager/set_authorized.rs +19 -9
  49. package/contracts/oapps/sac-manager/src/tests/sac_manager/test_helper.rs +27 -10
  50. package/contracts/oapps/sac-manager/src/tests/sac_manager/view_functions.rs +0 -15
  51. package/contracts/oapps/sac-manager/src/tests/test_helper.rs +19 -28
  52. package/contracts/upgrader/src/lib.rs +5 -2
  53. package/contracts/utils/src/auth.rs +6 -2
  54. package/contracts/utils/src/errors.rs +18 -0
  55. package/contracts/utils/src/lib.rs +1 -0
  56. package/contracts/utils/src/multisig.rs +5 -1
  57. package/contracts/utils/src/ownable.rs +1 -1
  58. package/contracts/utils/src/rbac.rs +428 -0
  59. package/contracts/utils/src/tests/auth.rs +2 -2
  60. package/contracts/utils/src/tests/mod.rs +1 -0
  61. package/contracts/utils/src/tests/multisig.rs +2 -2
  62. package/contracts/utils/src/tests/ownable.rs +4 -5
  63. package/contracts/utils/src/tests/rbac.rs +559 -0
  64. package/contracts/utils/src/tests/ttl_configurable.rs +5 -6
  65. package/contracts/utils/src/tests/upgradeable.rs +4 -5
  66. package/contracts/workers/worker/src/worker.rs +1 -1
  67. package/package.json +3 -3
  68. package/sdk/.turbo/turbo-test.log +368 -366
  69. package/sdk/dist/generated/bml.d.ts +53 -3
  70. package/sdk/dist/generated/bml.js +27 -3
  71. package/sdk/dist/generated/counter.d.ts +55 -5
  72. package/sdk/dist/generated/counter.js +28 -4
  73. package/sdk/dist/generated/dvn.d.ts +55 -5
  74. package/sdk/dist/generated/dvn.js +28 -4
  75. package/sdk/dist/generated/dvn_fee_lib.d.ts +55 -5
  76. package/sdk/dist/generated/dvn_fee_lib.js +28 -4
  77. package/sdk/dist/generated/endpoint.d.ts +55 -5
  78. package/sdk/dist/generated/endpoint.js +28 -4
  79. package/sdk/dist/generated/executor.d.ts +55 -5
  80. package/sdk/dist/generated/executor.js +28 -4
  81. package/sdk/dist/generated/executor_fee_lib.d.ts +55 -5
  82. package/sdk/dist/generated/executor_fee_lib.js +28 -4
  83. package/sdk/dist/generated/executor_helper.d.ts +53 -3
  84. package/sdk/dist/generated/executor_helper.js +27 -3
  85. package/sdk/dist/generated/layerzero_view.d.ts +55 -5
  86. package/sdk/dist/generated/layerzero_view.js +28 -4
  87. package/sdk/dist/generated/oft.d.ts +55 -5
  88. package/sdk/dist/generated/oft.js +28 -4
  89. package/sdk/dist/generated/price_feed.d.ts +55 -5
  90. package/sdk/dist/generated/price_feed.js +28 -4
  91. package/sdk/dist/generated/sac_manager.d.ts +213 -687
  92. package/sdk/dist/generated/sac_manager.js +57 -239
  93. package/sdk/dist/generated/sml.d.ts +55 -5
  94. package/sdk/dist/generated/sml.js +28 -4
  95. package/sdk/dist/generated/treasury.d.ts +55 -5
  96. package/sdk/dist/generated/treasury.js +28 -4
  97. package/sdk/dist/generated/uln302.d.ts +55 -5
  98. package/sdk/dist/generated/uln302.js +28 -4
  99. package/sdk/dist/generated/upgrader.d.ts +53 -3
  100. package/sdk/dist/generated/upgrader.js +27 -3
  101. package/sdk/package.json +1 -1
  102. package/sdk/test/oft-sml.test.ts +10 -9
  103. package/sdk/test/{sac-manager-redistribution.test.ts → sac-manager.test.ts} +49 -25
  104. package/contracts/oapps/sac-manager/src/errors.rs +0 -14
  105. 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
+ }
@@ -156,4 +156,3 @@ fn test_parses_name_with_special_chars() {
156
156
  let name = result.unwrap();
157
157
  assert_eq!(name, Some("key_v2_beta".to_string()));
158
158
  }
159
-
@@ -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();
@@ -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);
@@ -19,7 +19,7 @@ fn authorizer_is_current_contract_address() {
19
19
 
20
20
  let expected = env.as_contract(&contract_id, || env.current_contract_address());
21
21
  let got = client.authorizer();
22
- assert_eq!(got, expected);
22
+ assert_eq!(got, Some(expected));
23
23
  }
24
24
 
25
25
  #[test]
@@ -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
- // All owner-protected operations should fail
56
- assert_eq!(client.try_authorizer().unwrap_err().unwrap(), OwnableError::OwnerNotSet.into());
57
- assert_eq!(client.try_guarded().unwrap_err().unwrap(), OwnableError::OwnerNotSet.into());
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(), OwnableError::OwnerNotSet.into());
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::{OwnableError, TtlConfigurableError}, ttl_configurable::TtlConfig};
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, OwnableError::OwnerNotSet.into());
101
+ assert_eq!(err, AuthError::AuthorizerNotFound.into());
102
102
  }
103
103
 
104
104
  #[test]
@@ -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::OwnableError;
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 (OwnableError::OwnerNotSet),
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(), OwnableError::OwnerNotSet.into());
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
- OwnableError::OwnerNotSet.into()
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 `operation` address is the caller (e.g. OFT)
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, operation: &Address);
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"] }
@@ -0,0 +1,3 @@
1
+ mod sac_admin_wrapper;
2
+
3
+ pub use sac_admin_wrapper::{SACAdminWrapper, SACAdminWrapperClient};