@layerzerolabs/protocol-stellar-v2 0.2.29 → 0.2.30

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 (205) hide show
  1. package/.turbo/turbo-build.log +371 -321
  2. package/.turbo/turbo-lint.log +211 -202
  3. package/.turbo/turbo-test.log +1766 -1673
  4. package/Cargo.lock +11 -1
  5. package/contracts/common-macros/src/lib.rs +0 -2
  6. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +1 -0
  7. package/contracts/endpoint-v2/src/messaging_channel.rs +32 -3
  8. package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +1 -1
  9. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +1 -1
  10. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +6 -6
  11. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_payload_hash.rs +1 -1
  12. package/contracts/endpoint-v2/src/tests/messaging_channel/outbound.rs +16 -10
  13. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +10 -10
  14. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +3 -3
  15. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +4 -3
  16. package/contracts/macro-integration-tests/tests/runtime/upgradeable/migrate_guard_and_state.rs +1 -57
  17. package/contracts/macro-integration-tests/tests/ui/lz_contract/fail/upgradeable_missing_internal.stderr +0 -30
  18. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -3
  19. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +6 -4
  20. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -3
  21. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -3
  22. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_auth_trait.stderr +0 -30
  23. package/contracts/macro-integration-tests/tests/ui/upgradeable/fail/missing_upgradeable_internal.stderr +0 -30
  24. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/basic.rs +0 -2
  25. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/multisig_contract.rs +0 -2
  26. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/no_migration.rs +0 -2
  27. package/contracts/macro-integration-tests/tests/ui/upgradeable/pass/no_user_contractimpl.rs +1 -3
  28. package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +3 -6
  29. package/contracts/message-libs/message-lib-common/src/tests/worker_options/extract_type_3_options.rs +10 -0
  30. package/contracts/message-libs/message-lib-common/src/worker_options.rs +6 -2
  31. package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +3 -3
  32. package/contracts/message-libs/treasury/src/lib.rs +2 -1
  33. package/contracts/message-libs/treasury/src/tests/setup.rs +1 -1
  34. package/contracts/message-libs/treasury/src/treasury.rs +5 -2
  35. package/contracts/message-libs/uln-302/src/errors.rs +2 -0
  36. package/contracts/message-libs/uln-302/src/events.rs +3 -3
  37. package/contracts/message-libs/uln-302/src/interfaces/receive_uln.rs +8 -0
  38. package/contracts/message-libs/uln-302/src/lib.rs +2 -1
  39. package/contracts/message-libs/uln-302/src/receive_uln.rs +16 -13
  40. package/contracts/message-libs/uln-302/src/send_uln.rs +51 -24
  41. package/contracts/message-libs/uln-302/src/storage.rs +2 -2
  42. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +45 -1
  43. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verifiable.rs +63 -0
  44. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +47 -2
  45. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +50 -1
  46. package/contracts/message-libs/uln-302/src/uln302.rs +0 -8
  47. package/contracts/oapps/counter/Cargo.toml +4 -4
  48. package/contracts/oapps/counter/integration_tests/setup_uln.rs +22 -2
  49. package/contracts/oapps/counter/src/counter.rs +8 -8
  50. package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +33 -10
  51. package/contracts/oapps/oapp/src/lib.rs +6 -2
  52. package/contracts/oapps/oapp/src/oapp_core.rs +49 -24
  53. package/contracts/oapps/oapp/src/oapp_options_type3.rs +21 -14
  54. package/contracts/oapps/oapp/src/oapp_receiver.rs +17 -16
  55. package/contracts/oapps/oapp/src/oapp_sender.rs +66 -15
  56. package/contracts/oapps/oapp/src/tests/oapp_core.rs +5 -5
  57. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +18 -18
  58. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +4 -4
  59. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +3 -3
  60. package/contracts/oapps/oapp-macros/Cargo.toml +0 -1
  61. package/contracts/oapps/oapp-macros/src/generators.rs +87 -46
  62. package/contracts/oapps/oapp-macros/src/lib.rs +3 -61
  63. package/contracts/oapps/oapp-macros/src/tests/oapp.rs +9 -23
  64. package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +15 -11
  65. package/contracts/oapps/oft/Cargo.toml +1 -1
  66. package/contracts/oapps/oft/integration-tests/extensions/test_oft_fee.rs +3 -3
  67. package/contracts/oapps/oft/integration-tests/extensions/test_pausable.rs +4 -4
  68. package/contracts/oapps/oft/integration-tests/extensions/test_rate_limiter.rs +144 -8
  69. package/contracts/oapps/oft/integration-tests/setup.rs +4 -2
  70. package/contracts/oapps/oft/integration-tests/utils.rs +25 -11
  71. package/contracts/oapps/oft/src/extensions/oft_fee.rs +65 -63
  72. package/contracts/oapps/oft/src/extensions/pausable.rs +2 -3
  73. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +22 -5
  74. package/contracts/oapps/oft/src/interfaces/mint_burnable.rs +18 -0
  75. package/contracts/oapps/oft/src/interfaces/mod.rs +3 -0
  76. package/contracts/oapps/oft/src/lib.rs +4 -2
  77. package/contracts/oapps/oft/src/oft.rs +35 -36
  78. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +13 -9
  79. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +14 -9
  80. package/contracts/oapps/oft/src/oft_types/mod.rs +14 -12
  81. package/contracts/oapps/oft/src/tests/extensions/oft_fee.rs +28 -20
  82. package/contracts/oapps/oft/src/tests/extensions/rate_limiter.rs +136 -2
  83. package/contracts/oapps/oft/src/tests/oft_types/lock_unlock.rs +12 -8
  84. package/contracts/oapps/oft-core/integration-tests/setup.rs +8 -9
  85. package/contracts/oapps/oft-core/integration-tests/test_with_sml.rs +7 -6
  86. package/contracts/oapps/oft-core/integration-tests/utils.rs +5 -4
  87. package/contracts/oapps/oft-core/src/codec/oft_compose_msg_codec.rs +2 -2
  88. package/contracts/oapps/oft-core/src/codec/oft_msg_codec.rs +33 -37
  89. package/contracts/oapps/oft-core/src/errors.rs +2 -1
  90. package/contracts/oapps/oft-core/src/events.rs +6 -0
  91. package/contracts/oapps/oft-core/src/lib.rs +8 -4
  92. package/contracts/oapps/oft-core/src/oft_core.rs +205 -148
  93. package/contracts/oapps/oft-core/src/storage.rs +4 -2
  94. package/contracts/oapps/oft-core/src/tests/test_decimals.rs +2 -2
  95. package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +6 -6
  96. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +7 -6
  97. package/contracts/oapps/oft-core/src/tests/test_oft_msg_codec.rs +11 -82
  98. package/contracts/oapps/oft-core/src/tests/test_quote_oft.rs +13 -13
  99. package/contracts/oapps/oft-core/src/tests/test_quote_send.rs +1 -1
  100. package/contracts/oapps/oft-core/src/tests/test_resolve_address.rs +2 -2
  101. package/contracts/oapps/oft-core/src/tests/test_send.rs +22 -22
  102. package/contracts/oapps/oft-core/src/tests/test_utils.rs +20 -22
  103. package/contracts/oapps/oft-core/src/utils.rs +12 -8
  104. package/contracts/sac-manager/Cargo.toml +25 -0
  105. package/contracts/sac-manager/src/errors.rs +18 -0
  106. package/contracts/sac-manager/src/extensions/mod.rs +6 -0
  107. package/contracts/sac-manager/src/extensions/redistribution.rs +109 -0
  108. package/contracts/sac-manager/src/extensions/supply_control/mod.rs +488 -0
  109. package/contracts/sac-manager/src/extensions/supply_control/rate_limit.rs +126 -0
  110. package/contracts/sac-manager/src/interfaces/mod.rs +3 -0
  111. package/contracts/sac-manager/src/interfaces/sac_manager.rs +52 -0
  112. package/contracts/sac-manager/src/lib.rs +23 -0
  113. package/contracts/sac-manager/src/sac_manager.rs +193 -0
  114. package/contracts/sac-manager/src/storage.rs +20 -0
  115. package/contracts/sac-manager/src/tests/mod.rs +14 -0
  116. package/contracts/sac-manager/src/tests/redistribution/mod.rs +1 -0
  117. package/contracts/sac-manager/src/tests/redistribution/redistribute_funds.rs +82 -0
  118. package/contracts/sac-manager/src/tests/sac_manager/admin_mint.rs +206 -0
  119. package/contracts/sac-manager/src/tests/sac_manager/burn.rs +215 -0
  120. package/contracts/sac-manager/src/tests/sac_manager/clawback.rs +209 -0
  121. package/contracts/sac-manager/src/tests/sac_manager/mint.rs +252 -0
  122. package/contracts/sac-manager/src/tests/sac_manager/mod.rs +9 -0
  123. package/contracts/sac-manager/src/tests/sac_manager/set_admin.rs +36 -0
  124. package/contracts/sac-manager/src/tests/sac_manager/set_authorized.rs +43 -0
  125. package/contracts/sac-manager/src/tests/sac_manager/set_oft_address.rs +47 -0
  126. package/contracts/sac-manager/src/tests/sac_manager/test_helper.rs +75 -0
  127. package/contracts/sac-manager/src/tests/sac_manager/view_functions.rs +60 -0
  128. package/contracts/sac-manager/src/tests/supply_control/enumerable_set.rs +256 -0
  129. package/contracts/sac-manager/src/tests/supply_control/mod.rs +8 -0
  130. package/contracts/sac-manager/src/tests/supply_control/refill.rs +90 -0
  131. package/contracts/sac-manager/src/tests/supply_control/set_mint_whitelist.rs +245 -0
  132. package/contracts/sac-manager/src/tests/supply_control/set_supply_controller.rs +267 -0
  133. package/contracts/sac-manager/src/tests/supply_control/set_supply_controller_manager.rs +122 -0
  134. package/contracts/sac-manager/src/tests/supply_control/test_helper.rs +38 -0
  135. package/contracts/sac-manager/src/tests/supply_control/update_allow_any_mint_burn.rs +114 -0
  136. package/contracts/sac-manager/src/tests/supply_control/update_limit_config.rs +257 -0
  137. package/contracts/sac-manager/src/tests/test_helper.rs +190 -0
  138. package/contracts/upgrader/src/lib.rs +2 -1
  139. package/contracts/utils/src/errors.rs +0 -1
  140. package/contracts/utils/src/tests/upgradeable.rs +0 -66
  141. package/contracts/utils/src/upgradeable.rs +0 -18
  142. package/contracts/workers/dvn/src/dvn.rs +2 -2
  143. package/contracts/workers/dvn/src/interfaces/dvn.rs +2 -2
  144. package/contracts/workers/dvn/src/lib.rs +2 -1
  145. package/contracts/workers/dvn-fee-lib/src/lib.rs +3 -1
  146. package/contracts/workers/executor/src/auth.rs +42 -26
  147. package/contracts/workers/executor/src/executor.rs +28 -3
  148. package/contracts/workers/executor/src/lib.rs +4 -2
  149. package/contracts/workers/executor/src/storage.rs +21 -1
  150. package/contracts/workers/executor/src/tests/auth.rs +64 -20
  151. package/contracts/workers/executor/src/tests/executor.rs +1 -1
  152. package/contracts/workers/executor/src/tests/setup.rs +18 -0
  153. package/contracts/workers/executor-fee-lib/src/lib.rs +4 -1
  154. package/contracts/workers/executor-helper/src/executor_helper.rs +24 -10
  155. package/contracts/workers/executor-helper/src/tests/setup.rs +147 -34
  156. package/contracts/workers/price-feed/src/lib.rs +3 -1
  157. package/contracts/workers/worker/src/lib.rs +2 -1
  158. package/contracts/workers/worker/src/worker.rs +31 -17
  159. package/docs/oapp-guide.md +17 -8
  160. package/docs/oft-guide.md +3 -3
  161. package/package.json +3 -3
  162. package/sdk/.turbo/turbo-test.log +512 -351
  163. package/sdk/dist/generated/bml.d.ts +3 -9
  164. package/sdk/dist/generated/bml.js +6 -7
  165. package/sdk/dist/generated/counter.d.ts +22 -28
  166. package/sdk/dist/generated/counter.js +11 -12
  167. package/sdk/dist/generated/dvn.d.ts +36 -54
  168. package/sdk/dist/generated/dvn.js +10 -15
  169. package/sdk/dist/generated/dvn_fee_lib.d.ts +3 -21
  170. package/sdk/dist/generated/dvn_fee_lib.js +6 -11
  171. package/sdk/dist/generated/endpoint.d.ts +3 -9
  172. package/sdk/dist/generated/endpoint.js +6 -7
  173. package/sdk/dist/generated/executor.d.ts +80 -54
  174. package/sdk/dist/generated/executor.js +16 -16
  175. package/sdk/dist/generated/executor_fee_lib.d.ts +3 -21
  176. package/sdk/dist/generated/executor_fee_lib.js +6 -11
  177. package/sdk/dist/generated/executor_helper.d.ts +36 -42
  178. package/sdk/dist/generated/executor_helper.js +9 -10
  179. package/sdk/dist/generated/layerzero_view.d.ts +20 -32
  180. package/sdk/dist/generated/layerzero_view.js +25 -26
  181. package/sdk/dist/generated/oft.d.ts +147 -79
  182. package/sdk/dist/generated/oft.js +47 -54
  183. package/sdk/dist/generated/price_feed.d.ts +20 -38
  184. package/sdk/dist/generated/price_feed.js +15 -20
  185. package/sdk/dist/generated/sac_manager.d.ts +1309 -0
  186. package/sdk/dist/generated/sac_manager.js +484 -0
  187. package/sdk/dist/generated/sml.d.ts +3 -9
  188. package/sdk/dist/generated/sml.js +6 -7
  189. package/sdk/dist/generated/treasury.d.ts +3 -9
  190. package/sdk/dist/generated/treasury.js +8 -9
  191. package/sdk/dist/generated/uln302.d.ts +20 -20
  192. package/sdk/dist/generated/uln302.js +25 -22
  193. package/sdk/dist/generated/upgrader.d.ts +3 -9
  194. package/sdk/dist/generated/upgrader.js +6 -7
  195. package/sdk/dist/index.d.ts +1 -0
  196. package/sdk/dist/index.js +1 -0
  197. package/sdk/package.json +1 -1
  198. package/sdk/src/index.ts +1 -0
  199. package/sdk/test/oft-sml.test.ts +7 -5
  200. package/sdk/test/sac-manager-redistribution.test.ts +578 -0
  201. package/sdk/test/suites/globalSetup.ts +11 -6
  202. package/sdk/test/test_data/test_upgradeable_dvn.wasm +0 -0
  203. package/sdk/test/upgrader.test.ts +75 -202
  204. package/sdk/test/utils.ts +40 -0
  205. package/tools/ts-bindings-gen/src/main.rs +1 -0
@@ -68,7 +68,7 @@ fn test_effective_send_uln_config_with_custom_config() {
68
68
  assert_eq_event(
69
69
  &env,
70
70
  &uln302.address,
71
- SendUlnConfigSet { config: custom_config.clone(), dst_eid: eid, sender: oapp.clone() },
71
+ SendUlnConfigSet { config: Some(custom_config.clone()), dst_eid: eid, sender: oapp.clone() },
72
72
  );
73
73
 
74
74
  // Get aggregated config - should have custom confirmations but default DVNs
@@ -112,3 +112,52 @@ fn test_effective_send_uln_config_must_have_at_least_one_dvn() {
112
112
  let result = endpoint.try_set_config(&Address::generate(&env), &oapp, &uln302.address, &params);
113
113
  assert_eq!(result.err().unwrap().ok().unwrap(), Uln302Error::UlnAtLeastOneDVN.into());
114
114
  }
115
+
116
+ #[test]
117
+ fn test_remove_send_uln_config_by_setting_none() {
118
+ let setup = setup();
119
+
120
+ let default_config = UlnConfig::generate(&setup.env, 10, 2, 3, 2);
121
+ let eid = 100;
122
+
123
+ setup.set_default_configs(eid, default_config.clone());
124
+
125
+ let TestSetup { env, uln302, endpoint, .. } = setup;
126
+
127
+ let oapp = Address::generate(&env);
128
+
129
+ // Step 1: Set a custom send ULN config
130
+ let custom_config = OAppUlnConfig {
131
+ use_default_confirmations: false,
132
+ use_default_required_dvns: true,
133
+ use_default_optional_dvns: true,
134
+ uln_config: UlnConfig {
135
+ confirmations: 20,
136
+ required_dvns: vec![&env],
137
+ optional_dvns: vec![&env],
138
+ optional_dvn_threshold: 0,
139
+ },
140
+ };
141
+
142
+ let config_bytes = custom_config.clone().to_xdr(&env);
143
+ let params = vec![&env, SetConfigParam { eid, config_type: CONFIG_TYPE_SEND_ULN, config: config_bytes }];
144
+ endpoint.set_config(&Address::generate(&env), &oapp, &uln302.address, &params);
145
+
146
+ // Verify custom config is applied
147
+ let config = uln302.effective_send_uln_config(&oapp, &eid);
148
+ assert_eq!(config.confirmations, 20);
149
+ assert!(uln302.oapp_send_uln_config(&oapp, &eid).is_some());
150
+
151
+ // Step 2: Remove the custom config by setting None
152
+ let none_config: Option<OAppUlnConfig> = None;
153
+ let config_bytes = none_config.to_xdr(&env);
154
+ let params = vec![&env, SetConfigParam { eid, config_type: CONFIG_TYPE_SEND_ULN, config: config_bytes }];
155
+ endpoint.set_config(&Address::generate(&env), &oapp, &uln302.address, &params);
156
+
157
+ // Verify the OApp-specific config is removed
158
+ assert_eq!(uln302.oapp_send_uln_config(&oapp, &eid), None);
159
+
160
+ // Verify the effective config falls back to defaults
161
+ let config = uln302.effective_send_uln_config(&oapp, &eid);
162
+ assert_eq!(config, default_config);
163
+ }
@@ -30,10 +30,6 @@ impl Uln302 {
30
30
  UlnStorage::set_treasury(env, treasury);
31
31
  }
32
32
 
33
- // ============================================================================================
34
- // View Functions
35
- // ============================================================================================
36
-
37
33
  /// Returns the LayerZero endpoint contract address.
38
34
  pub fn endpoint(env: &Env) -> Address {
39
35
  UlnStorage::endpoint(env).unwrap()
@@ -95,10 +91,6 @@ impl IMessageLib for Uln302 {
95
91
  }
96
92
  }
97
93
 
98
- // ============================================================================================
99
- // Helper Functions
100
- // ============================================================================================
101
-
102
94
  /// Parse a config from XDR bytes, panicking with InvalidConfig error if parsing fails
103
95
  fn parse_config<T: FromXdr>(env: &Env, config_bytes: &Bytes) -> T {
104
96
  T::from_xdr(env, config_bytes).ok().unwrap_or_panic(env, Uln302Error::InvalidConfig)
@@ -19,17 +19,17 @@ oapp-macros = { workspace = true }
19
19
  [dev-dependencies]
20
20
  soroban-sdk = { workspace = true, features = ["testutils"] }
21
21
  utils = { workspace = true, features = ["testutils"] }
22
- simple-message-lib = { workspace = true }
22
+ simple-message-lib = { workspace = true, features = ["testutils"] }
23
23
  blocked-message-lib = { workspace = true }
24
24
  message-lib-common = { workspace = true, features = ["testutils"] }
25
25
  endpoint-v2 = { workspace = true, features = ["testutils"] }
26
26
  executor = { workspace = true, features = ["testutils"] }
27
27
  uln302 = { workspace = true, features = ["testutils"] }
28
28
  dvn = { workspace = true, features = ["testutils"] }
29
- dvn-fee-lib = { workspace = true }
30
- executor-fee-lib = { workspace = true }
29
+ dvn-fee-lib = { workspace = true, features = ["testutils"] }
30
+ executor-fee-lib = { workspace = true, features = ["testutils"] }
31
31
  treasury = { workspace = true, features = ["testutils"] }
32
- price-feed = { workspace = true }
32
+ price-feed = { workspace = true, features = ["testutils"] }
33
33
  fee-lib-interfaces = { workspace = true }
34
34
  executor-helper = { workspace = true }
35
35
  # For real DVN signature verification in integration tests
@@ -10,7 +10,7 @@ use crate::{
10
10
  use dvn::{DVNClient, DstConfig as DvnDstConfig, DstConfigParam as DvnDstConfigParam, LzDVN};
11
11
  use dvn_fee_lib::DvnFeeLib;
12
12
  use endpoint_v2::{EndpointV2, EndpointV2Client};
13
- use executor::{DstConfig as ExecutorDstConfig, ExecutorClient, LzExecutor, SetDstConfigParam};
13
+ use executor::{DstConfig as ExecutorDstConfig, ExecutorClient, LzExecutor, LzExecutorClient, SetDstConfigParam};
14
14
  use executor_fee_lib::ExecutorFeeLib;
15
15
  use executor_helper::{ExecutorHelper, ExecutorHelperClient};
16
16
  use fee_lib_interfaces::Price;
@@ -18,7 +18,7 @@ use price_feed::{types::UpdatePrice, LzPriceFeed};
18
18
  use soroban_sdk::{
19
19
  testutils::{Address as _, MockAuth, MockAuthInvoke},
20
20
  token::TokenClient,
21
- vec, Address, BytesN, Env, IntoVal, Vec,
21
+ vec, Address, BytesN, Env, IntoVal, Symbol, Vec,
22
22
  };
23
23
  use treasury::Treasury;
24
24
  use uln302::{
@@ -493,6 +493,26 @@ fn setup_chain_workers<'a>(
493
493
  let executor = ExecutorClient::new(env, &executor_address);
494
494
  let executor_helper = ExecutorHelperClient::new(env, &executor_helper_address);
495
495
 
496
+ // Register the executor helper with the executor (address + allowed function names)
497
+ let allowed_functions: Vec<Symbol> = vec![
498
+ env,
499
+ Symbol::new(env, "execute"),
500
+ Symbol::new(env, "compose"),
501
+ Symbol::new(env, "native_drop_and_execute"),
502
+ ];
503
+ let admin = &infra.admin;
504
+ let lz_executor = LzExecutorClient::new(env, &executor_address);
505
+ env.mock_auths(&[MockAuth {
506
+ address: admin,
507
+ invoke: &MockAuthInvoke {
508
+ contract: &executor_address,
509
+ fn_name: "set_executor_helper",
510
+ args: (admin, &executor_helper_address, &allowed_functions).into_val(env),
511
+ sub_invokes: &[],
512
+ },
513
+ }]);
514
+ lz_executor.set_executor_helper(admin, &executor_helper_address, &allowed_functions);
515
+
496
516
  (dvn, dvn2, executor, executor_helper)
497
517
  }
498
518
 
@@ -12,7 +12,7 @@ use endpoint_v2::{
12
12
  use oapp::{
13
13
  oapp_core::{initialize_oapp, OAppCore},
14
14
  oapp_receiver::{LzReceiveInternal, OAppReceiver},
15
- oapp_sender::OAppSenderInternal,
15
+ oapp_sender::{FeePayer, OAppSenderInternal},
16
16
  };
17
17
  use oapp_macros::oapp;
18
18
  use soroban_sdk::{assert_with_error, panic_with_error, token::TokenClient, Address, Bytes, BytesN, Env};
@@ -23,7 +23,7 @@ pub struct Counter;
23
23
  #[contract_impl]
24
24
  impl Counter {
25
25
  pub fn __constructor(env: &Env, owner: &Address, endpoint: &Address, delegate: &Address) {
26
- initialize_oapp::<Self>(env, owner, endpoint, &Some(delegate.clone()));
26
+ initialize_oapp::<Self>(env, owner, endpoint, delegate);
27
27
  let endpoint_client = LayerZeroEndpointV2Client::new(env, endpoint);
28
28
  CounterStorage::set_eid(env, &endpoint_client.eid());
29
29
  }
@@ -39,9 +39,9 @@ impl Counter {
39
39
  let outbound_count = Self::outbound_count(env, dst_eid);
40
40
  CounterStorage::set_outbound_count(env, dst_eid, &(outbound_count + 1));
41
41
 
42
- // Send the message
42
+ // Send the message — caller already authorized via require_auth() above
43
43
  let message = codec::encode(env, (msg_type as u8).into(), Self::eid(env));
44
- Self::__lz_send(env, dst_eid, &message, options, caller, fee, caller);
44
+ Self::__lz_send(env, dst_eid, &message, options, &FeePayer::Verified(caller.clone()), fee, caller);
45
45
  }
46
46
 
47
47
  // ============================================================================================
@@ -152,14 +152,14 @@ impl LzReceiveInternal for Counter {
152
152
  let outbound_count = Self::outbound_count(env, origin.src_eid);
153
153
  CounterStorage::set_outbound_count(env, origin.src_eid, &(outbound_count + 1));
154
154
 
155
- // Send the response message
155
+ // Send the response message — contract is the fee payer (auto-authorized)
156
156
  let options = options::executor_lz_receive_option(env, 200000, 10);
157
157
  Self::__lz_send(
158
158
  env,
159
159
  origin.src_eid,
160
160
  &codec::encode_with_value(env, MsgType::Vanilla, Self::eid(env), 10),
161
161
  &options,
162
- &contract_address,
162
+ &FeePayer::Verified(contract_address.clone()),
163
163
  &MessagingFee { native_fee: value, zro_fee: 0 },
164
164
  &contract_address,
165
165
  );
@@ -221,14 +221,14 @@ impl ILayerZeroComposer for Counter {
221
221
  // Increment the outbound count
222
222
  CounterStorage::set_outbound_count(env, src_eid, &(Self::outbound_count(env, src_eid) + 1));
223
223
 
224
- // Send the response message
224
+ // Send the response message — contract is the fee payer (auto-authorized)
225
225
  let curr_address = env.current_contract_address();
226
226
  Self::__lz_send(
227
227
  env,
228
228
  src_eid,
229
229
  &codec::encode(env, MsgType::Vanilla, Self::eid(env)),
230
230
  &options::executor_lz_receive_option(env, 200000, 0),
231
- &curr_address,
231
+ &FeePayer::Verified(curr_address.clone()),
232
232
  &MessagingFee { native_fee: value, zro_fee: 0 },
233
233
  &curr_address,
234
234
  );
@@ -3,9 +3,28 @@
3
3
  //! This module defines the `IOAppMsgInspector` trait that external inspector contracts
4
4
  //! must implement to validate outgoing LayerZero messages and options.
5
5
  //!
6
+ //! Implementations can signal failure in two ways:
7
+ //! - Return `false` to indicate the inspection failed.
8
+ //! - Panic directly to abort the transaction immediately.
9
+ //!
6
10
  //! ## Usage
7
11
  //!
8
- //! Inspector contracts should implement this trait and panic if inspection fails:
12
+ //! ### Returning a boolean
13
+ //!
14
+ //! ```ignore
15
+ //! use oapp::interfaces::IOAppMsgInspector;
16
+ //!
17
+ //! pub struct MyInspector;
18
+ //!
19
+ //! #[contractimpl]
20
+ //! impl IOAppMsgInspector for MyInspector {
21
+ //! fn inspect(env: &Env, oapp: &Address, message: &Bytes, options: &Bytes) -> bool {
22
+ //! is_valid(message, options)
23
+ //! }
24
+ //! }
25
+ //! ```
26
+ //!
27
+ //! ### Panicking on failure
9
28
  //!
10
29
  //! ```ignore
11
30
  //! use oapp::interfaces::IOAppMsgInspector;
@@ -14,12 +33,11 @@
14
33
  //!
15
34
  //! #[contractimpl]
16
35
  //! impl IOAppMsgInspector for MyInspector {
17
- //! fn inspect(env: &Env, oapp: &Address, message: &Bytes, options: &Bytes) {
18
- //! // Validate message and options
19
- //! // Panic if invalid
36
+ //! fn inspect(env: &Env, oapp: &Address, message: &Bytes, options: &Bytes) -> bool {
20
37
  //! if !is_valid(message, options) {
21
38
  //! panic_with_error!(env, MyError::InspectionFailed);
22
39
  //! }
40
+ //! true
23
41
  //! }
24
42
  //! }
25
43
  //! ```
@@ -31,17 +49,22 @@ use soroban_sdk::{contractclient, Address, Bytes, Env};
31
49
  /// Contracts implementing this trait can be set as message inspectors on OFT contracts
32
50
  /// to validate outgoing messages and options before they are sent cross-chain.
33
51
  ///
34
- /// If inspection fails, the implementation should panic to revert the transaction.
52
+ /// Implementations may either return `false` to indicate failure, or panic directly
53
+ /// to abort the transaction.
35
54
  #[contractclient(name = "OAppMsgInspectorClient")]
36
55
  pub trait IOAppMsgInspector {
37
- /// Inspects the LayerZero message and options before sending.
56
+ /// Allows the inspector to examine LayerZero message contents and determine their validity.
38
57
  ///
39
58
  /// # Arguments
40
59
  /// * `oapp` - The address of the OApp contract sending the message
41
- /// * `message` - The encoded message payload to be sent
42
- /// * `options` - The LayerZero options for the message
60
+ /// * `message` - The message payload to be inspected.
61
+ /// * `options` - Additional LayerZero options for inspection.
62
+ ///
63
+ /// # Returns
64
+ /// * `bool` - `true` if the inspection passed, `false` if the message or options are invalid.
43
65
  ///
44
66
  /// # Panics
45
- /// Should panic if the message or options are invalid, reverting the transaction.
46
- fn inspect(env: &Env, oapp: &Address, message: &Bytes, options: &Bytes);
67
+ /// Implementations may choose to panic instead of returning `false` to abort the
68
+ /// transaction immediately with a specific error.
69
+ fn inspect(env: &Env, oapp: &Address, message: &Bytes, options: &Bytes) -> bool;
47
70
  }
@@ -1,11 +1,15 @@
1
1
  #![no_std]
2
2
 
3
- pub mod errors;
4
- pub mod interfaces;
5
3
  pub mod oapp_core;
6
4
  pub mod oapp_options_type3;
7
5
  pub mod oapp_receiver;
8
6
  pub mod oapp_sender;
9
7
 
8
+ mod errors;
9
+ mod interfaces;
10
+
11
+ pub use errors::*;
12
+ pub use interfaces::*;
13
+
10
14
  #[cfg(test)]
11
15
  mod tests;
@@ -1,28 +1,8 @@
1
+ use crate::{errors::OAppError, oapp_receiver::RECEIVER_VERSION, oapp_sender::SENDER_VERSION};
1
2
  use common_macros::{contract_trait, only_auth, storage};
2
3
  use endpoint_v2::LayerZeroEndpointV2Client;
3
4
  use soroban_sdk::{contractevent, Address, BytesN, Env};
4
- use utils::ownable::{Ownable, OwnableInitializer};
5
-
6
- /// Initializes the OApp with the specified configuration.
7
- ///
8
- /// This function sets up the OApp by initializing ownership, storing the LayerZero endpoint,
9
- /// and optionally setting a delegate address for the endpoint.
10
- ///
11
- /// # Arguments
12
- /// * `env` - The Soroban environment
13
- /// * `owner` - The address that will own this OApp
14
- /// * `endpoint` - The LayerZero endpoint address to associate with this OApp
15
- /// * `delegate` - Optional delegate address to set on the endpoint for this OApp
16
- pub fn initialize_oapp<T: OAppCore + OwnableInitializer>(
17
- env: &Env,
18
- owner: &Address,
19
- endpoint: &Address,
20
- delegate: &Option<Address>,
21
- ) {
22
- T::init_owner(env, owner);
23
- OAppCoreStorage::set_endpoint(env, endpoint);
24
- LayerZeroEndpointV2Client::new(env, endpoint).set_delegate(&env.current_contract_address(), delegate);
25
- }
5
+ use utils::{option_ext::OptionExt, ownable::{Ownable, OwnableInitializer}};
26
6
 
27
7
  // =====================================================
28
8
  // OAppCore Storage and Events
@@ -30,10 +10,11 @@ pub fn initialize_oapp<T: OAppCore + OwnableInitializer>(
30
10
 
31
11
  #[storage]
32
12
  pub enum OAppCoreStorage {
33
- // Immutable endpoint address
13
+ // Endpoint address - set once during initialization
34
14
  #[instance(Address)]
35
15
  Endpoint,
36
16
 
17
+ // Mapping from endpoint ID to remote peer address
37
18
  #[persistent(BytesN<32>)]
38
19
  Peer { eid: u32 },
39
20
  }
@@ -58,7 +39,7 @@ pub trait OAppCore: Ownable {
58
39
  /// - `sender_version`: The version of the OAppSender
59
40
  /// - `receiver_version`: The version of the OAppReceiver
60
41
  fn oapp_version(_env: &soroban_sdk::Env) -> (u64, u64) {
61
- (1, 1)
42
+ (SENDER_VERSION, RECEIVER_VERSION)
62
43
  }
63
44
 
64
45
  /// Retrieves the LayerZero endpoint address associated with the OApp.
@@ -101,6 +82,50 @@ pub trait OAppCore: Ownable {
101
82
  }
102
83
  }
103
84
 
85
+ // =====================================================
86
+ // Helper Functions
87
+ // =====================================================
88
+
89
+ /// Initializes the OApp with the specified configuration.
90
+ ///
91
+ /// This function sets up the OApp by initializing ownership, storing the LayerZero endpoint,
92
+ /// and setting a delegate address for the endpoint.
93
+ ///
94
+ /// # Arguments
95
+ /// * `env` - The Soroban environment
96
+ /// * `owner` - The address that will own this OApp
97
+ /// * `endpoint` - The LayerZero endpoint address to associate with this OApp
98
+ /// * `delegate` - The delegate address to set on the endpoint for this OApp
99
+ pub fn initialize_oapp<T: OAppCore + OwnableInitializer>(
100
+ env: &Env,
101
+ owner: &Address,
102
+ endpoint: &Address,
103
+ delegate: &Address,
104
+ ) {
105
+ T::init_owner(env, owner);
106
+ OAppCoreStorage::set_endpoint(env, endpoint);
107
+ LayerZeroEndpointV2Client::new(env, endpoint)
108
+ .set_delegate(&env.current_contract_address(), &Some(delegate.clone()));
109
+ }
110
+
111
+ /// Retrieves the peer address associated with a specific endpoint ID; panics if NOT set.
112
+ ///
113
+ /// This is a safe getter that ensures a peer has been configured for the given endpoint.
114
+ /// If no peer is set (i.e., the peer is `None`), it will panic with `OAppError::NoPeer`.
115
+ ///
116
+ /// # Arguments
117
+ /// * `env` - The Soroban environment
118
+ /// * `eid` - The endpoint ID
119
+ ///
120
+ /// # Returns
121
+ /// The peer address (`BytesN<32>`) associated with the specified endpoint
122
+ ///
123
+ /// # Panics
124
+ /// Panics with `OAppError::NoPeer` if no peer is set for the given endpoint ID
125
+ pub fn get_peer_or_panic<T: OAppCore>(env: &Env, eid: u32) -> BytesN<32> {
126
+ T::peer(env, eid).unwrap_or_panic(env, OAppError::NoPeer)
127
+ }
128
+
104
129
  /// Returns a client for the LayerZero endpoint.
105
130
  pub fn endpoint_client<'a, T: OAppCore>(env: &'a Env) -> LayerZeroEndpointV2Client<'a> {
106
131
  LayerZeroEndpointV2Client::new(env, &T::endpoint(env))
@@ -1,7 +1,7 @@
1
1
  use crate::{self as oapp, errors::OAppError};
2
2
  use common_macros::{contract_trait, only_auth, storage};
3
3
  use soroban_sdk::{assert_with_error, contractevent, contracttype, panic_with_error, Bytes, Env, Vec};
4
- use utils::{buffer_reader::BufferReader, ownable::Ownable};
4
+ use utils::{auth::Auth, buffer_reader::BufferReader};
5
5
 
6
6
  pub const OPTION_TYPE3: u16 = 3;
7
7
 
@@ -10,20 +10,19 @@ pub const OPTION_TYPE3: u16 = 3;
10
10
  pub struct EnforcedOptionParam {
11
11
  pub eid: u32,
12
12
  pub msg_type: u32,
13
- pub options: Bytes,
13
+ pub options: Option<Bytes>,
14
14
  }
15
15
 
16
16
  #[storage]
17
17
  pub enum OAppOptionsType3Storage {
18
18
  #[persistent(Bytes)]
19
- #[default(Bytes::new(env))]
20
19
  EnforcedOptions { eid: u32, msg_type: u32 },
21
20
  }
22
21
 
23
22
  #[contractevent]
24
23
  #[derive(Clone, Debug, Eq, PartialEq)]
25
24
  pub struct EnforcedOptionSet {
26
- pub enforced_option_params: Vec<EnforcedOptionParam>,
25
+ pub enforced_options: Vec<EnforcedOptionParam>,
27
26
  }
28
27
 
29
28
  // =========================================================================
@@ -31,7 +30,7 @@ pub struct EnforcedOptionSet {
31
30
  // =========================================================================
32
31
 
33
32
  #[contract_trait]
34
- pub trait OAppOptionsType3: Ownable {
33
+ pub trait OAppOptionsType3: Auth {
35
34
  /// Retrieves the enforced options for a given endpoint and message type.
36
35
  ///
37
36
  /// # Arguments
@@ -40,11 +39,11 @@ pub trait OAppOptionsType3: Ownable {
40
39
  ///
41
40
  /// # Returns
42
41
  /// The enforced options for the given endpoint and message type
43
- fn enforced_options(env: &soroban_sdk::Env, eid: u32, msg_type: u32) -> soroban_sdk::Bytes {
42
+ fn enforced_options(env: &soroban_sdk::Env, eid: u32, msg_type: u32) -> Option<soroban_sdk::Bytes> {
44
43
  OAppOptionsType3Storage::enforced_options(env, eid, msg_type)
45
44
  }
46
45
 
47
- /// Sets the enforced options for specific endpoint and message type combinations.
46
+ /// Sets or removes the enforced options for specific endpoint and message type combinations.
48
47
  ///
49
48
  /// Only the `authorizer` of the OApp can call this function.
50
49
  /// Provides a way for the OApp to enforce things like paying for PreCrime, AND/OR minimum dst lzReceive gas amounts etc.
@@ -57,13 +56,15 @@ pub trait OAppOptionsType3: Ownable {
57
56
  #[only_auth]
58
57
  fn set_enforced_options(
59
58
  env: &soroban_sdk::Env,
60
- options: soroban_sdk::Vec<oapp::oapp_options_type3::EnforcedOptionParam>,
59
+ options: &soroban_sdk::Vec<oapp::oapp_options_type3::EnforcedOptionParam>,
61
60
  ) {
62
- for option in &options {
63
- assert_option_type3(env, &option.options);
64
- OAppOptionsType3Storage::set_enforced_options(env, option.eid, option.msg_type, &option.options);
61
+ for param in options {
62
+ if let Some(ref opts) = param.options {
63
+ assert_option_type3(env, opts);
64
+ }
65
+ OAppOptionsType3Storage::set_or_remove_enforced_options(env, param.eid, param.msg_type, &param.options);
65
66
  }
66
- EnforcedOptionSet { enforced_option_params: options }.publish(env);
67
+ EnforcedOptionSet { enforced_options: options.clone() }.publish(env);
67
68
  }
68
69
 
69
70
  /// Combines options for a given endpoint and message type.
@@ -86,23 +87,29 @@ pub trait OAppOptionsType3: Ownable {
86
87
  msg_type: u32,
87
88
  extra_options: &soroban_sdk::Bytes,
88
89
  ) -> soroban_sdk::Bytes {
89
- let mut enforced_options = Self::enforced_options(env, eid, msg_type);
90
+ let enforced_options_opt = Self::enforced_options(env, eid, msg_type);
90
91
 
91
- if enforced_options.is_empty() {
92
+ // No enforced options, pass whatever the caller supplied, even if it's empty or legacy type 1/2 options.
93
+ if enforced_options_opt.is_none() {
92
94
  return extra_options.clone();
93
95
  }
94
96
 
97
+ // No caller options, return enforced
98
+ let mut enforced_options = enforced_options_opt.unwrap(); // unwrap is safe because we checked if it is none above
95
99
  if extra_options.is_empty() {
96
100
  return enforced_options;
97
101
  }
98
102
 
103
+ // If caller provided extra_options, must be type 3 as its the ONLY type that can be combined.
99
104
  if extra_options.len() >= 2 {
100
105
  assert_option_type3(env, extra_options);
101
106
 
107
+ // Remove the first 2 bytes containing the type from the extra_options and combine with enforced.
102
108
  enforced_options.append(&extra_options.slice(2..));
103
109
  return enforced_options;
104
110
  }
105
111
 
112
+ // No valid set of options was found.
106
113
  panic_with_error!(env, OAppError::InvalidOptions);
107
114
  }
108
115
  }
@@ -1,11 +1,15 @@
1
1
  use crate::{
2
2
  errors::OAppError,
3
- oapp_core::{endpoint_client, OAppCore},
3
+ oapp_core::{endpoint_client, get_peer_or_panic, OAppCore},
4
4
  };
5
5
  use common_macros::contract_trait;
6
6
  use endpoint_v2::Origin;
7
7
  use soroban_sdk::{assert_with_error, token::TokenClient, Address, Bytes, BytesN, Env};
8
8
 
9
+ /// The version of the OAppReceiver implementation.
10
+ /// Version is bumped when changes are made to this contract.
11
+ pub const RECEIVER_VERSION: u64 = 1;
12
+
9
13
  // =====================================================
10
14
  // LzReceiveInternal Trait
11
15
  // =====================================================
@@ -43,12 +47,12 @@ pub trait LzReceiveInternal {
43
47
  /// these methods via `LayerZeroReceiverClient`.
44
48
  ///
45
49
  /// # Default Implementations
46
- /// | Method | Behavior |
47
- /// |--------|----------|
48
- /// | `allow_initialize_path` | Returns true if origin sender matches configured peer |
49
- /// | `next_nonce` | Returns 0 (unordered delivery) |
50
- /// | `lz_receive` | Verifies payload, then calls `LzReceiveInternal::__lz_receive` |
51
- /// | `is_compose_msg_sender` | Returns true if sender is current contract |
50
+ /// | Method | Behavior |
51
+ /// |--------------------------|----------------------------------------------------------------|
52
+ /// | `allow_initialize_path` | Returns true if origin sender matches configured peer |
53
+ /// | `next_nonce` | Returns 0 (unordered delivery) |
54
+ /// | `lz_receive` | Verifies payload, then calls `LzReceiveInternal::__lz_receive` |
55
+ /// | `is_compose_msg_sender` | Returns true if sender is current contract |
52
56
  ///
53
57
  /// # Usage
54
58
  ///
@@ -171,23 +175,20 @@ pub fn clear_payload_and_transfer<T: OAppCore>(
171
175
  message: &Bytes,
172
176
  value: i128,
173
177
  ) {
178
+ // Require authorization from the executor and transfer the value from the executor to the oapp if has value
179
+ executor.require_auth();
180
+ // Assert that the message is from the expected peer
181
+ assert_with_error!(env, get_peer_or_panic::<T>(env, origin.src_eid) == origin.sender, OAppError::OnlyPeer);
182
+
174
183
  let this_address = env.current_contract_address();
175
184
  let endpoint_client = endpoint_client::<T>(env);
176
185
 
177
- // Require authorization from the executor and transfer the value from the executor to the oapp if has value
178
- executor.require_auth();
186
+ // Transfer the value from the executor to the oapp if has value
179
187
  if value != 0 {
180
188
  let token_client = TokenClient::new(env, &endpoint_client.native_token());
181
189
  token_client.transfer(executor, &this_address, &value);
182
190
  }
183
191
 
184
- // Assert that the message is from the expected peer
185
- assert_with_error!(
186
- env,
187
- T::peer(env, origin.src_eid).is_some_and(|peer| peer == origin.sender),
188
- OAppError::OnlyPeer
189
- );
190
-
191
192
  // Clear the message payload from the endpoint
192
193
  endpoint_client.clear(&this_address, origin, &this_address, guid, message);
193
194
  }