@layerzerolabs/protocol-stellar-v2 0.2.40 → 0.2.43

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 (129) hide show
  1. package/.turbo/turbo-build.log +312 -397
  2. package/.turbo/turbo-lint.log +185 -245
  3. package/.turbo/turbo-test.log +1846 -1942
  4. package/Cargo.lock +22 -127
  5. package/Cargo.toml +4 -6
  6. package/contracts/common-macros/src/lib.rs +38 -15
  7. package/contracts/common-macros/src/lz_contract.rs +12 -21
  8. package/contracts/common-macros/src/tests/lz_contract.rs +17 -8
  9. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__lz_contract__snapshot_generated_lz_contract_code.snap +20 -0
  10. package/contracts/common-macros/src/upgradeable.rs +37 -30
  11. package/contracts/endpoint-v2/src/endpoint_v2.rs +4 -3
  12. package/contracts/endpoint-v2/src/errors.rs +2 -2
  13. package/contracts/endpoint-v2/src/messaging_channel.rs +11 -0
  14. package/contracts/endpoint-v2/src/messaging_composer.rs +1 -0
  15. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +12 -25
  16. package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +4 -4
  17. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +50 -10
  18. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +6 -35
  19. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +2 -2
  20. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +50 -1
  21. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +78 -0
  22. package/contracts/endpoint-v2/src/tests/messaging_channel/insert_and_drain_pending_nonces.rs +272 -0
  23. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +1 -0
  24. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +10 -5
  25. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +30 -0
  26. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +25 -6
  27. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +13 -11
  28. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +13 -10
  29. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +15 -11
  30. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +5 -3
  31. package/contracts/macro-integration-tests/tests/runtime/ownable/mod.rs +1 -1
  32. package/contracts/macro-integration-tests/tests/runtime/ownable/two_step_transfer.rs +14 -12
  33. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +3 -9
  34. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_invalid_inner_option.stderr +24 -1
  35. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +3 -3
  36. package/contracts/macro-integration-tests/tests/ui/lz_contract/pass/upgradeable_rbac.rs +44 -0
  37. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_auth_trait.rs +28 -0
  38. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_auth_trait.stderr +397 -0
  39. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +1 -0
  40. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +10 -10
  41. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +4 -0
  42. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +7 -0
  43. package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +5 -4
  44. package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +2 -0
  45. package/contracts/macro-integration-tests/tests/ui/ownable/pass/basic.rs +1 -1
  46. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/attr_args.stderr +1 -1
  47. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +2 -2
  48. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +2 -2
  49. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/rbac.rs +44 -0
  50. package/contracts/oapps/counter/integration_tests/utils.rs +5 -3
  51. package/contracts/oapps/counter/src/counter.rs +4 -3
  52. package/contracts/oapps/counter/src/tests/mod.rs +16 -1
  53. package/contracts/oapps/counter/src/tests/test_counter.rs +5 -2
  54. package/contracts/oapps/oapp/src/oapp_core.rs +22 -8
  55. package/contracts/oapps/oapp/src/oapp_options_type3.rs +7 -5
  56. package/contracts/oapps/oapp/src/tests/mod.rs +21 -0
  57. package/contracts/oapps/oapp/src/tests/oapp_core.rs +14 -11
  58. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +17 -10
  59. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +6 -3
  60. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +5 -3
  61. package/contracts/oapps/oapp/src/tests/test_macros.rs +25 -0
  62. package/contracts/oapps/oapp-macros/src/generators.rs +12 -9
  63. package/contracts/oapps/oapp-macros/src/lib.rs +1 -1
  64. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +15 -7
  65. package/contracts/oapps/oft/integration-tests/setup.rs +22 -4
  66. package/contracts/oapps/oft/integration-tests/utils.rs +94 -13
  67. package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -10
  68. package/contracts/oapps/oft/src/extensions/pausable.rs +31 -10
  69. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +9 -4
  70. package/contracts/oapps/oft/src/oft.rs +3 -3
  71. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +39 -27
  72. package/contracts/oapps/oft/src/tests/extensions/pausable.rs +38 -24
  73. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +87 -69
  74. package/contracts/oapps/oft/src/tests/oft_types/lock_unlock.rs +1 -0
  75. package/contracts/oapps/oft-core/integration-tests/setup.rs +28 -3
  76. package/contracts/oapps/oft-core/src/oft_core.rs +11 -6
  77. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +20 -20
  78. package/contracts/oapps/oft-core/src/tests/test_utils.rs +33 -3
  79. package/contracts/upgrader/src/lib.rs +67 -30
  80. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract3.wasm +0 -0
  81. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract4.wasm +0 -0
  82. package/contracts/upgrader/src/tests/test_upgrader.rs +50 -4
  83. package/contracts/utils/src/ownable.rs +16 -5
  84. package/contracts/utils/src/tests/ownable.rs +39 -39
  85. package/contracts/utils/src/upgradeable.rs +60 -17
  86. package/docs/oapp-guide.md +18 -13
  87. package/package.json +5 -5
  88. package/sdk/.turbo/turbo-test.log +359 -348
  89. package/sdk/dist/generated/bml.d.ts +4 -4
  90. package/sdk/dist/generated/bml.js +6 -6
  91. package/sdk/dist/generated/counter.d.ts +269 -123
  92. package/sdk/dist/generated/counter.js +45 -25
  93. package/sdk/dist/generated/dvn.d.ts +4 -6
  94. package/sdk/dist/generated/dvn.js +8 -8
  95. package/sdk/dist/generated/dvn_fee_lib.d.ts +8 -10
  96. package/sdk/dist/generated/dvn_fee_lib.js +8 -8
  97. package/sdk/dist/generated/endpoint.d.ts +9 -9
  98. package/sdk/dist/generated/endpoint.js +9 -9
  99. package/sdk/dist/generated/executor.d.ts +9 -11
  100. package/sdk/dist/generated/executor.js +11 -11
  101. package/sdk/dist/generated/executor_fee_lib.d.ts +9 -11
  102. package/sdk/dist/generated/executor_fee_lib.js +11 -11
  103. package/sdk/dist/generated/executor_helper.d.ts +4 -4
  104. package/sdk/dist/generated/executor_helper.js +6 -6
  105. package/sdk/dist/generated/layerzero_view.d.ts +9 -11
  106. package/sdk/dist/generated/layerzero_view.js +11 -11
  107. package/sdk/dist/generated/oft.d.ts +323 -156
  108. package/sdk/dist/generated/oft.js +65 -43
  109. package/sdk/dist/generated/price_feed.d.ts +8 -10
  110. package/sdk/dist/generated/price_feed.js +8 -8
  111. package/sdk/dist/generated/sac_manager.d.ts +8 -8
  112. package/sdk/dist/generated/sac_manager.js +6 -6
  113. package/sdk/dist/generated/sml.d.ts +9 -9
  114. package/sdk/dist/generated/sml.js +9 -9
  115. package/sdk/dist/generated/treasury.d.ts +9 -9
  116. package/sdk/dist/generated/treasury.js +9 -9
  117. package/sdk/dist/generated/uln302.d.ts +9 -9
  118. package/sdk/dist/generated/uln302.js +9 -9
  119. package/sdk/dist/generated/upgrader.d.ts +25 -16
  120. package/sdk/dist/generated/upgrader.js +5 -5
  121. package/sdk/package.json +1 -1
  122. package/sdk/test/counter-sml.test.ts +20 -0
  123. package/sdk/test/counter-uln.test.ts +20 -0
  124. package/sdk/test/oft-sml.test.ts +22 -0
  125. package/sdk/test/upgrader.test.ts +1 -0
  126. package/ts-bindings-gen.toml +67 -0
  127. package/turbo.json +1 -8
  128. package/tools/ts-bindings-gen/Cargo.toml +0 -16
  129. package/tools/ts-bindings-gen/src/main.rs +0 -214
@@ -65,15 +65,13 @@ impl Parse for CustomImpls {
65
65
  }
66
66
  }
67
67
 
68
- /// Generates a complete OApp implementation with contract attributes and trait implementations.
68
+ /// Generates OApp trait implementations only. No contract-level attributes are applied.
69
69
  ///
70
- /// This function creates:
71
- /// - `#[common_macros::lz_contract]` - Wrapper macro that combines:
72
- /// - `#[soroban_sdk::contract]` - Makes the struct a Soroban contract
73
- /// - `#[common_macros::ttl_configurable]` - Adds TTL configuration with auth
74
- /// - `#[common_macros::ttl_extendable]` - Adds manual TTL extension support
75
- /// - `#[common_macros::ownable]` - Adds single-owner access control
76
- /// - OAppCore, OAppSenderInternal, OAppReceiver, and OAppOptionsType3 trait implementations
70
+ /// This function creates OAppCore, OAppSenderInternal, OAppReceiver, and OAppOptionsType3 trait implementations.
71
+ ///
72
+ /// **The user must apply a contract macro** such as `#[common_macros::lz_contract]` or
73
+ /// `#[soroban_sdk::contract]` to the struct. `#[lz_contract]` provides contract, TTL, and Auth
74
+ /// (via `#[ownable]` or `#[multisig]`) in one place.
77
75
  ///
78
76
  /// The `custom` parameter controls which trait implementations are generated vs.
79
77
  /// expected to be provided by the user.
@@ -86,7 +84,6 @@ pub fn generate_oapp(attr: TokenStream, input: TokenStream) -> TokenStream {
86
84
  let receiver_impl = (!custom.receiver).then(|| generate_oapp_receiver(&item_struct.ident));
87
85
  let options_type3_impl = (!custom.options_type3).then(|| generate_oapp_options_type3(&item_struct.ident));
88
86
  quote! {
89
- #[common_macros::lz_contract]
90
87
  #item_struct
91
88
 
92
89
  #core_impl
@@ -98,12 +95,18 @@ pub fn generate_oapp(attr: TokenStream, input: TokenStream) -> TokenStream {
98
95
 
99
96
  /// Generates an empty `impl OAppCore` that uses the trait's default implementations
100
97
  /// for peer management and endpoint access.
98
+ ///
99
+ /// Also generates `impl RoleBasedAccessControl` because OAppCore extends it.
101
100
  fn generate_oapp_core(name: &Ident) -> TokenStream {
102
101
  quote! {
103
102
  use oapp::oapp_core::OAppCore as _;
103
+ use utils::rbac::RoleBasedAccessControl as _;
104
104
 
105
105
  #[soroban_sdk::contractimpl(contracttrait)]
106
106
  impl oapp::oapp_core::OAppCore for #name {}
107
+
108
+ #[soroban_sdk::contractimpl(contracttrait)]
109
+ impl utils::rbac::RoleBasedAccessControl for #name {}
107
110
  }
108
111
  }
109
112
 
@@ -126,7 +126,7 @@ mod generators;
126
126
 
127
127
  use proc_macro::TokenStream;
128
128
 
129
- /// Derives a complete OApp: `#[contract]` + `#[ownable]` + Core + Sender + Receiver + OptionsType3.
129
+ /// Derives OApp trait implementations. Apply `#[lz_contract]` (or similar) for contract + TTL + Auth.
130
130
  ///
131
131
  /// ## Usage
132
132
  ///
@@ -5,11 +5,13 @@ expression: combined
5
5
  ---
6
6
  // === Default (no custom impls) ===
7
7
 
8
- #[common_macros::lz_contract]
9
8
  pub struct MyOApp;
10
9
  use oapp::oapp_core::OAppCore as _;
10
+ use utils::rbac::RoleBasedAccessControl as _;
11
11
  #[soroban_sdk::contractimpl(contracttrait)]
12
12
  impl oapp::oapp_core::OAppCore for MyOApp {}
13
+ #[soroban_sdk::contractimpl(contracttrait)]
14
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
13
15
  use oapp::oapp_sender::OAppSenderInternal as _;
14
16
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
15
17
  use oapp::oapp_receiver::OAppReceiver as _;
@@ -22,7 +24,6 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
22
24
 
23
25
  // === custom = [core] ===
24
26
 
25
- #[common_macros::lz_contract]
26
27
  pub struct MyOApp;
27
28
  use oapp::oapp_sender::OAppSenderInternal as _;
28
29
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
@@ -36,11 +37,13 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
36
37
 
37
38
  // === custom = [sender] ===
38
39
 
39
- #[common_macros::lz_contract]
40
40
  pub struct MyOApp;
41
41
  use oapp::oapp_core::OAppCore as _;
42
+ use utils::rbac::RoleBasedAccessControl as _;
42
43
  #[soroban_sdk::contractimpl(contracttrait)]
43
44
  impl oapp::oapp_core::OAppCore for MyOApp {}
45
+ #[soroban_sdk::contractimpl(contracttrait)]
46
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
44
47
  use oapp::oapp_receiver::OAppReceiver as _;
45
48
  #[soroban_sdk::contractimpl(contracttrait)]
46
49
  impl oapp::oapp_receiver::OAppReceiver for MyOApp {}
@@ -51,11 +54,13 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
51
54
 
52
55
  // === custom = [receiver] ===
53
56
 
54
- #[common_macros::lz_contract]
55
57
  pub struct MyOApp;
56
58
  use oapp::oapp_core::OAppCore as _;
59
+ use utils::rbac::RoleBasedAccessControl as _;
57
60
  #[soroban_sdk::contractimpl(contracttrait)]
58
61
  impl oapp::oapp_core::OAppCore for MyOApp {}
62
+ #[soroban_sdk::contractimpl(contracttrait)]
63
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
59
64
  use oapp::oapp_sender::OAppSenderInternal as _;
60
65
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
61
66
  use oapp::oapp_options_type3::OAppOptionsType3 as _;
@@ -65,11 +70,13 @@ impl oapp::oapp_options_type3::OAppOptionsType3 for MyOApp {}
65
70
 
66
71
  // === custom = [options_type3] ===
67
72
 
68
- #[common_macros::lz_contract]
69
73
  pub struct MyOApp;
70
74
  use oapp::oapp_core::OAppCore as _;
75
+ use utils::rbac::RoleBasedAccessControl as _;
71
76
  #[soroban_sdk::contractimpl(contracttrait)]
72
77
  impl oapp::oapp_core::OAppCore for MyOApp {}
78
+ #[soroban_sdk::contractimpl(contracttrait)]
79
+ impl utils::rbac::RoleBasedAccessControl for MyOApp {}
73
80
  use oapp::oapp_sender::OAppSenderInternal as _;
74
81
  impl oapp::oapp_sender::OAppSenderInternal for MyOApp {}
75
82
  use oapp::oapp_receiver::OAppReceiver as _;
@@ -79,20 +86,21 @@ impl oapp::oapp_receiver::OAppReceiver for MyOApp {}
79
86
 
80
87
  // === custom = [core, sender, receiver, options_type3] ===
81
88
 
82
- #[common_macros::lz_contract]
83
89
  pub struct MyOApp;
84
90
 
85
91
 
86
92
  // === Struct attributes + fields are preserved ===
87
93
 
88
- #[common_macros::lz_contract]
89
94
  #[derive(Clone, Debug)]
90
95
  pub struct FancyOApp {
91
96
  pub x: u32,
92
97
  }
93
98
  use oapp::oapp_core::OAppCore as _;
99
+ use utils::rbac::RoleBasedAccessControl as _;
94
100
  #[soroban_sdk::contractimpl(contracttrait)]
95
101
  impl oapp::oapp_core::OAppCore for FancyOApp {}
102
+ #[soroban_sdk::contractimpl(contracttrait)]
103
+ impl utils::rbac::RoleBasedAccessControl for FancyOApp {}
96
104
  use oapp::oapp_sender::OAppSenderInternal as _;
97
105
  impl oapp::oapp_sender::OAppSenderInternal for FancyOApp {}
98
106
  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) {
@@ -1,6 +1,8 @@
1
1
  //! Utility functions for OFT-STD integration tests.
2
2
 
3
- use crate::extensions::rate_limiter::{Direction, Mode, RateLimitConfig};
3
+ use crate::extensions::rate_limiter::{Direction, Mode, RateLimitConfig, RATE_LIMITER_ADMIN_ROLE};
4
+ use crate::extensions::oft_fee::FEE_ADMIN_ROLE;
5
+ use crate::extensions::pausable::{PAUSER_ROLE, UNPAUSER_ROLE};
4
6
  use crate::integration_tests::setup::{decode_packet, ChainSetup};
5
7
  use crate::MintableClient;
6
8
  use endpoint_v2::{MessagingFee, Origin, OutboundPacket};
@@ -13,7 +15,6 @@ use soroban_sdk::{
13
15
  xdr::ToXdr,
14
16
  Address, Bytes, BytesN, Env, IntoVal, Map, Symbol, Val, Vec,
15
17
  };
16
-
17
18
  // ============================================================================
18
19
  // Address Conversion Utilities
19
20
  // ============================================================================
@@ -356,16 +357,44 @@ pub fn token_balance(env: &Env, token: &Address, account: &Address) -> i128 {
356
357
  // ============================================================================
357
358
 
358
359
  pub fn set_paused(env: &Env, chain: &ChainSetup<'_>, paused: bool) {
360
+ // `pause` / `unpause` are protected by RBAC (`PAUSER_ROLE` / `UNPAUSER_ROLE`). Grant them to owner for tests.
361
+ let pauser = Symbol::new(env, PAUSER_ROLE);
362
+ let unpauser = Symbol::new(env, UNPAUSER_ROLE);
359
363
  env.mock_auths(&[MockAuth {
360
364
  address: &chain.owner,
361
365
  invoke: &MockAuthInvoke {
362
366
  contract: &chain.oft.address,
363
- fn_name: "set_paused",
364
- args: (&paused,).into_val(env),
367
+ fn_name: "grant_role",
368
+ args: (&chain.owner, &pauser, &chain.owner).into_val(env),
365
369
  sub_invokes: &[],
366
370
  },
367
371
  }]);
368
- chain.oft.set_paused(&paused);
372
+ chain.oft.grant_role(&chain.owner, &pauser, &chain.owner);
373
+ env.mock_auths(&[MockAuth {
374
+ address: &chain.owner,
375
+ invoke: &MockAuthInvoke {
376
+ contract: &chain.oft.address,
377
+ fn_name: "grant_role",
378
+ args: (&chain.owner, &unpauser, &chain.owner).into_val(env),
379
+ sub_invokes: &[],
380
+ },
381
+ }]);
382
+ chain.oft.grant_role(&chain.owner, &unpauser, &chain.owner);
383
+
384
+ env.mock_auths(&[MockAuth {
385
+ address: &chain.owner,
386
+ invoke: &MockAuthInvoke {
387
+ contract: &chain.oft.address,
388
+ fn_name: if paused { "pause" } else { "unpause" },
389
+ args: (&chain.owner,).into_val(env),
390
+ sub_invokes: &[],
391
+ },
392
+ }]);
393
+ if paused {
394
+ chain.oft.pause(&chain.owner);
395
+ } else {
396
+ chain.oft.unpause(&chain.owner);
397
+ }
369
398
  }
370
399
 
371
400
  pub fn is_paused(chain: &ChainSetup<'_>) -> bool {
@@ -377,45 +406,84 @@ pub fn is_paused(chain: &ChainSetup<'_>) -> bool {
377
406
  // ============================================================================
378
407
 
379
408
  pub fn set_fee_deposit_address(env: &Env, chain: &ChainSetup<'_>, deposit_address: &Address) {
409
+ // `set_fee_deposit_address` is protected by RBAC (`FEE_ADMIN_ROLE`). Grant it to owner for tests.
410
+ let role = Symbol::new(env, FEE_ADMIN_ROLE);
411
+ env.mock_auths(&[MockAuth {
412
+ address: &chain.owner,
413
+ invoke: &MockAuthInvoke {
414
+ contract: &chain.oft.address,
415
+ fn_name: "grant_role",
416
+ args: (&chain.owner, &role, &chain.owner).into_val(env),
417
+ sub_invokes: &[],
418
+ },
419
+ }]);
420
+ chain.oft.grant_role(&chain.owner, &role, &chain.owner);
421
+
380
422
  let deposit_address_opt = Some(deposit_address.clone());
381
423
  env.mock_auths(&[MockAuth {
382
424
  address: &chain.owner,
383
425
  invoke: &MockAuthInvoke {
384
426
  contract: &chain.oft.address,
385
427
  fn_name: "set_fee_deposit_address",
386
- args: (&deposit_address_opt,).into_val(env),
428
+ args: (&deposit_address_opt, &chain.owner).into_val(env),
387
429
  sub_invokes: &[],
388
430
  },
389
431
  }]);
390
- chain.oft.set_fee_deposit_address(&deposit_address_opt);
432
+ chain.oft.set_fee_deposit_address(&deposit_address_opt, &chain.owner);
391
433
  }
392
434
 
393
435
  pub fn set_default_fee_bps(env: &Env, chain: &ChainSetup<'_>, fee_bps: u32) {
436
+ // `set_default_fee_bps` is protected by RBAC (`FEE_ADMIN_ROLE`). Grant it to owner for tests.
437
+ let role = Symbol::new(env, FEE_ADMIN_ROLE);
438
+ env.mock_auths(&[MockAuth {
439
+ address: &chain.owner,
440
+ invoke: &MockAuthInvoke {
441
+ contract: &chain.oft.address,
442
+ fn_name: "grant_role",
443
+ args: (&chain.owner, &role, &chain.owner).into_val(env),
444
+ sub_invokes: &[],
445
+ },
446
+ }]);
447
+ chain.oft.grant_role(&chain.owner, &role, &chain.owner);
448
+
394
449
  let fee_bps_opt = Some(fee_bps);
395
450
  env.mock_auths(&[MockAuth {
396
451
  address: &chain.owner,
397
452
  invoke: &MockAuthInvoke {
398
453
  contract: &chain.oft.address,
399
454
  fn_name: "set_default_fee_bps",
400
- args: (&fee_bps_opt,).into_val(env),
455
+ args: (&fee_bps_opt, &chain.owner).into_val(env),
401
456
  sub_invokes: &[],
402
457
  },
403
458
  }]);
404
- chain.oft.set_default_fee_bps(&fee_bps_opt);
459
+ chain.oft.set_default_fee_bps(&fee_bps_opt, &chain.owner);
405
460
  }
406
461
 
407
462
  pub fn set_fee_bps(env: &Env, chain: &ChainSetup<'_>, dst_eid: u32, fee_bps: u32) {
463
+ // `set_fee_bps` is protected by RBAC (`FEE_ADMIN_ROLE`). Grant it to owner for tests.
464
+ let role = Symbol::new(env, FEE_ADMIN_ROLE);
465
+ env.mock_auths(&[MockAuth {
466
+ address: &chain.owner,
467
+ invoke: &MockAuthInvoke {
468
+ contract: &chain.oft.address,
469
+ fn_name: "grant_role",
470
+ args: (&chain.owner, &role, &chain.owner).into_val(env),
471
+ sub_invokes: &[],
472
+ },
473
+ }]);
474
+ chain.oft.grant_role(&chain.owner, &role, &chain.owner);
475
+
408
476
  let fee_bps_opt = Some(fee_bps);
409
477
  env.mock_auths(&[MockAuth {
410
478
  address: &chain.owner,
411
479
  invoke: &MockAuthInvoke {
412
480
  contract: &chain.oft.address,
413
481
  fn_name: "set_fee_bps",
414
- args: (&dst_eid, &fee_bps_opt).into_val(env),
482
+ args: (&dst_eid, &fee_bps_opt, &chain.owner).into_val(env),
415
483
  sub_invokes: &[],
416
484
  },
417
485
  }]);
418
- chain.oft.set_fee_bps(&dst_eid, &fee_bps_opt);
486
+ chain.oft.set_fee_bps(&dst_eid, &fee_bps_opt, &chain.owner);
419
487
  }
420
488
 
421
489
  // ============================================================================
@@ -442,17 +510,30 @@ pub fn set_rate_limit_with_mode(
442
510
  window_seconds: u64,
443
511
  mode: Mode,
444
512
  ) {
513
+ // `set_rate_limit` is protected by RBAC (`RATE_LIMITER_ADMIN_ROLE`). Grant it to owner for tests.
514
+ let role = Symbol::new(env, RATE_LIMITER_ADMIN_ROLE);
515
+ env.mock_auths(&[MockAuth {
516
+ address: &chain.owner,
517
+ invoke: &MockAuthInvoke {
518
+ contract: &chain.oft.address,
519
+ fn_name: "grant_role",
520
+ args: (&chain.owner, &role, &chain.owner).into_val(env),
521
+ sub_invokes: &[],
522
+ },
523
+ }]);
524
+ chain.oft.grant_role(&chain.owner, &role, &chain.owner);
525
+
445
526
  let config = Some(RateLimitConfig { limit, window_seconds, mode });
446
527
  env.mock_auths(&[MockAuth {
447
528
  address: &chain.owner,
448
529
  invoke: &MockAuthInvoke {
449
530
  contract: &chain.oft.address,
450
531
  fn_name: "set_rate_limit",
451
- args: (direction, &dst_eid, &config).into_val(env),
532
+ args: (direction, &dst_eid, &config, &chain.owner).into_val(env),
452
533
  sub_invokes: &[],
453
534
  },
454
535
  }]);
455
- chain.oft.set_rate_limit(direction, &dst_eid, &config);
536
+ chain.oft.set_rate_limit(direction, &dst_eid, &config, &chain.owner);
456
537
  }
457
538
 
458
539
  pub fn rate_limit_capacity(chain: &ChainSetup<'_>, direction: &Direction, eid: u32) -> i128 {
@@ -1,6 +1,9 @@
1
- use common_macros::{contract_error, contract_trait, only_auth, storage};
1
+ use common_macros::{contract_error, contract_trait, only_role, storage};
2
2
  use soroban_sdk::{assert_with_error, contractevent, token::TokenClient, Address, Env};
3
- use utils::{auth::Auth, option_ext::OptionExt};
3
+ use utils::{option_ext::OptionExt, rbac::RoleBasedAccessControl};
4
+
5
+ /// Role for fee configuration (set_default_fee_bps, set_fee_bps, set_fee_deposit_address).
6
+ pub const FEE_ADMIN_ROLE: &str = "FEE_ADMIN_ROLE";
4
7
 
5
8
  /// Base fee in basis points (10,000 BPS = 100%)
6
9
  /// Used as denominator in fee calculations
@@ -69,7 +72,7 @@ pub struct FeeDepositAddressSet {
69
72
  // =========================================================================
70
73
 
71
74
  #[contract_trait]
72
- pub trait OFTFee: OFTFeeInternal + Auth {
75
+ pub trait OFTFee: OFTFeeInternal + RoleBasedAccessControl {
73
76
  // =========================================================================
74
77
  // Management Functions
75
78
  // =========================================================================
@@ -79,8 +82,9 @@ pub trait OFTFee: OFTFeeInternal + Auth {
79
82
  /// - `Some(n)`: sets the default fee to `n` basis points (must be >0 and <=10,000).
80
83
  /// - `Some(0)`: rejected — use `None` to remove the default fee instead.
81
84
  /// - `None`: removes the default fee (effective rate becomes 0).
82
- #[only_auth]
83
- fn set_default_fee_bps(env: &soroban_sdk::Env, default_fee_bps: &Option<u32>) {
85
+ /// * `operator` - The address that must have FEE_ADMIN_ROLE
86
+ #[only_role(operator, FEE_ADMIN_ROLE)]
87
+ fn set_default_fee_bps(env: &soroban_sdk::Env, default_fee_bps: &Option<u32>, operator: &soroban_sdk::Address) {
84
88
  Self::__set_default_fee_bps(env, default_fee_bps);
85
89
  }
86
90
 
@@ -92,14 +96,23 @@ pub trait OFTFee: OFTFeeInternal + Auth {
92
96
  /// # Arguments
93
97
  /// * `dst_eid` - The destination endpoint ID
94
98
  /// * `fee_bps` - The fee rate (0-10,000), or None to remove the fee configuration
95
- #[only_auth]
96
- fn set_fee_bps(env: &soroban_sdk::Env, dst_eid: u32, fee_bps: &Option<u32>) {
99
+ /// * `operator` - The address that must have FEE_ADMIN_ROLE
100
+ #[only_role(operator, FEE_ADMIN_ROLE)]
101
+ fn set_fee_bps(env: &soroban_sdk::Env, dst_eid: u32, fee_bps: &Option<u32>, operator: &soroban_sdk::Address) {
97
102
  Self::__set_fee_bps(env, dst_eid, fee_bps);
98
103
  }
99
104
 
100
105
  /// Sets or removes the address where collected fees will be deposited.
101
- #[only_auth]
102
- fn set_fee_deposit_address(env: &soroban_sdk::Env, fee_deposit_address: &Option<soroban_sdk::Address>) {
106
+ ///
107
+ /// # Arguments
108
+ /// * `fee_deposit_address` - The address to deposit fees to, or None to remove the fee deposit address
109
+ /// * `operator` - The address that must have FEE_ADMIN_ROLE
110
+ #[only_role(operator, FEE_ADMIN_ROLE)]
111
+ fn set_fee_deposit_address(
112
+ env: &soroban_sdk::Env,
113
+ fee_deposit_address: &Option<soroban_sdk::Address>,
114
+ operator: &soroban_sdk::Address,
115
+ ) {
103
116
  Self::__set_fee_deposit_address(env, fee_deposit_address);
104
117
  }
105
118
 
@@ -134,7 +147,7 @@ pub trait OFTFee: OFTFeeInternal + Auth {
134
147
  }
135
148
 
136
149
  /// Internal trait for OFT fee operations used by OFT hooks.
137
- /// Contains only truly internal methods that are called from OFTInternal implementations.
150
+ /// Contains only truly internal methods that are called from OFTFee implementations.
138
151
  pub trait OFTFeeInternal {
139
152
  // =========================================================================
140
153
  // OFT Hooks
@@ -1,6 +1,12 @@
1
- use common_macros::{contract_error, contract_trait, only_auth, storage};
1
+ use common_macros::{contract_error, contract_trait, only_role, storage};
2
2
  use soroban_sdk::{assert_with_error, contractevent, Env};
3
- use utils::auth::Auth;
3
+ use utils::rbac::RoleBasedAccessControl;
4
+
5
+ /// Role for pausing the contract.
6
+ pub const PAUSER_ROLE: &str = "PAUSER_ROLE";
7
+
8
+ /// Role for unpausing the contract.
9
+ pub const UNPAUSER_ROLE: &str = "UNPAUSER_ROLE";
4
10
 
5
11
  // =========================================================================
6
12
  // Storage
@@ -37,18 +43,33 @@ pub struct PausedSet {
37
43
  // =========================================================================
38
44
 
39
45
  #[contract_trait]
40
- pub trait OFTPausable: OFTPausableInternal + Auth {
41
- /// Sets the paused state of the OFT.
46
+ pub trait OFTPausable: OFTPausableInternal + RoleBasedAccessControl {
47
+ // =========================================================================
48
+ // Management Functions
49
+ // =========================================================================
50
+
51
+ /// Pauses the OFT. When paused, the OFT will reject new send/receive/quote_send/quote_oft operations.
42
52
  ///
43
- /// When paused, the OFT will reject new send/receive/quote_send/quote_oft operations.
53
+ /// # Arguments
54
+ /// * `operator` - The address that must have PAUSER_ROLE
55
+ #[only_role(operator, PAUSER_ROLE)]
56
+ fn pause(env: &soroban_sdk::Env, operator: &soroban_sdk::Address) {
57
+ Self::__set_paused(env, true);
58
+ }
59
+
60
+ /// Unpauses the OFT.
44
61
  ///
45
62
  /// # Arguments
46
- /// * `paused` - `true` to pause, `false` to unpause
47
- #[only_auth]
48
- fn set_paused(env: &soroban_sdk::Env, paused: bool) {
49
- Self::__set_paused(env, paused);
63
+ /// * `operator` - The address that must have UNPAUSER_ROLE
64
+ #[only_role(operator, UNPAUSER_ROLE)]
65
+ fn unpause(env: &soroban_sdk::Env, operator: &soroban_sdk::Address) {
66
+ Self::__set_paused(env, false);
50
67
  }
51
68
 
69
+ // =========================================================================
70
+ // View Functions
71
+ // =========================================================================
72
+
52
73
  /// Returns the paused state of the OFT.
53
74
  fn is_paused(env: &soroban_sdk::Env) -> bool {
54
75
  Self::__is_paused(env)
@@ -56,7 +77,7 @@ pub trait OFTPausable: OFTPausableInternal + Auth {
56
77
  }
57
78
 
58
79
  /// Internal trait for pausable operations used by OFT hooks.
59
- /// Contains only truly internal methods that are called from OFTInternal implementations.
80
+ /// Contains only truly internal methods that are called from OFTPausable implementations.
60
81
  pub trait OFTPausableInternal {
61
82
  // =========================================================================
62
83
  // OFT Hooks
@@ -1,7 +1,10 @@
1
1
  use crate as oft;
2
- use common_macros::{contract_error, contract_trait, only_auth, storage};
2
+ use common_macros::{contract_error, contract_trait, only_role, storage};
3
3
  use soroban_sdk::{assert_with_error, contractevent, contracttype, Env};
4
- use utils::auth::Auth;
4
+ use utils::rbac::RoleBasedAccessControl;
5
+
6
+ /// Role for rate limiter configuration (set_rate_limit).
7
+ pub const RATE_LIMITER_ADMIN_ROLE: &str = "RATE_LIMITER_ADMIN_ROLE";
5
8
 
6
9
  // =========================================================================
7
10
  // Types
@@ -94,7 +97,7 @@ pub struct RateLimitSet {
94
97
  // =========================================================================
95
98
 
96
99
  #[contract_trait]
97
- pub trait RateLimiter: RateLimiterInternal + Auth {
100
+ pub trait RateLimiter: RateLimiterInternal + RoleBasedAccessControl {
98
101
  // =========================================================================
99
102
  // Management Functions
100
103
  // =========================================================================
@@ -105,12 +108,14 @@ pub trait RateLimiter: RateLimiterInternal + Auth {
105
108
  /// * `direction` - The direction (Inbound or Outbound)
106
109
  /// * `eid` - The endpoint ID
107
110
  /// * `config` - The rate limit configuration, or None to remove the rate limit
108
- #[only_auth]
111
+ /// * `operator` - The address that must have RATE_LIMITER_ADMIN_ROLE
112
+ #[only_role(operator, RATE_LIMITER_ADMIN_ROLE)]
109
113
  fn set_rate_limit(
110
114
  env: &soroban_sdk::Env,
111
115
  direction: &oft::rate_limiter::Direction,
112
116
  eid: u32,
113
117
  config: &Option<oft::rate_limiter::RateLimitConfig>,
118
+ operator: &soroban_sdk::Address,
114
119
  ) {
115
120
  Self::__set_rate_limit(env, direction, eid, config);
116
121
  }
@@ -7,7 +7,7 @@ use crate::{
7
7
  },
8
8
  oft_types::{lock_unlock, mint_burn, OftType},
9
9
  };
10
- use common_macros::{contract_impl, storage};
10
+ use common_macros::{contract_impl, lz_contract, storage};
11
11
  use oapp_macros::oapp;
12
12
  use oft_core::{
13
13
  impl_oft_lz_receive, utils as oft_utils, OFTCore, OFTError, OFTFeeDetail, OFTInternal, OFTLimit, OFTReceipt,
@@ -29,6 +29,7 @@ enum OFTStorage {
29
29
  // OFT Contract
30
30
  // =========================================================================
31
31
 
32
+ #[lz_contract]
32
33
  #[oapp]
33
34
  pub struct OFT;
34
35
 
@@ -42,11 +43,10 @@ impl OFT {
42
43
  token: &Address,
43
44
  shared_decimals: u32,
44
45
  oft_type: OftType,
45
- owner: &Address,
46
46
  endpoint: &Address,
47
47
  delegate: &Address,
48
48
  ) {
49
- Self::__initialize_oft(env, token, shared_decimals, owner, endpoint, delegate);
49
+ Self::__initialize_oft(env, token, shared_decimals, delegate, endpoint, delegate);
50
50
  OFTStorage::set_oft_type(env, &oft_type);
51
51
  }
52
52