@layerzerolabs/protocol-stellar-v2 0.2.40 → 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
@@ -1,7 +1,12 @@
1
1
  use endpoint_v2::Origin;
2
+ use oapp::oapp_core::OAPP_ADMIN_ROLE;
2
3
  use oapp::oapp_receiver::LzReceiveInternal;
3
4
  use oapp_macros::oapp;
4
- use soroban_sdk::{contractimpl, symbol_short, Address, Bytes, BytesN, Env};
5
+ use soroban_sdk::{
6
+ contractimpl, symbol_short,
7
+ testutils::{MockAuth, MockAuthInvoke},
8
+ Address, Bytes, BytesN, Env, IntoVal, Symbol,
9
+ };
5
10
 
6
11
  mod oapp_core;
7
12
  mod options_type3;
@@ -46,3 +51,19 @@ impl TestOApp {
46
51
  env.storage().instance().get(&symbol_short!("lzr_c")).unwrap_or(false)
47
52
  }
48
53
  }
54
+
55
+ /// Grants `OAPP_ADMIN_ROLE` to `owner` via the public `grant_role` interface.
56
+ /// Call after `init()` in tests that exercise RBAC-protected entrypoints.
57
+ pub fn grant_oapp_admin(env: &Env, contract: &Address, owner: &Address) {
58
+ let role = Symbol::new(env, OAPP_ADMIN_ROLE);
59
+ env.mock_auths(&[MockAuth {
60
+ address: owner,
61
+ invoke: &MockAuthInvoke {
62
+ contract,
63
+ fn_name: "grant_role",
64
+ args: (owner, &role, owner).into_val(env),
65
+ sub_invokes: &[],
66
+ },
67
+ }]);
68
+ utils::rbac::RoleBasedAccessControlClient::new(env, contract).grant_role(owner, &role, owner);
69
+ }
@@ -1,6 +1,6 @@
1
1
  // Runtime tests: OAppCore behavior generated by `#[oapp]`.
2
2
 
3
- use super::{TestOApp, TestOAppClient};
3
+ use super::{grant_oapp_admin, TestOApp, TestOAppClient};
4
4
  use oapp::oapp_core::{OAppCoreStorage, PeerSet};
5
5
  use soroban_sdk::{
6
6
  contract, contractimpl,
@@ -64,6 +64,7 @@ fn set_peer_requires_auth_and_updates_storage() {
64
64
  let owner = Address::generate(&env);
65
65
  let endpoint = Address::generate(&env);
66
66
  client.init(&owner, &endpoint);
67
+ grant_oapp_admin(&env, &contract_id, &owner);
67
68
 
68
69
  let eid: u32 = 101;
69
70
  let peer = Some(BytesN::<32>::from_array(&env, &[7u8; 32]));
@@ -72,7 +73,7 @@ fn set_peer_requires_auth_and_updates_storage() {
72
73
  assert_eq!(client.peer(&eid), None);
73
74
 
74
75
  // Unauthorized set should fail.
75
- let unauthorized = client.try_set_peer(&eid, &peer);
76
+ let unauthorized = client.try_set_peer(&eid, &peer, &owner);
76
77
  assert_eq!(
77
78
  unauthorized.unwrap_err().unwrap(),
78
79
  Error::from_type_and_code(ScErrorType::Context, ScErrorCode::InvalidAction)
@@ -85,11 +86,11 @@ fn set_peer_requires_auth_and_updates_storage() {
85
86
  invoke: &MockAuthInvoke {
86
87
  contract: &contract_id,
87
88
  fn_name: "set_peer",
88
- args: (&eid, &peer).into_val(&env),
89
+ args: (&eid, &peer, &owner).into_val(&env),
89
90
  sub_invokes: &[],
90
91
  },
91
92
  }])
92
- .set_peer(&eid, &peer);
93
+ .set_peer(&eid, &peer, &owner);
93
94
 
94
95
  // Assert event before any other contract call (Soroban events are per-call).
95
96
  assert_contains_event(&env, &contract_id, PeerSet { eid, peer: peer.clone() });
@@ -106,11 +107,11 @@ fn set_peer_requires_auth_and_updates_storage() {
106
107
  invoke: &MockAuthInvoke {
107
108
  contract: &contract_id,
108
109
  fn_name: "set_peer",
109
- args: (&eid, &none).into_val(&env),
110
+ args: (&eid, &none, &owner).into_val(&env),
110
111
  sub_invokes: &[],
111
112
  },
112
113
  }]);
113
- client.set_peer(&eid, &none);
114
+ client.set_peer(&eid, &none, &owner);
114
115
  assert_contains_event(&env, &contract_id, PeerSet { eid, peer: None });
115
116
  env.as_contract(&contract_id, || {
116
117
  assert_eq!(OAppCoreStorage::peer(&env, eid), None);
@@ -128,10 +129,11 @@ fn set_delegate_requires_auth_and_updates_endpoint() {
128
129
 
129
130
  let owner = Address::generate(&env);
130
131
  client.init(&owner, &endpoint_id);
132
+ grant_oapp_admin(&env, &contract_id, &owner);
131
133
 
132
134
  // Unauthorized set should fail.
133
135
  let delegate = Some(Address::generate(&env));
134
- let unauthorized = client.try_set_delegate(&delegate);
136
+ let unauthorized = client.try_set_delegate(&delegate, &owner);
135
137
  assert_eq!(
136
138
  unauthorized.unwrap_err().unwrap(),
137
139
  Error::from_type_and_code(ScErrorType::Context, ScErrorCode::InvalidAction)
@@ -144,11 +146,11 @@ fn set_delegate_requires_auth_and_updates_endpoint() {
144
146
  invoke: &MockAuthInvoke {
145
147
  contract: &contract_id,
146
148
  fn_name: "set_delegate",
147
- args: (&delegate,).into_val(&env),
149
+ args: (&delegate, &owner).into_val(&env),
148
150
  sub_invokes: &[],
149
151
  },
150
152
  }])
151
- .set_delegate(&delegate);
153
+ .set_delegate(&delegate, &owner);
152
154
 
153
155
  assert_eq!(endpoint_client.delegate(&contract_id), delegate);
154
156
 
@@ -160,11 +162,11 @@ fn set_delegate_requires_auth_and_updates_endpoint() {
160
162
  invoke: &MockAuthInvoke {
161
163
  contract: &contract_id,
162
164
  fn_name: "set_delegate",
163
- args: (&none,).into_val(&env),
165
+ args: (&none, &owner).into_val(&env),
164
166
  sub_invokes: &[],
165
167
  },
166
168
  }])
167
- .set_delegate(&none);
169
+ .set_delegate(&none, &owner);
168
170
 
169
171
  assert_eq!(endpoint_client.delegate(&contract_id), None);
170
172
  }
@@ -1,6 +1,6 @@
1
1
  // Runtime tests: OAppOptionsType3 defaults generated by `#[oapp]`.
2
2
 
3
- use super::{TestOApp, TestOAppClient};
3
+ use super::{grant_oapp_admin, TestOApp, TestOAppClient};
4
4
  use oapp::oapp_options_type3::{EnforcedOptionParam, EnforcedOptionSet};
5
5
  use oapp::OAppError;
6
6
  use soroban_sdk::{
@@ -28,6 +28,7 @@ fn enforced_options_lifecycle_and_auth() {
28
28
 
29
29
  let owner = Address::generate(&env);
30
30
  client.init(&owner, &Address::generate(&env));
31
+ grant_oapp_admin(&env, &contract_id, &owner);
31
32
 
32
33
  // Unset returns None (storage default).
33
34
  assert_eq!(client.enforced_options(&999, &999), None);
@@ -41,7 +42,7 @@ fn enforced_options_lifecycle_and_auth() {
41
42
  ];
42
43
 
43
44
  // Unauthorized set should fail (only_auth).
44
- assert!(client.try_set_enforced_options(&params).is_err());
45
+ assert!(client.try_set_enforced_options(&params, &owner).is_err());
45
46
 
46
47
  // Non-owner authorized should also fail.
47
48
  let non_owner = Address::generate(&env);
@@ -50,11 +51,11 @@ fn enforced_options_lifecycle_and_auth() {
50
51
  invoke: &MockAuthInvoke {
51
52
  contract: &contract_id,
52
53
  fn_name: "set_enforced_options",
53
- args: (&params,).into_val(&env),
54
+ args: (&params, &non_owner).into_val(&env),
54
55
  sub_invokes: &[],
55
56
  },
56
57
  }]);
57
- assert!(client.try_set_enforced_options(&params).is_err());
58
+ assert!(client.try_set_enforced_options(&params, &non_owner).is_err());
58
59
 
59
60
  // Owner-authorized set should succeed.
60
61
  env.mock_auths(&[MockAuth {
@@ -62,11 +63,11 @@ fn enforced_options_lifecycle_and_auth() {
62
63
  invoke: &MockAuthInvoke {
63
64
  contract: &contract_id,
64
65
  fn_name: "set_enforced_options",
65
- args: (&params,).into_val(&env),
66
+ args: (&params, &owner).into_val(&env),
66
67
  sub_invokes: &[],
67
68
  },
68
69
  }]);
69
- client.set_enforced_options(&params);
70
+ client.set_enforced_options(&params, &owner);
70
71
 
71
72
  assert_contains_event(&env, &contract_id, EnforcedOptionSet { enforced_options: params.clone() });
72
73
 
@@ -82,6 +83,7 @@ fn set_enforced_options_rejects_invalid_option_type() {
82
83
 
83
84
  let owner = Address::generate(&env);
84
85
  client.init(&owner, &Address::generate(&env));
86
+ grant_oapp_admin(&env, &contract_id, &owner);
85
87
 
86
88
  // wrong type header (not 3)
87
89
  let mut invalid = Bytes::from_array(&env, &(4u16).to_be_bytes());
@@ -94,11 +96,11 @@ fn set_enforced_options_rejects_invalid_option_type() {
94
96
  invoke: &MockAuthInvoke {
95
97
  contract: &contract_id,
96
98
  fn_name: "set_enforced_options",
97
- args: (&params,).into_val(&env),
99
+ args: (&params, &owner).into_val(&env),
98
100
  sub_invokes: &[],
99
101
  },
100
102
  }]);
101
- let result = client.try_set_enforced_options(&params);
103
+ let result = client.try_set_enforced_options(&params, &owner);
102
104
  assert_eq!(result.err().unwrap().ok().unwrap(), OAppError::InvalidOptions.into());
103
105
  }
104
106
 
@@ -110,6 +112,7 @@ fn combine_options_behavior_and_validation() {
110
112
 
111
113
  let owner = Address::generate(&env);
112
114
  client.init(&owner, &Address::generate(&env));
115
+ grant_oapp_admin(&env, &contract_id, &owner);
113
116
 
114
117
  // No enforced => returns extra (including empty).
115
118
  let extra_only = create_valid_options(&env, &[9, 10, 11]);
@@ -126,11 +129,11 @@ fn combine_options_behavior_and_validation() {
126
129
  invoke: &MockAuthInvoke {
127
130
  contract: &contract_id,
128
131
  fn_name: "set_enforced_options",
129
- args: (&params,).into_val(&env),
132
+ args: (&params, &owner).into_val(&env),
130
133
  sub_invokes: &[],
131
134
  },
132
135
  }]);
133
- client.set_enforced_options(&params);
136
+ client.set_enforced_options(&params, &owner);
134
137
 
135
138
  // Enforced present: empty extra => enforced.
136
139
  assert_eq!(client.combine_options(&REMOTE_EID_1, &MSG_TYPE_SEND, &Bytes::new(&env)), enforced.clone());
@@ -1,6 +1,6 @@
1
1
  // Runtime tests: OAppReceiver defaults generated by `#[oapp]`.
2
2
 
3
- use super::{TestOApp, TestOAppClient};
3
+ use super::{grant_oapp_admin, TestOApp, TestOAppClient};
4
4
  use endpoint_v2::Origin;
5
5
  use oapp::OAppError;
6
6
  use soroban_sdk::{
@@ -87,6 +87,7 @@ fn allow_initialize_path_follows_peer_configuration() {
87
87
  let owner = Address::generate(&env);
88
88
  let endpoint = Address::generate(&env);
89
89
  client.init(&owner, &endpoint);
90
+ grant_oapp_admin(&env, &contract_id, &owner);
90
91
 
91
92
  let eid: u32 = REMOTE_EID_FOR_ALLOW_INIT;
92
93
  let sender = BytesN::<32>::from_array(&env, &[3u8; 32]);
@@ -103,11 +104,11 @@ fn allow_initialize_path_follows_peer_configuration() {
103
104
  invoke: &MockAuthInvoke {
104
105
  contract: &contract_id,
105
106
  fn_name: "set_peer",
106
- args: (&eid, &other_peer).into_val(&env),
107
+ args: (&eid, &other_peer, &owner).into_val(&env),
107
108
  sub_invokes: &[],
108
109
  },
109
110
  }]);
110
- client.set_peer(&eid, &other_peer);
111
+ client.set_peer(&eid, &other_peer, &owner);
111
112
  assert_eq!(client.allow_initialize_path(&origin), false);
112
113
 
113
114
  // Set matching peer => true.
@@ -117,11 +118,11 @@ fn allow_initialize_path_follows_peer_configuration() {
117
118
  invoke: &MockAuthInvoke {
118
119
  contract: &contract_id,
119
120
  fn_name: "set_peer",
120
- args: (&eid, &matching_peer).into_val(&env),
121
+ args: (&eid, &matching_peer, &owner).into_val(&env),
121
122
  sub_invokes: &[],
122
123
  },
123
124
  }]);
124
- client.set_peer(&eid, &matching_peer);
125
+ client.set_peer(&eid, &matching_peer, &owner);
125
126
 
126
127
  assert_eq!(client.allow_initialize_path(&origin), true);
127
128
  }
@@ -140,6 +141,7 @@ fn lz_receive_clears_payload_transfers_value_and_calls_internal_handler() {
140
141
  let oapp = env.register(TestOApp, ());
141
142
  let oapp_client = TestOAppClient::new(&env, &oapp);
142
143
  oapp_client.init(&owner, &endpoint);
144
+ grant_oapp_admin(&env, &oapp, &owner);
143
145
 
144
146
  // Configure peer so peer check passes.
145
147
  let peer = BytesN::<32>::from_array(&env, &[9u8; 32]);
@@ -149,11 +151,11 @@ fn lz_receive_clears_payload_transfers_value_and_calls_internal_handler() {
149
151
  invoke: &MockAuthInvoke {
150
152
  contract: &oapp,
151
153
  fn_name: "set_peer",
152
- args: (&REMOTE_EID, &peer_opt).into_val(&env),
154
+ args: (&REMOTE_EID, &peer_opt, &owner).into_val(&env),
153
155
  sub_invokes: &[],
154
156
  },
155
157
  }]);
156
- oapp_client.set_peer(&REMOTE_EID, &peer_opt);
158
+ oapp_client.set_peer(&REMOTE_EID, &peer_opt, &owner);
157
159
 
158
160
  // Before any lz_receive call, internal handler should not have been invoked.
159
161
  assert_eq!(oapp_client.lz_receive_called(), false);
@@ -226,6 +228,7 @@ fn lz_receive_wrong_peer_returns_only_peer() {
226
228
  let oapp = env.register(TestOApp, ());
227
229
  let oapp_client = TestOAppClient::new(&env, &oapp);
228
230
  oapp_client.init(&owner, &endpoint);
231
+ grant_oapp_admin(&env, &oapp, &owner);
229
232
 
230
233
  // Set peer to some value...
231
234
  let configured_peer = BytesN::<32>::from_array(&env, &[7u8; 32]);
@@ -235,11 +238,11 @@ fn lz_receive_wrong_peer_returns_only_peer() {
235
238
  invoke: &MockAuthInvoke {
236
239
  contract: &oapp,
237
240
  fn_name: "set_peer",
238
- args: (&REMOTE_EID, &peer_opt).into_val(&env),
241
+ args: (&REMOTE_EID, &peer_opt, &owner).into_val(&env),
239
242
  sub_invokes: &[],
240
243
  },
241
244
  }]);
242
- oapp_client.set_peer(&REMOTE_EID, &peer_opt);
245
+ oapp_client.set_peer(&REMOTE_EID, &peer_opt, &owner);
243
246
 
244
247
  // ...but call lz_receive with a different sender.
245
248
  let executor = Address::generate(&env);
@@ -312,6 +315,7 @@ fn lz_receive_requires_executor_auth() {
312
315
  let oapp = env.register(TestOApp, ());
313
316
  let oapp_client = TestOAppClient::new(&env, &oapp);
314
317
  oapp_client.init(&owner, &endpoint);
318
+ grant_oapp_admin(&env, &oapp, &owner);
315
319
 
316
320
  // Configure peer so we fail specifically at executor.require_auth().
317
321
  let peer = BytesN::<32>::from_array(&env, &[7u8; 32]);
@@ -321,11 +325,11 @@ fn lz_receive_requires_executor_auth() {
321
325
  invoke: &MockAuthInvoke {
322
326
  contract: &oapp,
323
327
  fn_name: "set_peer",
324
- args: (&REMOTE_EID, &peer_opt).into_val(&env),
328
+ args: (&REMOTE_EID, &peer_opt, &owner).into_val(&env),
325
329
  sub_invokes: &[],
326
330
  },
327
331
  }]);
328
- oapp_client.set_peer(&REMOTE_EID, &peer_opt);
332
+ oapp_client.set_peer(&REMOTE_EID, &peer_opt, &owner);
329
333
 
330
334
  let executor = Address::generate(&env);
331
335
  let origin = Origin { src_eid: REMOTE_EID, sender: peer, nonce: 1 };
@@ -129,11 +129,11 @@ fn set_peer(
129
129
  invoke: &MockAuthInvoke {
130
130
  contract: oapp,
131
131
  fn_name: "set_peer",
132
- args: (&eid, &peer_opt).into_val(env),
132
+ args: (&eid, &peer_opt, owner).into_val(env),
133
133
  sub_invokes: &[],
134
134
  },
135
135
  }]);
136
- client.set_peer(&eid, &peer_opt);
136
+ client.set_peer(&eid, &peer_opt, owner);
137
137
  }
138
138
 
139
139
  fn mint_to(
@@ -210,6 +210,7 @@ fn setup() -> Setup {
210
210
  let oapp = env.register(TestOAppSender, ());
211
211
  let client = TestOAppSenderClient::new(&env, &oapp);
212
212
  client.init(&owner, &endpoint);
213
+ super::grant_oapp_admin(&env, &oapp, &owner);
213
214
 
214
215
  Setup { env, owner, token_admin, native_token, zro_token, endpoint, oapp }
215
216
  }
@@ -1,4 +1,4 @@
1
- // Runtime tests: 2-step ownership transfer behavior (`propose_ownership_transfer` + `accept_ownership`).
1
+ // Runtime tests: 2-step ownership transfer behavior (`begin_ownership_transfer` + `accept_ownership`).
2
2
  //
3
3
  // Ownable supports a safer two-step flow using temporary storage with TTL. These tests ensure
4
4
  // the macro-exported contract entrypoints are wired and behave correctly at runtime.
@@ -24,10 +24,13 @@ fn propose_requires_owner_auth() {
24
24
 
25
25
  // No auth provided -> should fail at require_auth.
26
26
  let ttl = 10u32;
27
- let res = client.try_propose_ownership_transfer(&new_owner, &ttl);
27
+ let res = client.try_begin_ownership_transfer(&new_owner, &ttl);
28
28
  assert_eq!(
29
29
  res.err().unwrap().ok().unwrap(),
30
- soroban_sdk::Error::from_type_and_code(soroban_sdk::xdr::ScErrorType::Context, soroban_sdk::xdr::ScErrorCode::InvalidAction)
30
+ soroban_sdk::Error::from_type_and_code(
31
+ soroban_sdk::xdr::ScErrorType::Context,
32
+ soroban_sdk::xdr::ScErrorCode::InvalidAction
33
+ )
31
34
  );
32
35
  }
33
36
 
@@ -47,12 +50,12 @@ fn propose_rejects_invalid_ttl() {
47
50
  address: &owner,
48
51
  invoke: &MockAuthInvoke {
49
52
  contract: &contract_id,
50
- fn_name: "propose_ownership_transfer",
53
+ fn_name: "begin_ownership_transfer",
51
54
  args: (&new_owner, &ttl).into_val(&env),
52
55
  sub_invokes: &[],
53
56
  },
54
57
  }])
55
- .try_propose_ownership_transfer(&new_owner, &ttl);
58
+ .try_begin_ownership_transfer(&new_owner, &ttl);
56
59
  assert_eq!(res.err().unwrap().ok().unwrap(), OwnableError::InvalidTtl.into());
57
60
  assert_eq!(client.pending_owner(), None);
58
61
  }
@@ -74,12 +77,12 @@ fn propose_and_accept_transfers_ownership() {
74
77
  address: &owner,
75
78
  invoke: &MockAuthInvoke {
76
79
  contract: &contract_id,
77
- fn_name: "propose_ownership_transfer",
80
+ fn_name: "begin_ownership_transfer",
78
81
  args: (&new_owner, &ttl).into_val(&env),
79
82
  sub_invokes: &[],
80
83
  },
81
84
  }])
82
- .propose_ownership_transfer(&new_owner, &ttl);
85
+ .begin_ownership_transfer(&new_owner, &ttl);
83
86
 
84
87
  assert_eq_event(
85
88
  &env,
@@ -128,12 +131,12 @@ fn pending_transfer_blocks_single_step_transfer_and_renounce() {
128
131
  address: &owner,
129
132
  invoke: &MockAuthInvoke {
130
133
  contract: &contract_id,
131
- fn_name: "propose_ownership_transfer",
134
+ fn_name: "begin_ownership_transfer",
132
135
  args: (&pending, &ttl).into_val(&env),
133
136
  sub_invokes: &[],
134
137
  },
135
138
  }])
136
- .propose_ownership_transfer(&pending, &ttl);
139
+ .begin_ownership_transfer(&pending, &ttl);
137
140
 
138
141
  // With owner auth, immediate transfer should fail due to TransferInProgress.
139
142
  let transfer = client
@@ -180,12 +183,12 @@ fn pending_transfer_expires_and_cannot_be_accepted() {
180
183
  address: &owner,
181
184
  invoke: &MockAuthInvoke {
182
185
  contract: &contract_id,
183
- fn_name: "propose_ownership_transfer",
186
+ fn_name: "begin_ownership_transfer",
184
187
  args: (&pending, &ttl).into_val(&env),
185
188
  sub_invokes: &[],
186
189
  },
187
190
  }])
188
- .propose_ownership_transfer(&pending, &ttl);
191
+ .begin_ownership_transfer(&pending, &ttl);
189
192
 
190
193
  assert_eq!(client.pending_owner(), Some(pending.clone()));
191
194
 
@@ -216,4 +219,3 @@ fn pending_transfer_expires_and_cannot_be_accepted() {
216
219
  // Owner should remain unchanged.
217
220
  assert_eq!(client.owner(), Some(owner));
218
221
  }
219
-
@@ -13,8 +13,8 @@ use soroban_sdk::{
13
13
  xdr::{ScErrorCode, ScErrorType},
14
14
  Address, Bytes, BytesN, Env, Error, IntoVal, Val,
15
15
  };
16
- use utils::upgradeable::{UpgradeableInternal, UpgradeableStorage};
17
16
  use utils::errors::AuthError;
17
+ use utils::upgradeable::{UpgradeableInternal, UpgradeableStorage};
18
18
 
19
19
  // A small, known-good contract WASM used for upgrade() testing.
20
20
  // Sourced from the `upgrader` crate test fixtures.
@@ -202,10 +202,7 @@ fn upgrade_and_migrate_fail_before_owner_init() {
202
202
  UpgradeableStorage::set_migrating(&env, &true);
203
203
  });
204
204
  let migration_data = 1u32.to_xdr(&env);
205
- assert_eq!(
206
- client.try_migrate(&migration_data).unwrap_err().unwrap(),
207
- AuthError::AuthorizerNotFound.into()
208
- );
205
+ assert_eq!(client.try_migrate(&migration_data).unwrap_err().unwrap(), AuthError::AuthorizerNotFound.into());
209
206
  }
210
207
 
211
208
  #[test]
@@ -237,10 +234,7 @@ fn migrate_rejects_invalid_migration_data_and_does_not_clear_flag() {
237
234
  }])
238
235
  .try_migrate(&bad_bytes);
239
236
 
240
- assert_eq!(
241
- res.err().unwrap().ok().unwrap(),
242
- utils::errors::UpgradeableError::InvalidMigrationData.into()
243
- );
237
+ assert_eq!(res.err().unwrap().ok().unwrap(), utils::errors::UpgradeableError::InvalidMigrationData.into());
244
238
 
245
239
  // Since migration failed before reaching the "clear flag" line, migrating should still be true.
246
240
  env.as_contract(&contract_id, || {
@@ -4,4 +4,27 @@ error: custom attribute panicked
4
4
  7 | #[common_macros::lz_contract(upgradeable(bad_inner))]
5
5
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6
6
  |
7
- = help: message: failed to parse lz_contract config: expected `no_migration`
7
+ = help: message: failed to parse upgradeable config: expected `no_migration` or `rbac`
8
+ = note: this error originates in the attribute macro `common_macros::lz_contract` (in Nightly builds, run with -Z macro-backtrace for more info)
9
+
10
+ error[E0433]: failed to resolve: could not find `MyContract` in the crate root
11
+ --> tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.rs:7:1
12
+ |
13
+ 7 | #[common_macros::lz_contract(upgradeable(bad_inner))]
14
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not find `MyContract` in the crate root
15
+ |
16
+ = note: this error originates in the attribute macro `soroban_sdk::contractimpl` (in Nightly builds, run with -Z macro-backtrace for more info)
17
+
18
+ error[E0412]: cannot find type `MyContract` in this scope
19
+ --> tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.rs:8:12
20
+ |
21
+ 8 | pub struct MyContract;
22
+ | ^^^^^^^^^^ not found in this scope
23
+
24
+ error[E0412]: cannot find type `MyContract` in this scope
25
+ --> tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.rs:7:1
26
+ |
27
+ 7 | #[common_macros::lz_contract(upgradeable(bad_inner))]
28
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
29
+ |
30
+ = note: this error originates in the attribute macro `soroban_sdk::contractimpl` (in Nightly builds, run with -Z macro-backtrace for more info)
@@ -16,7 +16,7 @@ error[E0277]: the trait bound `MyContract: UpgradeableInternal` is not satisfied
16
16
  12 | pub struct MyContract;
17
17
  | ^^^^^^^^^^ the trait `UpgradeableInternal` is not implemented for `MyContract`
18
18
  |
19
- note: required by a bound in `upgrade`
19
+ note: required by a bound in `utils::upgradeable::Upgradeable::upgrade`
20
20
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
21
21
  |
22
22
  | pub trait Upgradeable: UpgradeableInternal + Auth {
@@ -31,7 +31,7 @@ error[E0277]: the trait bound `MyContract: UpgradeableInternal` is not satisfied
31
31
  12 | pub struct MyContract;
32
32
  | ^^^^^^^^^^ the trait `UpgradeableInternal` is not implemented for `MyContract`
33
33
  |
34
- note: required by a bound in `migrate`
34
+ note: required by a bound in `utils::upgradeable::Upgradeable::migrate`
35
35
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
36
36
  |
37
37
  | pub trait Upgradeable: UpgradeableInternal + Auth {
@@ -46,7 +46,7 @@ error[E0277]: the trait bound `MyContract: UpgradeableInternal` is not satisfied
46
46
  17 | MyContract::upgrade(env, &hash);
47
47
  | ^^^^^^^^^^ the trait `UpgradeableInternal` is not implemented for `MyContract`
48
48
  |
49
- note: required by a bound in `upgrade`
49
+ note: required by a bound in `utils::upgradeable::Upgradeable::upgrade`
50
50
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
51
51
  |
52
52
  | pub trait Upgradeable: UpgradeableInternal + Auth {
@@ -0,0 +1,44 @@
1
+ // UI (trybuild) test: `#[lz_contract(upgradeable)]` compiles with RBAC.
2
+ //
3
+ // Purpose:
4
+ // - Ensures lz_contract upgradeable wrapper can coexist with RoleBasedAccessControl.
5
+
6
+ use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
7
+ use utils::rbac::{grant_role_no_auth, RoleBasedAccessControl};
8
+ use utils::ttl_configurable::TtlConfig;
9
+ use utils::upgradeable::UpgradeableInternal;
10
+
11
+ #[common_macros::lz_contract(upgradeable)]
12
+ pub struct MyContract;
13
+
14
+ impl UpgradeableInternal for MyContract {
15
+ type MigrationData = ();
16
+
17
+ fn __migrate(_env: &Env, _migration_data: &Self::MigrationData) {}
18
+ }
19
+
20
+ #[contractimpl(contracttrait)]
21
+ impl RoleBasedAccessControl for MyContract {}
22
+
23
+ #[contractimpl]
24
+ impl MyContract {
25
+ pub fn init(env: Env, owner: Address) {
26
+ Self::init_owner(&env, &owner);
27
+ }
28
+
29
+ pub fn smoke(env: Env, operator: Address) {
30
+ // Smoke-use RBAC helper (doesn't execute in trybuild).
31
+ let role = soroban_sdk::Symbol::new(&env, "SOME_ROLE");
32
+ grant_role_no_auth(&env, &operator, &role, &env.current_contract_address());
33
+
34
+ let _cfg: (Option<TtlConfig>, Option<TtlConfig>) = Self::ttl_configs(&env);
35
+ Self::extend_instance_ttl(&env, 1, 2);
36
+
37
+ let hash = BytesN::<32>::from_array(&env, &[0u8; 32]);
38
+ let migration_data = Bytes::new(&env);
39
+ Self::upgrade(&env, &hash);
40
+ Self::migrate(&env, &migration_data);
41
+ }
42
+ }
43
+
44
+ fn main() {}
@@ -7,6 +7,7 @@ use oapp::oapp_receiver::{LzReceiveInternal, OAppReceiver};
7
7
  use oapp::oapp_sender::OAppSenderInternal;
8
8
  use oapp_macros::oapp;
9
9
  use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
10
+ use utils::rbac::RoleBasedAccessControl;
10
11
 
11
12
  #[oapp(custom = [core, sender, receiver, options_type3])]
12
13
  pub struct MyOApp;
@@ -24,6 +25,8 @@ impl LzReceiveInternal for MyOApp {
24
25
  }
25
26
  }
26
27
 
28
+ impl RoleBasedAccessControl for MyOApp {}
29
+
27
30
  #[contractimpl(contracttrait)]
28
31
  impl OAppCore for MyOApp {}
29
32
 
@@ -13,6 +13,7 @@ use oapp::oapp_receiver::{LzReceiveInternal, OAppReceiver};
13
13
  use oapp::oapp_sender::OAppSenderInternal;
14
14
  use oapp_macros::oapp;
15
15
  use soroban_sdk::{contractimpl, Address, Bytes, BytesN, Env};
16
+ use utils::rbac::RoleBasedAccessControl;
16
17
 
17
18
  #[oapp(custom = [core])]
18
19
  pub struct MyOAppCustomCore;
@@ -30,6 +31,8 @@ impl LzReceiveInternal for MyOAppCustomCore {
30
31
  }
31
32
  }
32
33
 
34
+ impl RoleBasedAccessControl for MyOAppCustomCore {}
35
+
33
36
  #[contractimpl(contracttrait)]
34
37
  impl OAppCore for MyOAppCustomCore {
35
38
  fn oapp_version(_env: &Env) -> (u64, u64) {
@@ -30,7 +30,7 @@ impl MyContract {
30
30
 
31
31
  // A couple key Ownable APIs type-check.
32
32
  <Self as utils::ownable::Ownable>::transfer_ownership(&env, &owner);
33
- <Self as utils::ownable::Ownable>::propose_ownership_transfer(&env, &owner, 1);
33
+ <Self as utils::ownable::Ownable>::begin_ownership_transfer(&env, &owner, 1);
34
34
  <Self as utils::ownable::Ownable>::accept_ownership(&env);
35
35
  <Self as utils::ownable::Ownable>::renounce_ownership(&env);
36
36
  }
@@ -4,7 +4,7 @@ error: custom attribute panicked
4
4
  7 | #[common_macros::upgradeable(not_migration)]
5
5
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6
6
  |
7
- = help: message: failed to parse upgradeable config: expected `no_migration`
7
+ = help: message: failed to parse upgradeable config: expected `no_migration` or `rbac`
8
8
 
9
9
  error[E0433]: failed to resolve: could not find `MyContract` in the crate root
10
10
  --> tests/ui/upgradeable/fail/attr_args.rs:6:1
@@ -16,7 +16,7 @@ error[E0277]: the trait bound `MyContract: utils::auth::Auth` is not satisfied
16
16
  12 | pub struct MyContract;
17
17
  | ^^^^^^^^^^ the trait `utils::auth::Auth` is not implemented for `MyContract`
18
18
  |
19
- note: required by a bound in `upgrade`
19
+ note: required by a bound in `utils::upgradeable::Upgradeable::upgrade`
20
20
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
21
21
  |
22
22
  | pub trait Upgradeable: UpgradeableInternal + Auth {
@@ -31,7 +31,7 @@ error[E0277]: the trait bound `MyContract: utils::auth::Auth` is not satisfied
31
31
  12 | pub struct MyContract;
32
32
  | ^^^^^^^^^^ the trait `utils::auth::Auth` is not implemented for `MyContract`
33
33
  |
34
- note: required by a bound in `migrate`
34
+ note: required by a bound in `utils::upgradeable::Upgradeable::migrate`
35
35
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
36
36
  |
37
37
  | pub trait Upgradeable: UpgradeableInternal + Auth {
@@ -24,7 +24,7 @@ error[E0277]: the trait bound `MyContract: UpgradeableInternal` is not satisfied
24
24
  8 | pub struct MyContract;
25
25
  | ^^^^^^^^^^ the trait `UpgradeableInternal` is not implemented for `MyContract`
26
26
  |
27
- note: required by a bound in `upgrade`
27
+ note: required by a bound in `utils::upgradeable::Upgradeable::upgrade`
28
28
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
29
29
  |
30
30
  | pub trait Upgradeable: UpgradeableInternal + Auth {
@@ -39,7 +39,7 @@ error[E0277]: the trait bound `MyContract: UpgradeableInternal` is not satisfied
39
39
  8 | pub struct MyContract;
40
40
  | ^^^^^^^^^^ the trait `UpgradeableInternal` is not implemented for `MyContract`
41
41
  |
42
- note: required by a bound in `migrate`
42
+ note: required by a bound in `utils::upgradeable::Upgradeable::migrate`
43
43
  --> $WORKSPACE/contracts/utils/src/upgradeable.rs
44
44
  |
45
45
  | pub trait Upgradeable: UpgradeableInternal + Auth {