@layerzerolabs/protocol-stellar-v2 0.2.39 → 0.2.41

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 (114) hide show
  1. package/.turbo/turbo-build.log +226 -313
  2. package/.turbo/turbo-lint.log +98 -227
  3. package/.turbo/turbo-test.log +1803 -1954
  4. package/contracts/common-macros/src/lib.rs +38 -15
  5. package/contracts/common-macros/src/lz_contract.rs +12 -21
  6. package/contracts/common-macros/src/tests/lz_contract.rs +17 -8
  7. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__lz_contract__snapshot_generated_lz_contract_code.snap +20 -0
  8. package/contracts/common-macros/src/upgradeable.rs +37 -30
  9. package/contracts/endpoint-v2/src/endpoint_v2.rs +4 -3
  10. package/contracts/endpoint-v2/src/errors.rs +2 -2
  11. package/contracts/endpoint-v2/src/messaging_channel.rs +11 -0
  12. package/contracts/endpoint-v2/src/messaging_composer.rs +1 -0
  13. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -25
  14. package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +4 -4
  15. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +50 -10
  16. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +6 -35
  17. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +2 -2
  18. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +50 -1
  19. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +78 -0
  20. package/contracts/endpoint-v2/src/tests/messaging_channel/insert_and_drain_pending_nonces.rs +272 -0
  21. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -0
  22. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +10 -5
  23. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +30 -0
  24. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +22 -1
  25. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +13 -11
  26. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +13 -10
  27. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +15 -11
  28. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +3 -2
  29. package/contracts/macro-integration-tests/tests/runtime/ownable/two_step_transfer.rs +14 -12
  30. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +3 -9
  31. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.stderr +24 -1
  32. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +3 -3
  33. package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/upgradeable_rbac.rs +44 -0
  34. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +3 -0
  35. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +3 -0
  36. package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
  37. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/attr_args.stderr +1 -1
  38. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +2 -2
  39. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +2 -2
  40. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/rbac.rs +44 -0
  41. package/contracts/oapps/counter/integration_tests/utils.rs +5 -3
  42. package/contracts/oapps/counter/src/tests/mod.rs +16 -1
  43. package/contracts/oapps/counter/src/tests/test_counter.rs +5 -2
  44. package/contracts/oapps/oapp/src/oapp_core.rs +21 -7
  45. package/contracts/oapps/oapp/src/oapp_options_type3.rs +7 -5
  46. package/contracts/oapps/oapp/src/tests/mod.rs +21 -0
  47. package/contracts/oapps/oapp/src/tests/oapp_core.rs +12 -10
  48. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +11 -7
  49. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +4 -2
  50. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +3 -2
  51. package/contracts/oapps/oapp/src/tests/test_macros.rs +15 -0
  52. package/contracts/oapps/oapp-macros/src/generators.rs +6 -0
  53. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +15 -0
  54. package/contracts/oapps/oft/integration-tests/setup.rs +22 -4
  55. package/contracts/oapps/oft/integration-tests/utils.rs +94 -13
  56. package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -10
  57. package/contracts/oapps/oft/src/extensions/pausable.rs +31 -10
  58. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +9 -4
  59. package/contracts/oapps/oft/src/oft.rs +1 -2
  60. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +39 -27
  61. package/contracts/oapps/oft/src/tests/extensions/pausable.rs +38 -24
  62. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +87 -69
  63. package/contracts/oapps/oft-core/integration-tests/setup.rs +27 -3
  64. package/contracts/oapps/oft-core/src/oft_core.rs +10 -5
  65. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +20 -20
  66. package/contracts/oapps/oft-core/src/tests/test_utils.rs +31 -3
  67. package/contracts/upgrader/src/lib.rs +67 -30
  68. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract3.wasm +0 -0
  69. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract4.wasm +0 -0
  70. package/contracts/upgrader/src/tests/test_upgrader.rs +50 -4
  71. package/contracts/utils/src/ownable.rs +16 -5
  72. package/contracts/utils/src/tests/ownable.rs +39 -39
  73. package/contracts/utils/src/upgradeable.rs +60 -17
  74. package/docs/oapp-guide.md +4 -4
  75. package/package.json +3 -4
  76. package/sdk/.turbo/turbo-test.log +381 -366
  77. package/sdk/dist/generated/bml.d.ts +4 -4
  78. package/sdk/dist/generated/bml.js +6 -6
  79. package/sdk/dist/generated/counter.d.ts +158 -12
  80. package/sdk/dist/generated/counter.js +32 -12
  81. package/sdk/dist/generated/dvn.d.ts +4 -6
  82. package/sdk/dist/generated/dvn.js +8 -8
  83. package/sdk/dist/generated/dvn_fee_lib.d.ts +8 -10
  84. package/sdk/dist/generated/dvn_fee_lib.js +8 -8
  85. package/sdk/dist/generated/endpoint.d.ts +9 -9
  86. package/sdk/dist/generated/endpoint.js +9 -9
  87. package/sdk/dist/generated/executor.d.ts +9 -11
  88. package/sdk/dist/generated/executor.js +11 -11
  89. package/sdk/dist/generated/executor_fee_lib.d.ts +9 -11
  90. package/sdk/dist/generated/executor_fee_lib.js +11 -11
  91. package/sdk/dist/generated/executor_helper.d.ts +4 -4
  92. package/sdk/dist/generated/executor_helper.js +6 -6
  93. package/sdk/dist/generated/layerzero_view.d.ts +9 -11
  94. package/sdk/dist/generated/layerzero_view.js +11 -11
  95. package/sdk/dist/generated/oft.d.ts +194 -27
  96. package/sdk/dist/generated/oft.js +44 -22
  97. package/sdk/dist/generated/price_feed.d.ts +8 -10
  98. package/sdk/dist/generated/price_feed.js +8 -8
  99. package/sdk/dist/generated/sac_manager.d.ts +8 -8
  100. package/sdk/dist/generated/sac_manager.js +6 -6
  101. package/sdk/dist/generated/sml.d.ts +9 -9
  102. package/sdk/dist/generated/sml.js +9 -9
  103. package/sdk/dist/generated/treasury.d.ts +9 -9
  104. package/sdk/dist/generated/treasury.js +9 -9
  105. package/sdk/dist/generated/uln302.d.ts +9 -9
  106. package/sdk/dist/generated/uln302.js +9 -9
  107. package/sdk/dist/generated/upgrader.d.ts +25 -16
  108. package/sdk/dist/generated/upgrader.js +5 -5
  109. package/sdk/package.json +1 -1
  110. package/sdk/test/counter-sml.test.ts +20 -0
  111. package/sdk/test/counter-uln.test.ts +20 -0
  112. package/sdk/test/oft-sml.test.ts +22 -0
  113. package/sdk/test/upgrader.test.ts +1 -0
  114. package/turbo.json +1 -8
@@ -0,0 +1,44 @@
1
+ // UI (trybuild) test: `#[upgradeable(rbac)]` compiles with UpgradeableRbac.
2
+ //
3
+ // Purpose:
4
+ // - Ensures the macro generates `impl UpgradeableRbac` when `rbac` is specified.
5
+ // - Verifies upgrade/migrate take the extra `operator` parameter.
6
+
7
+ use soroban_sdk::{contract, contractimpl, Address, Bytes, BytesN, Env};
8
+ use utils::rbac::{grant_role_no_auth, RoleBasedAccessControl};
9
+ use utils::upgradeable::{UpgradeableInternal, UPGRADER_ROLE};
10
+
11
+ #[contract]
12
+ #[common_macros::ownable]
13
+ #[common_macros::upgradeable(rbac)]
14
+ pub struct MyContract;
15
+
16
+ impl UpgradeableInternal for MyContract {
17
+ type MigrationData = ();
18
+
19
+ fn __migrate(_env: &Env, _migration_data: &Self::MigrationData) {}
20
+ }
21
+
22
+ #[contractimpl(contracttrait)]
23
+ impl RoleBasedAccessControl for MyContract {}
24
+
25
+ #[contractimpl]
26
+ impl MyContract {
27
+ pub fn init(env: Env, owner: Address) {
28
+ Self::init_owner(&env, &owner);
29
+ }
30
+
31
+ pub fn init_upgrader(env: Env, operator: Address) {
32
+ let upgrader_role = soroban_sdk::Symbol::new(&env, UPGRADER_ROLE);
33
+ grant_role_no_auth(&env, &operator, &upgrader_role, &env.current_contract_address());
34
+ }
35
+
36
+ pub fn smoke(env: Env, operator: Address) {
37
+ let hash = BytesN::<32>::from_array(&env, &[0u8; 32]);
38
+ let migration_data = Bytes::new(&env);
39
+ Self::upgrade(&env, &hash, &operator);
40
+ Self::migrate(&env, &migration_data, &operator);
41
+ }
42
+ }
43
+
44
+ fn main() {}
@@ -2,7 +2,7 @@
2
2
 
3
3
  extern crate std;
4
4
 
5
- use crate::{codec::MsgType, counter::CounterClient, tests::mint_to};
5
+ use crate::{codec::MsgType, counter::CounterClient, tests::{grant_oapp_admin, mint_to}};
6
6
  use endpoint_v2::{EndpointV2Client, MessagingFee, Origin, OutboundPacket};
7
7
  use message_lib_common::packet_codec_v1;
8
8
  use soroban_sdk::{
@@ -63,17 +63,19 @@ pub fn register_library(env: &Env, owner: &Address, endpoint: &EndpointV2Client<
63
63
 
64
64
  /// Sets the peer address for a counter on a destination EID.
65
65
  pub fn set_peer(env: &Env, owner: &Address, counter: &CounterClient<'_>, dst_eid: u32, peer: &BytesN<32>) {
66
+ grant_oapp_admin(env, &counter.address, owner);
67
+
66
68
  let peer_option = Some(peer.clone());
67
69
  env.mock_auths(&[MockAuth {
68
70
  address: owner,
69
71
  invoke: &MockAuthInvoke {
70
72
  contract: &counter.address,
71
73
  fn_name: "set_peer",
72
- args: (&dst_eid, &peer_option).into_val(env),
74
+ args: (&dst_eid, &peer_option, owner).into_val(env),
73
75
  sub_invokes: &[],
74
76
  },
75
77
  }]);
76
- counter.set_peer(&dst_eid, &peer_option);
78
+ counter.set_peer(&dst_eid, &peer_option, owner);
77
79
  }
78
80
 
79
81
  /// Decodes an outbound packet emitted by the endpoint.
@@ -1,7 +1,8 @@
1
+ use oapp::oapp_core::OAPP_ADMIN_ROLE;
1
2
  use soroban_sdk::{
2
3
  testutils::{MockAuth, MockAuthInvoke},
3
4
  token::StellarAssetClient,
4
- Address, Env, IntoVal,
5
+ Address, Env, IntoVal, Symbol,
5
6
  };
6
7
 
7
8
  pub mod test_codec;
@@ -23,3 +24,17 @@ pub fn mint_to(env: &Env, owner: &Address, native_token: &Address, to: &Address,
23
24
  sac.mint(to, &amount);
24
25
  }
25
26
 
27
+ pub fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
28
+ let role = Symbol::new(env, OAPP_ADMIN_ROLE);
29
+ env.mock_auths(&[MockAuth {
30
+ address: owner,
31
+ invoke: &MockAuthInvoke {
32
+ contract,
33
+ fn_name: "grant_role",
34
+ args: (owner, &role, owner).into_val(env),
35
+ sub_invokes: &[],
36
+ },
37
+ }]);
38
+ utils::rbac::RoleBasedAccessControlClient::new(env, contract).grant_role(owner, &role, owner);
39
+ }
40
+
@@ -88,17 +88,20 @@ fn setup<'a>() -> TestSetup<'a> {
88
88
  }
89
89
 
90
90
  fn setup_mock_peer(env: &Env, owner: &Address, counter: &CounterClient<'_>, dst_eid: u32) -> BytesN<32> {
91
+ super::grant_oapp_admin(env, &counter.address, owner);
92
+
91
93
  let peer = BytesN::from_array(env, &[1u8; 32]);
94
+ let peer_option = Some(peer.clone());
92
95
  env.mock_auths(&[MockAuth {
93
96
  address: owner,
94
97
  invoke: &MockAuthInvoke {
95
98
  contract: &counter.address,
96
99
  fn_name: "set_peer",
97
- args: (&dst_eid, &Some(peer.clone())).into_val(env),
100
+ args: (&dst_eid, &peer_option, owner).into_val(env),
98
101
  sub_invokes: &[],
99
102
  },
100
103
  }]);
101
- counter.set_peer(&dst_eid, &Some(peer.clone()));
104
+ counter.set_peer(&dst_eid, &peer_option, owner);
102
105
  peer
103
106
  }
104
107
 
@@ -1,8 +1,15 @@
1
1
  use crate::{errors::OAppError, oapp_receiver::RECEIVER_VERSION, oapp_sender::SENDER_VERSION};
2
- use common_macros::{contract_trait, only_auth, storage};
2
+ use common_macros::{contract_trait, only_role, storage};
3
3
  use endpoint_v2::LayerZeroEndpointV2Client;
4
4
  use soroban_sdk::{contractevent, Address, BytesN, Env};
5
- use utils::{option_ext::OptionExt, ownable::{Ownable, OwnableInitializer}};
5
+ use utils::{
6
+ option_ext::OptionExt,
7
+ ownable::{Ownable, OwnableInitializer},
8
+ rbac::RoleBasedAccessControl,
9
+ };
10
+
11
+ /// Role for OApp administrative actions (set_peer, set_delegate, set_enforced_options).
12
+ pub const OAPP_ADMIN_ROLE: &str = "OAPP_ADMIN_ROLE";
6
13
 
7
14
  // =====================================================
8
15
  // OAppCore Storage and Events
@@ -31,7 +38,7 @@ pub struct PeerSet {
31
38
  // =====================================================
32
39
 
33
40
  #[contract_trait]
34
- pub trait OAppCore: Ownable {
41
+ pub trait OAppCore: Ownable + RoleBasedAccessControl {
35
42
  /// Retrieves the OApp version information.
36
43
  ///
37
44
  /// # Returns
@@ -66,8 +73,14 @@ pub trait OAppCore: Ownable {
66
73
  /// # Arguments
67
74
  /// * `eid` - The endpoint ID
68
75
  /// * `peer` - The address of the peer to be associated with the corresponding endpoint, or None to remove the peer
69
- #[only_auth]
70
- fn set_peer(env: &soroban_sdk::Env, eid: u32, peer: &Option<soroban_sdk::BytesN<32>>) {
76
+ /// * `operator` - The address that must have OAPP_ADMIN_ROLE
77
+ #[only_role(operator, OAPP_ADMIN_ROLE)]
78
+ fn set_peer(
79
+ env: &soroban_sdk::Env,
80
+ eid: u32,
81
+ peer: &Option<soroban_sdk::BytesN<32>>,
82
+ operator: &soroban_sdk::Address,
83
+ ) {
71
84
  OAppCoreStorage::set_or_remove_peer(env, eid, peer);
72
85
  PeerSet { eid, peer: peer.clone() }.publish(env);
73
86
  }
@@ -76,8 +89,9 @@ pub trait OAppCore: Ownable {
76
89
  ///
77
90
  /// # Arguments
78
91
  /// * `delegate` - The address of the delegate to be set, or None to remove the delegate
79
- #[only_auth]
80
- fn set_delegate(env: &soroban_sdk::Env, delegate: &Option<soroban_sdk::Address>) {
92
+ /// * `operator` - The address that must have OAPP_ADMIN_ROLE
93
+ #[only_role(operator, OAPP_ADMIN_ROLE)]
94
+ fn set_delegate(env: &soroban_sdk::Env, delegate: &Option<soroban_sdk::Address>, operator: &soroban_sdk::Address) {
81
95
  endpoint_client::<Self>(env).set_delegate(&env.current_contract_address(), delegate);
82
96
  }
83
97
  }
@@ -1,7 +1,7 @@
1
- use crate::{self as oapp, errors::OAppError};
2
- use common_macros::{contract_trait, only_auth, storage};
1
+ use crate::{self as oapp, errors::OAppError, oapp_core::OAPP_ADMIN_ROLE};
2
+ use common_macros::{contract_trait, only_role, storage};
3
3
  use soroban_sdk::{assert_with_error, contractevent, contracttype, panic_with_error, Bytes, Env, Vec};
4
- use utils::{auth::Auth, buffer_reader::BufferReader};
4
+ use utils::{buffer_reader::BufferReader, rbac::RoleBasedAccessControl};
5
5
 
6
6
  pub const OPTION_TYPE3: u16 = 3;
7
7
 
@@ -30,7 +30,7 @@ pub struct EnforcedOptionSet {
30
30
  // =========================================================================
31
31
 
32
32
  #[contract_trait]
33
- pub trait OAppOptionsType3: Auth {
33
+ pub trait OAppOptionsType3: RoleBasedAccessControl {
34
34
  /// Retrieves the enforced options for a given endpoint and message type.
35
35
  ///
36
36
  /// # Arguments
@@ -53,10 +53,12 @@ pub trait OAppOptionsType3: Auth {
53
53
  ///
54
54
  /// # Arguments
55
55
  /// * `options` - A vector of EnforcedOptionParam structures specifying enforced options
56
- #[only_auth]
56
+ /// * `operator` - The address that must have OAPP_ADMIN_ROLE
57
+ #[only_role(operator, OAPP_ADMIN_ROLE)]
57
58
  fn set_enforced_options(
58
59
  env: &soroban_sdk::Env,
59
60
  options: &soroban_sdk::Vec<oapp::oapp_options_type3::EnforcedOptionParam>,
61
+ operator: &soroban_sdk::Address,
60
62
  ) {
61
63
  for param in options {
62
64
  if let Some(ref opts) = param.options {
@@ -3,3 +3,24 @@ mod oapp_options_type3;
3
3
  mod oapp_receiver;
4
4
  mod oapp_sender;
5
5
  mod test_macros;
6
+
7
+ use crate::oapp_core::OAPP_ADMIN_ROLE;
8
+ use soroban_sdk::{
9
+ testutils::{MockAuth, MockAuthInvoke},
10
+ Address, Env, IntoVal, Symbol,
11
+ };
12
+
13
+ /// Grants `OAPP_ADMIN_ROLE` to `owner` via the public `grant_role` interface.
14
+ pub(super) fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
15
+ let role = Symbol::new(env, OAPP_ADMIN_ROLE);
16
+ env.mock_auths(&[MockAuth {
17
+ address: owner,
18
+ invoke: &MockAuthInvoke {
19
+ contract,
20
+ fn_name: "grant_role",
21
+ args: (owner, &role, owner).into_val(env),
22
+ sub_invokes: &[],
23
+ },
24
+ }]);
25
+ utils::rbac::RoleBasedAccessControlClient::new(env, contract).grant_role(owner, &role, owner);
26
+ }
@@ -75,6 +75,8 @@ fn setup<'a>() -> TestSetup<'a> {
75
75
  let oapp = env.register(DummyOApp, (&owner, &endpoint));
76
76
  soroban_sdk::log!(&env, "oapp: {}", oapp);
77
77
  let oapp_client = DummyOAppClient::new(&env, &oapp);
78
+ super::grant_oapp_admin(&env, &oapp, &owner);
79
+
78
80
  TestSetup { env, owner, endpoint, oapp_client }
79
81
  }
80
82
 
@@ -90,11 +92,11 @@ fn set_peer_with_auth(
90
92
  invoke: &MockAuthInvoke {
91
93
  contract: &oapp_client.address,
92
94
  fn_name: "set_peer",
93
- args: (&eid, peer).into_val(env),
95
+ args: (&eid, peer, signer).into_val(env),
94
96
  sub_invokes: &[],
95
97
  },
96
98
  }]);
97
- oapp_client.set_peer(&eid, peer);
99
+ oapp_client.set_peer(&eid, peer, signer);
98
100
  }
99
101
 
100
102
  fn set_delegate_with_auth(env: &Env, signer: &Address, oapp_client: &DummyOAppClient<'_>, delegate: &Option<Address>) {
@@ -103,11 +105,11 @@ fn set_delegate_with_auth(env: &Env, signer: &Address, oapp_client: &DummyOAppCl
103
105
  invoke: &MockAuthInvoke {
104
106
  contract: &oapp_client.address,
105
107
  fn_name: "set_delegate",
106
- args: (delegate,).into_val(env),
108
+ args: (delegate, signer).into_val(env),
107
109
  sub_invokes: &[],
108
110
  },
109
111
  }]);
110
- oapp_client.set_delegate(delegate);
112
+ oapp_client.set_delegate(delegate, signer);
111
113
  }
112
114
 
113
115
  #[test]
@@ -166,14 +168,14 @@ fn test_peer_lifecycle_set_get_update_remove_and_events() {
166
168
  #[test]
167
169
  #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
168
170
  fn test_set_peer_unauthorized() {
169
- let TestSetup { env, oapp_client, .. } = setup();
171
+ let TestSetup { env, owner, oapp_client, .. } = setup();
170
172
 
171
173
  let test_peer: BytesN<32> = BytesN::from_array(&env, &[33; 32]);
172
- oapp_client.set_peer(&REMOTE_EID, &Some(test_peer));
174
+ oapp_client.set_peer(&REMOTE_EID, &Some(test_peer), &owner);
173
175
  }
174
176
 
175
177
  #[test]
176
- #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
178
+ #[should_panic(expected = "Error(Contract, #1086)")] // RbacError::Unauthorized
177
179
  fn test_set_peer_non_owner_authorized() {
178
180
  let TestSetup { env, owner, oapp_client, .. } = setup();
179
181
  let non_owner = Address::generate(&env);
@@ -204,14 +206,14 @@ fn test_set_delegate_updates_and_clears_endpoint_delegate() {
204
206
  #[test]
205
207
  #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
206
208
  fn test_set_delegate_unauthorized() {
207
- let TestSetup { env, oapp_client, .. } = setup();
209
+ let TestSetup { env, owner, oapp_client, .. } = setup();
208
210
 
209
211
  let delegate = Address::generate(&env);
210
- oapp_client.set_delegate(&Some(delegate));
212
+ oapp_client.set_delegate(&Some(delegate), &owner);
211
213
  }
212
214
 
213
215
  #[test]
214
- #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
216
+ #[should_panic(expected = "Error(Contract, #1086)")] // RbacError::Unauthorized
215
217
  fn test_set_delegate_non_owner_authorized() {
216
218
  let TestSetup { env, owner, oapp_client, .. } = setup();
217
219
  let non_owner = Address::generate(&env);
@@ -32,6 +32,9 @@ impl DummyEndpoint {
32
32
  #[oapp_macros::oapp(custom = [core, sender, receiver])]
33
33
  pub struct DummyOAppOptionsType3;
34
34
 
35
+ #[contract_impl(contracttrait)]
36
+ impl utils::rbac::RoleBasedAccessControl for DummyOAppOptionsType3 {}
37
+
35
38
  #[contract_impl(contracttrait)]
36
39
  impl OAppCore for DummyOAppOptionsType3 {}
37
40
 
@@ -73,6 +76,7 @@ fn setup<'a>() -> TestSetup<'a> {
73
76
  let delegate = owner.clone();
74
77
  let oapp = env.register(DummyOAppOptionsType3, (&owner, &endpoint, &delegate));
75
78
  let oapp_client = DummyOAppOptionsType3Client::new(&env, &oapp);
79
+ super::grant_oapp_admin(&env, &oapp, &owner);
76
80
 
77
81
  TestSetup { env, owner, oapp_client }
78
82
  }
@@ -94,11 +98,11 @@ fn set_enforced_options_with_auth(
94
98
  invoke: &MockAuthInvoke {
95
99
  contract: &oapp_client.address,
96
100
  fn_name: "set_enforced_options",
97
- args: (enforced_params,).into_val(env),
101
+ args: (enforced_params, signer).into_val(env),
98
102
  sub_invokes: &[],
99
103
  },
100
104
  }]);
101
- oapp_client.set_enforced_options(enforced_params);
105
+ oapp_client.set_enforced_options(enforced_params, signer);
102
106
  }
103
107
 
104
108
  #[test]
@@ -164,16 +168,16 @@ fn test_combine_options() {
164
168
  #[test]
165
169
  #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
166
170
  fn test_set_enforced_options_unauthorized() {
167
- let TestSetup { env, oapp_client, .. } = setup();
171
+ let TestSetup { env, owner, oapp_client, .. } = setup();
168
172
 
169
173
  let options = create_valid_options(&env, &[1, 2, 3, 4]);
170
174
  let enforced_params =
171
175
  vec![&env, EnforcedOptionParam { eid: REMOTE_EID_1, msg_type: MSG_TYPE_SEND, options: Some(options.clone()) }];
172
- oapp_client.set_enforced_options(&enforced_params);
176
+ oapp_client.set_enforced_options(&enforced_params, &owner);
173
177
  }
174
178
 
175
179
  #[test]
176
- #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
180
+ #[should_panic(expected = "Error(Contract, #1086)")] // RbacError::Unauthorized
177
181
  fn test_set_enforced_options_non_owner_authorized() {
178
182
  let TestSetup { env, owner, oapp_client, .. } = setup();
179
183
  let non_owner = Address::generate(&env);
@@ -202,11 +206,11 @@ fn test_set_enforced_options_invalid_options_returns_error() {
202
206
  invoke: &MockAuthInvoke {
203
207
  contract: &oapp_client.address,
204
208
  fn_name: "set_enforced_options",
205
- args: (&enforced_params,).into_val(&env),
209
+ args: (&enforced_params, &owner).into_val(&env),
206
210
  sub_invokes: &[],
207
211
  },
208
212
  }]);
209
- let result = oapp_client.try_set_enforced_options(&enforced_params);
213
+ let result = oapp_client.try_set_enforced_options(&enforced_params, &owner);
210
214
  assert_eq!(result.err().unwrap().ok().unwrap(), OAppError::InvalidOptions.into());
211
215
  }
212
216
 
@@ -95,6 +95,8 @@ fn setup<'a>() -> TestSetup<'a> {
95
95
  let endpoint = env.register(MockEndpoint, (&native_token,));
96
96
  let oapp = env.register(DummyOAppReceiver, (&owner, &endpoint));
97
97
  let oapp_client = DummyOAppReceiverClient::new(&env, &oapp);
98
+ super::grant_oapp_admin(&env, &oapp, &owner);
99
+
98
100
  TestSetup { env, owner, endpoint, token_admin, native_token, native_token_admin_client, oapp_client }
99
101
  }
100
102
 
@@ -105,11 +107,11 @@ fn set_peer(env: &Env, owner: &Address, oapp_client: &DummyOAppReceiverClient<'_
105
107
  invoke: &MockAuthInvoke {
106
108
  contract: &oapp_client.address,
107
109
  fn_name: "set_peer",
108
- args: (&eid, &peer_option).into_val(env),
110
+ args: (&eid, &peer_option, owner).into_val(env),
109
111
  sub_invokes: &[],
110
112
  },
111
113
  }]);
112
- oapp_client.set_peer(&eid, &peer_option);
114
+ oapp_client.set_peer(&eid, &peer_option, owner);
113
115
  }
114
116
 
115
117
  fn lz_receive(
@@ -152,6 +152,7 @@ fn setup<'a>() -> TestSetup<'a> {
152
152
  // Deploy OApp
153
153
  let oapp = env.register(DummyOAppSender, (&owner, &endpoint));
154
154
  let oapp_client = DummyOAppSenderClient::new(&env, &oapp);
155
+ super::grant_oapp_admin(&env, &oapp, &owner);
155
156
 
156
157
  TestSetup {
157
158
  env,
@@ -180,11 +181,11 @@ fn set_peer_with_auth(
180
181
  invoke: &MockAuthInvoke {
181
182
  contract: &oapp_client.address,
182
183
  fn_name: "set_peer",
183
- args: (&eid, &peer_option).into_val(env),
184
+ args: (&eid, &peer_option, owner).into_val(env),
184
185
  sub_invokes: &[],
185
186
  },
186
187
  }]);
187
- oapp_client.set_peer(&eid, &peer_option);
188
+ oapp_client.set_peer(&eid, &peer_option, owner);
188
189
  }
189
190
 
190
191
  fn mint_to(
@@ -42,6 +42,9 @@ mod test_full_manual_core {
42
42
  #[oapp(custom = [core])]
43
43
  struct TestFullManualCore;
44
44
 
45
+ #[soroban_sdk::contractimpl(contracttrait)]
46
+ impl utils::rbac::RoleBasedAccessControl for TestFullManualCore {}
47
+
45
48
  #[contractimpl(contracttrait)]
46
49
  impl OAppCore for TestFullManualCore {
47
50
  fn oapp_version(_env: &Env) -> (u64, u64) {
@@ -191,6 +194,9 @@ mod test_full_manual_core_sender {
191
194
  #[oapp(custom = [core, sender])]
192
195
  struct TestFullManualCoreSender;
193
196
 
197
+ #[soroban_sdk::contractimpl(contracttrait)]
198
+ impl utils::rbac::RoleBasedAccessControl for TestFullManualCoreSender {}
199
+
194
200
  #[contractimpl(contracttrait)]
195
201
  impl OAppCore for TestFullManualCoreSender {
196
202
  fn oapp_version(_env: &Env) -> (u64, u64) {
@@ -234,6 +240,9 @@ mod test_full_manual_core_receiver {
234
240
  #[oapp(custom = [core, receiver])]
235
241
  struct TestFullManualCoreReceiver;
236
242
 
243
+ #[soroban_sdk::contractimpl(contracttrait)]
244
+ impl utils::rbac::RoleBasedAccessControl for TestFullManualCoreReceiver {}
245
+
237
246
  #[contractimpl(contracttrait)]
238
247
  impl OAppCore for TestFullManualCoreReceiver {
239
248
  fn oapp_version(_env: &Env) -> (u64, u64) {
@@ -316,6 +325,9 @@ mod test_full_manual_all_except_options {
316
325
  #[oapp(custom = [core, sender, receiver])]
317
326
  struct TestFullManualAllExceptOptions;
318
327
 
328
+ #[soroban_sdk::contractimpl(contracttrait)]
329
+ impl utils::rbac::RoleBasedAccessControl for TestFullManualAllExceptOptions {}
330
+
319
331
  #[contractimpl(contracttrait)]
320
332
  impl OAppCore for TestFullManualAllExceptOptions {
321
333
  fn oapp_version(_env: &Env) -> (u64, u64) {
@@ -364,6 +376,9 @@ mod test_full_manual_all {
364
376
  #[oapp(custom = [core, sender, receiver, options_type3])]
365
377
  struct TestFullManualAll;
366
378
 
379
+ #[soroban_sdk::contractimpl(contracttrait)]
380
+ impl utils::rbac::RoleBasedAccessControl for TestFullManualAll {}
381
+
367
382
  #[contractimpl(contracttrait)]
368
383
  impl OAppCore for TestFullManualAll {
369
384
  fn oapp_version(_env: &Env) -> (u64, u64) {
@@ -98,12 +98,18 @@ pub fn generate_oapp(attr: TokenStream, input: TokenStream) -> TokenStream {
98
98
 
99
99
  /// Generates an empty `impl OAppCore` that uses the trait's default implementations
100
100
  /// for peer management and endpoint access.
101
+ ///
102
+ /// Also generates `impl RoleBasedAccessControl` because OAppCore extends it.
101
103
  fn generate_oapp_core(name: &Ident) -> TokenStream {
102
104
  quote! {
103
105
  use oapp::oapp_core::OAppCore as _;
106
+ use utils::rbac::RoleBasedAccessControl as _;
104
107
 
105
108
  #[soroban_sdk::contractimpl(contracttrait)]
106
109
  impl oapp::oapp_core::OAppCore for #name {}
110
+
111
+ #[soroban_sdk::contractimpl(contracttrait)]
112
+ impl utils::rbac::RoleBasedAccessControl for #name {}
107
113
  }
108
114
  }
109
115
 
@@ -8,8 +8,11 @@ expression: combined
8
8
  #[common_macros::lz_contract]
9
9
  pub struct MyOApp;
10
10
  use oapp::oapp_core::OAppCore as _;
11
+ use utils::rbac::RoleBasedAccessControl as _;
11
12
  #[soroban_sdk::contractimpl(contracttrait)]
12
13
  impl oapp::oapp_core::OAppCore for MyOApp {}
14
+ #[soroban_sdk::contractimpl(contracttrait)]
15
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
13
16
  use oapp::oapp_sender::OAppSenderInternal as _;
14
17
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
15
18
  use oapp::oapp_receiver::OAppReceiver as _;
@@ -39,8 +42,11 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
39
42
  #[common_macros::lz_contract]
40
43
  pub struct MyOApp;
41
44
  use oapp::oapp_core::OAppCore as _;
45
+ use utils::rbac::RoleBasedAccessControl as _;
42
46
  #[soroban_sdk::contractimpl(contracttrait)]
43
47
  impl oapp::oapp_core::OAppCore for MyOApp {}
48
+ #[soroban_sdk::contractimpl(contracttrait)]
49
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
44
50
  use oapp::oapp_receiver::OAppReceiver as _;
45
51
  #[soroban_sdk::contractimpl(contracttrait)]
46
52
  impl oapp::oapp_receiver::OAppReceiver for MyOApp {}
@@ -54,8 +60,11 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
54
60
  #[common_macros::lz_contract]
55
61
  pub struct MyOApp;
56
62
  use oapp::oapp_core::OAppCore as _;
63
+ use utils::rbac::RoleBasedAccessControl as _;
57
64
  #[soroban_sdk::contractimpl(contracttrait)]
58
65
  impl oapp::oapp_core::OAppCore for MyOApp {}
66
+ #[soroban_sdk::contractimpl(contracttrait)]
67
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
59
68
  use oapp::oapp_sender::OAppSenderInternal as _;
60
69
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
61
70
  use oapp::oapp_options_type3::OAppOptionsType3 as _;
@@ -68,8 +77,11 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
68
77
  #[common_macros::lz_contract]
69
78
  pub struct MyOApp;
70
79
  use oapp::oapp_core::OAppCore as _;
80
+ use utils::rbac::RoleBasedAccessControl as _;
71
81
  #[soroban_sdk::contractimpl(contracttrait)]
72
82
  impl oapp::oapp_core::OAppCore for MyOApp {}
83
+ #[soroban_sdk::contractimpl(contracttrait)]
84
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
73
85
  use oapp::oapp_sender::OAppSenderInternal as _;
74
86
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
75
87
  use oapp::oapp_receiver::OAppReceiver as _;
@@ -91,8 +103,11 @@ pub struct FancyOApp {
91
103
  pub x: u32,
92
104
  }
93
105
  use oapp::oapp_core::OAppCore as _;
106
+ use utils::rbac::RoleBasedAccessControl as _;
94
107
  #[soroban_sdk::contractimpl(contracttrait)]
95
108
  impl oapp::oapp_core::OAppCore for FancyOApp {}
109
+ #[soroban_sdk::contractimpl(contracttrait)]
110
+ impl utils::rbac::RoleBasedAccessControl for FancyOApp {}
96
111
  use oapp::oapp_sender::OAppSenderInternal as _;
97
112
  impl oapp::oapp_sender::OAppSenderInternal for FancyOApp {}
98
113
  use oapp::oapp_receiver::OAppReceiver as _;
@@ -10,12 +10,13 @@ use crate::{
10
10
  oft_types::OftType,
11
11
  };
12
12
  use endpoint_v2::{EndpointV2, EndpointV2Client};
13
+ use oapp::oapp_core::OAPP_ADMIN_ROLE;
13
14
  use simple_message_lib::{SimpleMessageLib, SimpleMessageLibClient};
14
15
  use soroban_sdk::{
15
16
  contract, contractimpl, contracttype, log,
16
17
  testutils::{Address as _, MockAuth, MockAuthInvoke},
17
18
  token::{StellarAssetClient, TokenClient},
18
- Address, BytesN, Env, IntoVal,
19
+ Address, BytesN, Env, IntoVal, Symbol,
19
20
  };
20
21
 
21
22
  // ============================================================================
@@ -126,7 +127,7 @@ fn setup_chain<'a>(env: &Env) -> ChainSetup<'a> {
126
127
  let shared_decimals: u32 = 6; // Default shared decimals
127
128
  // MintBurn with SAC wrapper: OFT uses wrapper for mint on credit; burn is on token directly.
128
129
  let mode = OftType::MintBurn(sac_wrapper_address.clone());
129
- let oft_address = env.register(OFT, (&oft_token, &shared_decimals, &mode, &owner, &endpoint_address, &delegate));
130
+ let oft_address = env.register(OFT, (&oft_token, &shared_decimals, &mode, &endpoint_address, delegate.as_ref().unwrap()));
130
131
 
131
132
  let endpoint = EndpointV2Client::new(env, &endpoint_address);
132
133
  let sml = SimpleMessageLibClient::new(env, &sml_address);
@@ -213,17 +214,34 @@ pub fn wire_oft(env: &Env, chains: &[&ChainSetup<'_>]) {
213
214
  }
214
215
  }
215
216
 
217
+ fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
218
+ let role = Symbol::new(env, OAPP_ADMIN_ROLE);
219
+ env.mock_auths(&[MockAuth {
220
+ address: owner,
221
+ invoke: &MockAuthInvoke {
222
+ contract,
223
+ fn_name: "grant_role",
224
+ args: (owner, &role, owner).into_val(env),
225
+ sub_invokes: &[],
226
+ },
227
+ }]);
228
+ utils::rbac::RoleBasedAccessControlClient::new(env, contract).grant_role(owner, &role, owner);
229
+ }
230
+
216
231
  pub fn set_peer(env: &Env, owner: &Address, oft: &OFTClient<'_>, dst_eid: u32, peer: &BytesN<32>) {
232
+ grant_oapp_admin(env, &oft.address, owner);
233
+
234
+ let peer_option = Some(peer.clone());
217
235
  env.mock_auths(&[MockAuth {
218
236
  address: owner,
219
237
  invoke: &MockAuthInvoke {
220
238
  contract: &oft.address,
221
239
  fn_name: "set_peer",
222
- args: (&dst_eid, &Some(peer.clone())).into_val(env),
240
+ args: (&dst_eid, &peer_option, owner).into_val(env),
223
241
  sub_invokes: &[],
224
242
  },
225
243
  }]);
226
- oapp::oapp_core::OAppCoreClient::new(env, &oft.address).set_peer(&dst_eid, &Some(peer.clone()));
244
+ oapp::oapp_core::OAppCoreClient::new(env, &oft.address).set_peer(&dst_eid, &peer_option, owner);
227
245
  }
228
246
 
229
247
  pub fn register_library(env: &Env, owner: &Address, endpoint: &EndpointV2Client<'_>, lib: &Address) {