@layerzerolabs/protocol-stellar-v2 0.2.20 → 0.2.21

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 (198) hide show
  1. package/.turbo/turbo-build.log +783 -802
  2. package/.turbo/turbo-lint.log +320 -157
  3. package/.turbo/turbo-test.log +1414 -1457
  4. package/Cargo.lock +109 -108
  5. package/Cargo.toml +32 -18
  6. package/contracts/common-macros/Cargo.toml +7 -7
  7. package/contracts/common-macros/src/auth.rs +18 -37
  8. package/contracts/common-macros/src/contract_ttl.rs +2 -2
  9. package/contracts/common-macros/src/lib.rs +27 -10
  10. package/contracts/common-macros/src/lz_contract.rs +38 -7
  11. package/contracts/common-macros/src/storage.rs +251 -292
  12. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
  13. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -9
  16. package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
  17. package/contracts/common-macros/src/ttl_configurable.rs +2 -10
  18. package/contracts/common-macros/src/ttl_extendable.rs +2 -10
  19. package/contracts/common-macros/src/upgradeable.rs +56 -15
  20. package/contracts/common-macros/src/utils.rs +0 -9
  21. package/contracts/endpoint-v2/src/lib.rs +3 -2
  22. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
  23. package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
  24. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
  25. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
  26. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
  27. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
  28. package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
  29. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
  30. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
  31. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
  32. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
  33. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
  34. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
  35. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
  36. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
  37. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
  38. package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
  39. package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
  40. package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
  41. package/contracts/layerzero-views/Cargo.toml +0 -1
  42. package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
  43. package/contracts/macro-integration-tests/Cargo.toml +5 -15
  44. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
  45. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
  46. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
  47. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
  48. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
  49. package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
  50. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
  51. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
  52. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
  53. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
  54. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
  55. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
  56. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
  57. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
  58. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
  59. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
  60. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
  61. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
  62. package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
  63. package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
  64. package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
  65. package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
  66. package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
  67. package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
  68. package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
  69. package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
  70. package/contracts/message-libs/treasury/Cargo.toml +0 -2
  71. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
  72. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
  73. package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
  74. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
  75. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
  76. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
  77. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +7 -27
  78. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
  79. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
  80. package/contracts/oapps/counter/Cargo.toml +4 -6
  81. package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
  82. package/contracts/oapps/oapp/src/errors.rs +1 -1
  83. package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
  84. package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
  85. package/contracts/oapps/oapp/src/lib.rs +1 -0
  86. package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
  87. package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
  88. package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
  89. package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
  90. package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
  91. package/contracts/oapps/oapp/src/tests/{test_oapp_core.rs → oapp_core.rs} +4 -4
  92. package/contracts/oapps/oapp/src/tests/{test_oapp_options_type3.rs → oapp_options_type3.rs} +3 -4
  93. package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
  94. package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
  95. package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
  96. package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
  97. package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
  98. package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
  99. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
  100. package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
  101. package/contracts/oapps/oft/src/extensions/oft_fee.rs +136 -74
  102. package/contracts/oapps/oft/src/extensions/pausable.rs +44 -10
  103. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +170 -130
  104. package/contracts/oapps/oft/src/oft.rs +19 -12
  105. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
  106. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +1 -1
  107. package/contracts/oapps/oft-core/Cargo.toml +1 -4
  108. package/contracts/oapps/oft-core/integration-tests/setup.rs +2 -2
  109. package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
  110. package/contracts/oapps/oft-core/src/errors.rs +3 -2
  111. package/contracts/oapps/oft-core/src/events.rs +6 -0
  112. package/contracts/oapps/oft-core/src/lib.rs +1 -1
  113. package/contracts/oapps/oft-core/src/oft_core.rs +115 -60
  114. package/contracts/oapps/oft-core/src/storage.rs +7 -3
  115. package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
  116. package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
  117. package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
  118. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
  119. package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
  120. package/contracts/oapps/oft-core/src/tests/test_utils.rs +59 -14
  121. package/contracts/utils/Cargo.toml +0 -1
  122. package/contracts/utils/src/errors.rs +1 -1
  123. package/contracts/utils/src/multisig.rs +17 -8
  124. package/contracts/utils/src/ownable.rs +6 -6
  125. package/contracts/utils/src/testing_utils.rs +124 -54
  126. package/contracts/utils/src/tests/multisig.rs +12 -12
  127. package/contracts/utils/src/tests/ownable.rs +6 -6
  128. package/contracts/utils/src/tests/testing_utils.rs +50 -167
  129. package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
  130. package/contracts/utils/src/tests/upgradeable.rs +1 -1
  131. package/contracts/utils/src/ttl_configurable.rs +10 -4
  132. package/contracts/utils/src/upgradeable.rs +5 -5
  133. package/contracts/workers/dvn/Cargo.toml +5 -6
  134. package/contracts/workers/dvn/src/dvn.rs +2 -12
  135. package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
  136. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +37 -19
  137. package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
  138. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +15 -13
  139. package/contracts/workers/executor/Cargo.toml +3 -0
  140. package/contracts/workers/executor/src/executor.rs +2 -12
  141. package/contracts/workers/executor/src/lib.rs +2 -2
  142. package/contracts/workers/executor/src/tests/auth.rs +394 -0
  143. package/contracts/workers/executor/src/tests/executor.rs +410 -0
  144. package/contracts/workers/executor/src/tests/mod.rs +3 -0
  145. package/contracts/workers/executor/src/tests/setup.rs +250 -0
  146. package/contracts/workers/executor-fee-lib/Cargo.toml +5 -0
  147. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +1 -12
  148. package/contracts/workers/executor-fee-lib/src/lib.rs +8 -2
  149. package/contracts/workers/executor-helper/Cargo.toml +0 -1
  150. package/contracts/workers/price-feed/Cargo.toml +5 -0
  151. package/contracts/workers/price-feed/src/lib.rs +9 -4
  152. package/contracts/workers/price-feed/src/price_feed.rs +1 -11
  153. package/contracts/workers/worker/src/errors.rs +1 -1
  154. package/contracts/workers/worker/src/tests/setup.rs +1 -1
  155. package/contracts/workers/worker/src/tests/worker.rs +55 -41
  156. package/contracts/workers/worker/src/worker.rs +34 -25
  157. package/docs/error-spec.md +55 -0
  158. package/docs/layerzero-v2-on-stellar.md +447 -0
  159. package/docs/oapp-guide.md +212 -0
  160. package/docs/oft-guide.md +314 -0
  161. package/package.json +3 -3
  162. package/sdk/.turbo/turbo-test.log +260 -257
  163. package/sdk/dist/generated/bml.d.ts +3 -3
  164. package/sdk/dist/generated/bml.js +4 -4
  165. package/sdk/dist/generated/counter.d.ts +295 -295
  166. package/sdk/dist/generated/counter.js +43 -43
  167. package/sdk/dist/generated/dvn.d.ts +91 -91
  168. package/sdk/dist/generated/dvn.js +24 -24
  169. package/sdk/dist/generated/dvn_fee_lib.d.ts +92 -92
  170. package/sdk/dist/generated/dvn_fee_lib.js +25 -25
  171. package/sdk/dist/generated/endpoint.d.ts +99 -99
  172. package/sdk/dist/generated/endpoint.js +16 -16
  173. package/sdk/dist/generated/executor.d.ts +91 -91
  174. package/sdk/dist/generated/executor.js +24 -24
  175. package/sdk/dist/generated/executor_fee_lib.d.ts +92 -92
  176. package/sdk/dist/generated/executor_fee_lib.js +25 -25
  177. package/sdk/dist/generated/executor_helper.d.ts +3 -3
  178. package/sdk/dist/generated/executor_helper.js +4 -4
  179. package/sdk/dist/generated/layerzero_view.d.ts +186 -186
  180. package/sdk/dist/generated/layerzero_view.js +35 -35
  181. package/sdk/dist/generated/oft.d.ts +366 -352
  182. package/sdk/dist/generated/oft.js +74 -79
  183. package/sdk/dist/generated/price_feed.d.ts +198 -198
  184. package/sdk/dist/generated/price_feed.js +39 -39
  185. package/sdk/dist/generated/sml.d.ts +99 -99
  186. package/sdk/dist/generated/sml.js +16 -16
  187. package/sdk/dist/generated/treasury.d.ts +99 -99
  188. package/sdk/dist/generated/treasury.js +16 -16
  189. package/sdk/dist/generated/uln302.d.ts +99 -99
  190. package/sdk/dist/generated/uln302.js +16 -16
  191. package/sdk/dist/generated/upgrader.d.ts +3 -3
  192. package/sdk/dist/generated/upgrader.js +3 -3
  193. package/sdk/package.json +1 -1
  194. package/sdk/test/suites/localnet.ts +84 -20
  195. package/contracts/ERROR_SPEC.md +0 -51
  196. package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
  197. /package/contracts/oapps/oapp/src/tests/{test_oapp_receiver.rs → oapp_receiver.rs} +0 -0
  198. /package/contracts/oapps/oapp/src/tests/{test_oapp_sender.rs → oapp_sender.rs} +0 -0
@@ -2,33 +2,32 @@ use crate::errors::DvnFeeLibError;
2
2
  use common_macros::{contract_impl, lz_contract};
3
3
  use fee_lib_interfaces::{DvnFeeParams, IDvnFeeLib, LayerZeroPriceFeedClient};
4
4
  use soroban_sdk::{assert_with_error, Address, Env};
5
- use utils::upgradeable::UpgradeableInternal;
6
5
 
7
6
  // ============================================================================
8
7
  // Constants
9
8
  // ============================================================================
10
9
 
11
10
  /// Basis points denominator (10000 = 100%).
12
- pub(crate) const BPS_BASE: i128 = 10000;
11
+ const BPS_BASE: i128 = 10000;
13
12
 
14
13
  /// Fixed bytes for execute function call.
15
- pub(crate) const EXECUTE_FIXED_BYTES: u32 = 260;
14
+ const EXECUTE_FIXED_BYTES: u32 = 260;
16
15
 
17
16
  /// Raw signature bytes length (65 bytes: 64 for signature + 1 for recovery ID).
18
- pub(crate) const SIGNATURE_RAW_BYTES: u32 = 65;
17
+ const SIGNATURE_RAW_BYTES: u32 = 65;
19
18
 
20
19
  /// Verify function bytes (padded).
21
- pub(crate) const VERIFY_BYTES: u32 = 288;
20
+ const VERIFY_BYTES: u32 = 288;
22
21
 
23
22
  /// Native token decimal rate for XLM (10^7 stroops per XLM).
24
- pub(crate) const NATIVE_DECIMALS_RATE: u128 = 10_000_000;
23
+ const NATIVE_DECIMALS_RATE: u128 = 10_000_000;
25
24
 
26
25
  /// DVN fee library contract for calculating DVN verification fees.
27
26
  ///
28
27
  /// Provides fee calculation logic based on quorum size, destination gas costs,
29
28
  /// and current gas prices from the price feed. Handles fee multipliers and
30
29
  /// floor margins.
31
- #[lz_contract(upgradeable)]
30
+ #[lz_contract(upgradeable(no_migration))]
32
31
  pub struct DvnFeeLib;
33
32
 
34
33
  #[contract_impl]
@@ -66,16 +65,6 @@ impl IDvnFeeLib for DvnFeeLib {
66
65
  }
67
66
  }
68
67
 
69
- // ============================================================================
70
- // Upgradeable Implementation
71
- // ============================================================================
72
-
73
- /// No migration logic needed for initial upgrade capability
74
- impl UpgradeableInternal for DvnFeeLib {
75
- type MigrationData = ();
76
- fn __migrate(_env: &Env, _migration_data: &Self::MigrationData) {}
77
- }
78
-
79
68
  // ============================================================================
80
69
  // Internal Helper Functions
81
70
  // ============================================================================
@@ -94,7 +83,7 @@ impl UpgradeableInternal for DvnFeeLib {
94
83
  ///
95
84
  /// # Returns
96
85
  /// Fee with premium applied (max of multiplier fee and margin fee).
97
- pub(crate) fn apply_premium(
86
+ fn apply_premium(
98
87
  env: &Env,
99
88
  fee: i128,
100
89
  multiplier_bps: u32,
@@ -126,7 +115,7 @@ pub(crate) fn apply_premium(
126
115
  ///
127
116
  /// # Returns
128
117
  /// Total calldata size in bytes.
129
- pub(crate) fn get_call_data_size(quorum: u32) -> u32 {
118
+ fn get_call_data_size(quorum: u32) -> u32 {
130
119
  let mut total_signature_bytes = quorum * SIGNATURE_RAW_BYTES;
131
120
  if !total_signature_bytes.is_multiple_of(32) {
132
121
  total_signature_bytes = total_signature_bytes - (total_signature_bytes % 32) + 32;
@@ -139,3 +128,32 @@ fn safe_u128_to_i128(env: &Env, value: u128) -> i128 {
139
128
  assert_with_error!(env, value <= i128::MAX as u128, DvnFeeLibError::Overflow);
140
129
  value as i128
141
130
  }
131
+
132
+ /// Test-only module exposing internal items for unit and integration tests.
133
+ #[cfg(test)]
134
+ pub(crate) mod test {
135
+ use super::*;
136
+
137
+ // Re-export constants for testing
138
+ pub const BPS_BASE: i128 = super::BPS_BASE;
139
+ pub const EXECUTE_FIXED_BYTES: u32 = super::EXECUTE_FIXED_BYTES;
140
+ pub const VERIFY_BYTES: u32 = super::VERIFY_BYTES;
141
+ pub const NATIVE_DECIMALS_RATE: u128 = super::NATIVE_DECIMALS_RATE;
142
+
143
+ /// Test-only wrapper for apply_premium to enable testing.
144
+ pub fn apply_premium_for_test(
145
+ env: &Env,
146
+ fee: i128,
147
+ multiplier_bps: u32,
148
+ default_multiplier_bps: u32,
149
+ floor_margin_usd: u128,
150
+ native_price_usd: u128,
151
+ ) -> i128 {
152
+ super::apply_premium(env, fee, multiplier_bps, default_multiplier_bps, floor_margin_usd, native_price_usd)
153
+ }
154
+
155
+ /// Test-only wrapper for get_call_data_size to enable testing.
156
+ pub fn get_call_data_size_for_test(quorum: u32) -> u32 {
157
+ super::get_call_data_size(quorum)
158
+ }
159
+ }
@@ -1,9 +1,19 @@
1
1
  #![no_std]
2
2
 
3
- pub mod dvn_fee_lib;
4
3
  pub mod errors;
5
4
 
6
- pub use dvn_fee_lib::{DvnFeeLib, DvnFeeLibClient};
5
+ cfg_if::cfg_if! {
6
+ // Include implementation when NOT in library mode, OR when testutils is enabled (for tests)
7
+ if #[cfg(any(not(feature = "library"), feature = "testutils"))] {
8
+ mod dvn_fee_lib;
9
+ // Export the contract and client for testing purposes
10
+ pub use dvn_fee_lib::{DvnFeeLib, DvnFeeLibClient};
11
+ }
12
+ }
13
+
14
+ // Re-export test helpers module for integration tests
15
+ #[cfg(test)]
16
+ use dvn_fee_lib::test;
7
17
 
8
18
  #[cfg(test)]
9
19
  extern crate std;
@@ -1,18 +1,20 @@
1
- use crate::dvn_fee_lib::{
2
- apply_premium, get_call_data_size, DvnFeeLib, BPS_BASE, EXECUTE_FIXED_BYTES, NATIVE_DECIMALS_RATE, VERIFY_BYTES,
1
+ use crate::test::{
2
+ apply_premium_for_test, get_call_data_size_for_test, BPS_BASE, EXECUTE_FIXED_BYTES, NATIVE_DECIMALS_RATE,
3
+ VERIFY_BYTES,
3
4
  };
5
+ use crate::DvnFeeLib;
4
6
  use fee_lib_interfaces::{DvnFeeParams, FeeEstimate, IDvnFeeLib};
5
7
  use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, Bytes, Env};
6
8
 
7
9
  #[test]
8
10
  fn get_call_data_size_pads_signatures() {
9
- let size = get_call_data_size(1);
11
+ let size = get_call_data_size_for_test(1);
10
12
  assert_eq!(size, EXECUTE_FIXED_BYTES + VERIFY_BYTES + 96 + 32);
11
13
 
12
- let size = get_call_data_size(2);
14
+ let size = get_call_data_size_for_test(2);
13
15
  assert_eq!(size, EXECUTE_FIXED_BYTES + VERIFY_BYTES + 160 + 32);
14
16
 
15
- let size = get_call_data_size(32);
17
+ let size = get_call_data_size_for_test(32);
16
18
  assert_eq!(size, EXECUTE_FIXED_BYTES + VERIFY_BYTES + 2080 + 32);
17
19
  }
18
20
 
@@ -22,7 +24,7 @@ fn apply_premium_multiplier_only_both_zero() {
22
24
  let fee = 1_000i128;
23
25
  let multiplier_bps = 15_000u32;
24
26
  // multiplier_bps is non-zero, so default_multiplier_bps is ignored
25
- let result = apply_premium(&env, fee, multiplier_bps, 10_000, 0, 0);
27
+ let result = apply_premium_for_test(&env, fee, multiplier_bps, 10_000, 0, 0);
26
28
  assert_eq!(result, fee * multiplier_bps as i128 / BPS_BASE);
27
29
  }
28
30
 
@@ -31,7 +33,7 @@ fn apply_premium_multiplier_only_native_price_zero() {
31
33
  let env = Env::default();
32
34
  let fee = 1_000i128;
33
35
  let multiplier_bps = 15_000u32;
34
- let result = apply_premium(&env, fee, multiplier_bps, 10_000, 100, 0);
36
+ let result = apply_premium_for_test(&env, fee, multiplier_bps, 10_000, 100, 0);
35
37
  assert_eq!(result, fee * multiplier_bps as i128 / BPS_BASE);
36
38
  }
37
39
 
@@ -40,7 +42,7 @@ fn apply_premium_multiplier_only_floor_margin_zero() {
40
42
  let env = Env::default();
41
43
  let fee = 1_000i128;
42
44
  let multiplier_bps = 15_000u32;
43
- let result = apply_premium(&env, fee, multiplier_bps, 10_000, 0, NATIVE_DECIMALS_RATE);
45
+ let result = apply_premium_for_test(&env, fee, multiplier_bps, 10_000, 0, NATIVE_DECIMALS_RATE);
44
46
  assert_eq!(result, fee * multiplier_bps as i128 / BPS_BASE);
45
47
  }
46
48
 
@@ -50,7 +52,7 @@ fn apply_premium_uses_default_when_multiplier_zero() {
50
52
  let fee = 1_000i128;
51
53
  let default_bps = 12_000u32;
52
54
  // multiplier_bps is 0, so default_multiplier_bps should be used
53
- let result = apply_premium(&env, fee, 0, default_bps, 0, 0);
55
+ let result = apply_premium_for_test(&env, fee, 0, default_bps, 0, 0);
54
56
  assert_eq!(result, fee * default_bps as i128 / BPS_BASE);
55
57
  }
56
58
 
@@ -62,7 +64,7 @@ fn apply_premium_floor_margin_wins() {
62
64
  let floor_margin_usd = 10u128;
63
65
  let native_price_usd = NATIVE_DECIMALS_RATE;
64
66
 
65
- let result = apply_premium(&env, fee, multiplier_bps, 10_000, floor_margin_usd, native_price_usd);
67
+ let result = apply_premium_for_test(&env, fee, multiplier_bps, 10_000, floor_margin_usd, native_price_usd);
66
68
  assert_eq!(result, fee + floor_margin_usd as i128);
67
69
  }
68
70
 
@@ -74,7 +76,7 @@ fn apply_premium_multiplier_wins_over_small_floor() {
74
76
  let floor_margin_usd = 1u128;
75
77
  let native_price_usd = NATIVE_DECIMALS_RATE;
76
78
 
77
- let result = apply_premium(&env, fee, multiplier_bps, 10_000, floor_margin_usd, native_price_usd);
79
+ let result = apply_premium_for_test(&env, fee, multiplier_bps, 10_000, floor_margin_usd, native_price_usd);
78
80
  assert_eq!(result, 1_200);
79
81
  }
80
82
 
@@ -281,7 +283,7 @@ fn apply_premium_panics_on_overflow() {
281
283
  let env = Env::default();
282
284
  let fee = i128::MAX / 2;
283
285
  let multiplier_bps = 20_000u32;
284
- apply_premium(&env, fee, multiplier_bps, 10_000, u128::MAX, 1);
286
+ apply_premium_for_test(&env, fee, multiplier_bps, 10_000, u128::MAX, 1);
285
287
  }
286
288
 
287
289
  #[test]
@@ -292,6 +294,6 @@ fn apply_premium_floor_margin_truncates() {
292
294
  let floor_margin_usd = 1u128;
293
295
  let native_price_usd = NATIVE_DECIMALS_RATE * 3 / 2;
294
296
 
295
- let result = apply_premium(&env, fee, multiplier_bps, 10_000, floor_margin_usd, native_price_usd);
297
+ let result = apply_premium_for_test(&env, fee, multiplier_bps, 10_000, floor_margin_usd, native_price_usd);
296
298
  assert_eq!(result, 0);
297
299
  }
@@ -26,5 +26,8 @@ endpoint-v2 = { workspace = true, features = ["library"] }
26
26
 
27
27
  [dev-dependencies]
28
28
  soroban-sdk = { workspace = true, features = ["testutils"] }
29
+ rand = { workspace = true }
30
+ ed25519-dalek = { workspace = true }
31
+ utils = { workspace = true, features = ["testutils"] }
29
32
 
30
33
 
@@ -10,14 +10,14 @@ use endpoint_v2::{FeeRecipient, LayerZeroEndpointV2Client, Origin};
10
10
  use fee_lib_interfaces::{ExecutorFeeLibClient, FeeParams};
11
11
  use message_lib_common::interfaces::ILayerZeroExecutor;
12
12
  use soroban_sdk::{token::TokenClient, vec, Address, Bytes, BytesN, Env, Vec};
13
- use utils::{option_ext::OptionExt, upgradeable::UpgradeableInternal};
13
+ use utils::option_ext::OptionExt;
14
14
  use worker::{
15
15
  assert_acl, assert_not_paused, assert_supported_message_lib, errors::WorkerError, init_worker, require_admin_auth,
16
16
  Worker,
17
17
  };
18
18
 
19
19
  /// LayerZero Executor contract for cross-chain message execution.
20
- #[lz_contract(upgradeable)]
20
+ #[lz_contract(upgradeable(no_migration))]
21
21
  pub struct LzExecutor;
22
22
 
23
23
  #[contract_impl]
@@ -194,16 +194,6 @@ impl ILayerZeroExecutor for LzExecutor {
194
194
  #[contract_impl(contracttrait)]
195
195
  impl Worker for LzExecutor {}
196
196
 
197
- // ============================================================================
198
- // Upgradeable Implementation
199
- // ============================================================================
200
-
201
- /// No migration logic needed for initial upgrade capability
202
- impl UpgradeableInternal for LzExecutor {
203
- type MigrationData = ();
204
- fn __migrate(_env: &Env, _migration_data: &Self::MigrationData) {}
205
- }
206
-
207
197
  // ============================================================================
208
198
  // Include SubModules
209
199
  // ============================================================================
@@ -16,5 +16,5 @@ cfg_if::cfg_if! {
16
16
  }
17
17
  }
18
18
 
19
- // #[cfg(test)]
20
- // mod tests;
19
+ #[cfg(test)]
20
+ mod tests;
@@ -0,0 +1,394 @@
1
+ use super::setup::{Ed25519KeyPair, TestSetup};
2
+ use crate::auth::ExecutorSignature;
3
+ use crate::errors::ExecutorError;
4
+ use soroban_sdk::auth::{Context, ContractContext, CreateContractHostFnContext};
5
+ use soroban_sdk::testutils::Address as _;
6
+ use soroban_sdk::{vec, Address, BytesN, Env, IntoVal, Symbol, Val, Vec};
7
+
8
+ fn mk_sig(setup: &TestSetup<'_>, admin_kp: &Ed25519KeyPair, payload: &BytesN<32>) -> ExecutorSignature {
9
+ ExecutorSignature {
10
+ public_key: admin_kp.public_key(&setup.env),
11
+ signature: admin_kp.sign_payload(&setup.env, payload),
12
+ }
13
+ }
14
+
15
+ fn contract_ctx(env: &Env, contract: Address, fn_name: &str, args: Vec<Val>) -> Context {
16
+ Context::Contract(ContractContext { contract, fn_name: Symbol::new(env, fn_name), args })
17
+ }
18
+
19
+ fn check_auth(
20
+ setup: &TestSetup<'_>,
21
+ payload: &BytesN<32>,
22
+ sig: ExecutorSignature,
23
+ auth_contexts: &Vec<Context>,
24
+ ) -> Result<(), Result<ExecutorError, soroban_sdk::InvokeError>> {
25
+ setup.env.try_invoke_contract_check_auth::<ExecutorError>(
26
+ &setup.contract_id,
27
+ payload,
28
+ sig.into_val(&setup.env),
29
+ auth_contexts,
30
+ )
31
+ }
32
+
33
+ #[test]
34
+ fn test_check_auth_allows_lz_receive_value_zero_single_context() {
35
+ let env = Env::default();
36
+ let admin_kp = Ed25519KeyPair::generate();
37
+ let admin_addr = admin_kp.address(&env);
38
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
39
+
40
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
41
+ let sig = mk_sig(&setup, &admin_kp, &payload);
42
+
43
+ // Executor auth expects `lz_receive`/`lz_compose` contexts and requires the last arg to be `value: i128`.
44
+ // Use value = 0 so only a single context is required.
45
+ let args: Vec<Val> = vec![&setup.env, 0i128.into_val(&setup.env)];
46
+ let oapp = Address::generate(&setup.env);
47
+ let auth_contexts: Vec<Context> = vec![&setup.env, contract_ctx(&setup.env, oapp, "lz_receive", args)];
48
+
49
+ let res = check_auth(&setup, &payload, sig, &auth_contexts);
50
+ assert!(res.is_ok(), "Expected success, got {:?}", res);
51
+ }
52
+
53
+ #[test]
54
+ fn test_check_auth_allows_lz_compose_value_zero_single_context() {
55
+ let env = Env::default();
56
+ let admin_kp = Ed25519KeyPair::generate();
57
+ let admin_addr = admin_kp.address(&env);
58
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
59
+
60
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
61
+ let sig = mk_sig(&setup, &admin_kp, &payload);
62
+
63
+ let args: Vec<Val> = vec![&setup.env, 0i128.into_val(&setup.env)];
64
+ let composer = Address::generate(&setup.env);
65
+ let auth_contexts: Vec<Context> = vec![&setup.env, contract_ctx(&setup.env, composer, "lz_compose", args)];
66
+
67
+ let res = check_auth(&setup, &payload, sig, &auth_contexts);
68
+ assert!(res.is_ok(), "Expected success, got {:?}", res);
69
+ }
70
+
71
+ #[test]
72
+ fn test_check_auth_allows_value_transfer_when_value_nonzero() {
73
+ let env = Env::default();
74
+ let admin_kp = Ed25519KeyPair::generate();
75
+ let admin_addr = admin_kp.address(&env);
76
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
77
+
78
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
79
+ let sig = mk_sig(&setup, &admin_kp, &payload);
80
+
81
+ let value: i128 = 123;
82
+ let oapp = Address::generate(&setup.env);
83
+ let exec_args: Vec<Val> = vec![&setup.env, value.into_val(&setup.env)];
84
+
85
+ let from = Address::generate(&setup.env);
86
+ let to = Address::generate(&setup.env);
87
+ let transfer_args: Vec<Val> =
88
+ vec![&setup.env, from.into_val(&setup.env), to.into_val(&setup.env), value.into_val(&setup.env)];
89
+
90
+ let auth_contexts: Vec<Context> = vec![
91
+ &setup.env,
92
+ contract_ctx(&setup.env, oapp, "lz_receive", exec_args),
93
+ contract_ctx(&setup.env, setup.native_token.clone(), "transfer", transfer_args),
94
+ ];
95
+
96
+ let res = check_auth(&setup, &payload, sig, &auth_contexts);
97
+ assert!(res.is_ok(), "Expected success, got {:?}", res);
98
+ }
99
+
100
+ #[test]
101
+ fn test_check_auth_allows_alert_calls_only_on_endpoint() {
102
+ let env = Env::default();
103
+ let admin_kp = Ed25519KeyPair::generate();
104
+ let admin_addr = admin_kp.address(&env);
105
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
106
+
107
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
108
+ let sig = mk_sig(&setup, &admin_kp, &payload);
109
+
110
+ let empty_args: Vec<Val> = Vec::new(&setup.env);
111
+ for fn_name in ["lz_receive_alert", "lz_compose_alert"] {
112
+ let contexts: Vec<Context> =
113
+ vec![&setup.env, contract_ctx(&setup.env, setup.endpoint.clone(), fn_name, empty_args.clone())];
114
+ let res = check_auth(&setup, &payload, sig.clone(), &contexts);
115
+ assert!(res.is_ok(), "Expected success for {fn_name}, got {:?}", res);
116
+ }
117
+ }
118
+
119
+ #[test]
120
+ fn test_check_auth_rejects_signature_mismatch() {
121
+ let env = Env::default();
122
+ let admin_kp = Ed25519KeyPair::generate();
123
+ let admin_addr = admin_kp.address(&env);
124
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
125
+
126
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
127
+ let other_kp = Ed25519KeyPair::generate();
128
+
129
+ // Admin pubkey is registered, but signature is produced by a different key.
130
+ let sig = ExecutorSignature {
131
+ public_key: admin_kp.public_key(&setup.env),
132
+ signature: other_kp.sign_payload(&setup.env, &payload),
133
+ };
134
+
135
+ let oapp = Address::generate(&setup.env);
136
+ let args: Vec<Val> = vec![&setup.env, 0i128.into_val(&setup.env)];
137
+ let contexts: Vec<Context> = vec![&setup.env, contract_ctx(&setup.env, oapp, "lz_receive", args)];
138
+
139
+ let res = check_auth(&setup, &payload, sig, &contexts);
140
+ assert!(matches!(res, Err(Err(_))), "Expected host error, got {:?}", res);
141
+ }
142
+
143
+ #[test]
144
+ fn test_check_auth_rejects_non_admin() {
145
+ let env = Env::default();
146
+ let admin_kp = Ed25519KeyPair::generate();
147
+ let admin_addr = admin_kp.address(&env);
148
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
149
+
150
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
151
+ let oapp = Address::generate(&setup.env);
152
+ let args: Vec<Val> = vec![&setup.env, 0i128.into_val(&setup.env)];
153
+ let contexts: Vec<Context> = vec![&setup.env, contract_ctx(&setup.env, oapp, "lz_receive", args)];
154
+
155
+ // Unauthorized: signer not in admins list
156
+ let non_admin_kp = Ed25519KeyPair::generate();
157
+ let sig = ExecutorSignature {
158
+ public_key: non_admin_kp.public_key(&setup.env),
159
+ signature: non_admin_kp.sign_payload(&setup.env, &payload),
160
+ };
161
+
162
+ let res = check_auth(&setup, &payload, sig, &contexts);
163
+ assert_eq!(res, Err(Ok(ExecutorError::Unauthorized)));
164
+ }
165
+
166
+ #[test]
167
+ fn test_check_auth_rejects_empty_or_too_many_contexts() {
168
+ let env = Env::default();
169
+ let admin_kp = Ed25519KeyPair::generate();
170
+ let admin_addr = admin_kp.address(&env);
171
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
172
+
173
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
174
+ let sig = mk_sig(&setup, &admin_kp, &payload);
175
+
176
+ // Empty contexts
177
+ let empty: Vec<Context> = Vec::new(&setup.env);
178
+ assert_eq!(check_auth(&setup, &payload, sig.clone(), &empty), Err(Ok(ExecutorError::UnauthorizedContext)));
179
+
180
+ // Too many contexts (>2)
181
+ let oapp = Address::generate(&setup.env);
182
+ let args0: Vec<Val> = vec![&setup.env, 0i128.into_val(&setup.env)];
183
+ let too_many: Vec<Context> = vec![
184
+ &setup.env,
185
+ contract_ctx(&setup.env, oapp.clone(), "lz_receive", args0.clone()),
186
+ contract_ctx(&setup.env, oapp.clone(), "lz_receive", args0.clone()),
187
+ contract_ctx(&setup.env, oapp, "lz_receive", args0),
188
+ ];
189
+ assert_eq!(check_auth(&setup, &payload, sig, &too_many), Err(Ok(ExecutorError::UnauthorizedContext)));
190
+ }
191
+
192
+ #[test]
193
+ fn test_check_auth_rejects_non_contract_first_context() {
194
+ let env = Env::default();
195
+ let admin_kp = Ed25519KeyPair::generate();
196
+ let admin_addr = admin_kp.address(&env);
197
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
198
+
199
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
200
+ let sig = mk_sig(&setup, &admin_kp, &payload);
201
+
202
+ let create_ctx: Vec<Context> = vec![
203
+ &setup.env,
204
+ Context::CreateContractHostFn(CreateContractHostFnContext {
205
+ executable: soroban_sdk::auth::ContractExecutable::Wasm(BytesN::from_array(&setup.env, &[2u8; 32])),
206
+ salt: BytesN::from_array(&setup.env, &[3u8; 32]),
207
+ }),
208
+ ];
209
+ assert_eq!(check_auth(&setup, &payload, sig, &create_ctx), Err(Ok(ExecutorError::UnauthorizedContext)));
210
+ }
211
+
212
+ #[test]
213
+ fn test_check_auth_rejects_invalid_execute_fn_name() {
214
+ let env = Env::default();
215
+ let admin_kp = Ed25519KeyPair::generate();
216
+ let admin_addr = admin_kp.address(&env);
217
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
218
+
219
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
220
+ let sig = mk_sig(&setup, &admin_kp, &payload);
221
+
222
+ let oapp = Address::generate(&setup.env);
223
+ let bad_fn: Vec<Context> =
224
+ vec![&setup.env, contract_ctx(&setup.env, oapp, "not_allowed", vec![&setup.env, 0i128.into_val(&setup.env)])];
225
+ assert_eq!(check_auth(&setup, &payload, sig, &bad_fn), Err(Ok(ExecutorError::UnauthorizedContext)));
226
+ }
227
+
228
+ #[test]
229
+ fn test_check_auth_rejects_invalid_alert_contexts() {
230
+ let env = Env::default();
231
+ let admin_kp = Ed25519KeyPair::generate();
232
+ let admin_addr = admin_kp.address(&env);
233
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
234
+
235
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
236
+ let sig = mk_sig(&setup, &admin_kp, &payload);
237
+
238
+ let oapp = Address::generate(&setup.env);
239
+
240
+ // Alert fn must target endpoint and must be the only context
241
+ let bad_alert_contract: Vec<Context> =
242
+ vec![&setup.env, contract_ctx(&setup.env, oapp.clone(), "lz_receive_alert", Vec::new(&setup.env))];
243
+ assert_eq!(
244
+ check_auth(&setup, &payload, sig.clone(), &bad_alert_contract),
245
+ Err(Ok(ExecutorError::UnauthorizedContext))
246
+ );
247
+
248
+ let bad_alert_extra_ctx: Vec<Context> = vec![
249
+ &setup.env,
250
+ contract_ctx(&setup.env, setup.endpoint.clone(), "lz_receive_alert", Vec::new(&setup.env)),
251
+ contract_ctx(&setup.env, oapp, "lz_receive", vec![&setup.env, 0i128.into_val(&setup.env)]),
252
+ ];
253
+ assert_eq!(check_auth(&setup, &payload, sig, &bad_alert_extra_ctx), Err(Ok(ExecutorError::UnauthorizedContext)));
254
+ }
255
+
256
+ #[test]
257
+ fn test_check_auth_rejects_execute_missing_or_wrong_value_type() {
258
+ let env = Env::default();
259
+ let admin_kp = Ed25519KeyPair::generate();
260
+ let admin_addr = admin_kp.address(&env);
261
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
262
+
263
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
264
+ let sig = mk_sig(&setup, &admin_kp, &payload);
265
+
266
+ let oapp = Address::generate(&setup.env);
267
+
268
+ // Execute path requires last arg to be i128 value
269
+ let missing_value: Vec<Context> =
270
+ vec![&setup.env, contract_ctx(&setup.env, oapp.clone(), "lz_receive", Vec::new(&setup.env))];
271
+ assert_eq!(check_auth(&setup, &payload, sig.clone(), &missing_value), Err(Ok(ExecutorError::UnauthorizedContext)));
272
+
273
+ let wrong_value_type: Vec<Context> = vec![
274
+ &setup.env,
275
+ contract_ctx(
276
+ &setup.env,
277
+ oapp,
278
+ "lz_receive",
279
+ vec![&setup.env, Symbol::new(&setup.env, "not_i128").into_val(&setup.env)],
280
+ ),
281
+ ];
282
+ assert_eq!(check_auth(&setup, &payload, sig, &wrong_value_type), Err(Ok(ExecutorError::UnauthorizedContext)));
283
+ }
284
+
285
+ #[test]
286
+ fn test_check_auth_rejects_value_zero_with_extra_context() {
287
+ let env = Env::default();
288
+ let admin_kp = Ed25519KeyPair::generate();
289
+ let admin_addr = admin_kp.address(&env);
290
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
291
+
292
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
293
+ let sig = mk_sig(&setup, &admin_kp, &payload);
294
+
295
+ let oapp = Address::generate(&setup.env);
296
+ let value_zero_with_transfer: Vec<Context> = vec![
297
+ &setup.env,
298
+ contract_ctx(&setup.env, oapp, "lz_receive", vec![&setup.env, 0i128.into_val(&setup.env)]),
299
+ contract_ctx(
300
+ &setup.env,
301
+ setup.native_token.clone(),
302
+ "transfer",
303
+ vec![
304
+ &setup.env,
305
+ Address::generate(&setup.env).into_val(&setup.env),
306
+ Address::generate(&setup.env).into_val(&setup.env),
307
+ 1i128.into_val(&setup.env),
308
+ ],
309
+ ),
310
+ ];
311
+ assert_eq!(
312
+ check_auth(&setup, &payload, sig, &value_zero_with_transfer),
313
+ Err(Ok(ExecutorError::UnauthorizedContext))
314
+ );
315
+ }
316
+
317
+ #[test]
318
+ fn test_check_auth_rejects_value_nonzero_missing_transfer_context() {
319
+ let env = Env::default();
320
+ let admin_kp = Ed25519KeyPair::generate();
321
+ let admin_addr = admin_kp.address(&env);
322
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
323
+
324
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
325
+ let sig = mk_sig(&setup, &admin_kp, &payload);
326
+
327
+ let oapp = Address::generate(&setup.env);
328
+ let value_nonzero_missing_transfer: Vec<Context> =
329
+ vec![&setup.env, contract_ctx(&setup.env, oapp, "lz_receive", vec![&setup.env, 1i128.into_val(&setup.env)])];
330
+ assert_eq!(
331
+ check_auth(&setup, &payload, sig, &value_nonzero_missing_transfer),
332
+ Err(Ok(ExecutorError::UnauthorizedContext))
333
+ );
334
+ }
335
+
336
+ #[test]
337
+ fn test_check_auth_rejects_invalid_transfer_context() {
338
+ let env = Env::default();
339
+ let admin_kp = Ed25519KeyPair::generate();
340
+ let admin_addr = admin_kp.address(&env);
341
+ let setup = TestSetup::new_with_env_and_admin(env, &admin_addr);
342
+
343
+ let payload = BytesN::from_array(&setup.env, &[1u8; 32]);
344
+ let sig = mk_sig(&setup, &admin_kp, &payload);
345
+
346
+ let oapp = Address::generate(&setup.env);
347
+ let base_exec: Context = contract_ctx(&setup.env, oapp, "lz_receive", vec![&setup.env, 5i128.into_val(&setup.env)]);
348
+ let transfer_args: Vec<Val> = vec![
349
+ &setup.env,
350
+ Address::generate(&setup.env).into_val(&setup.env),
351
+ Address::generate(&setup.env).into_val(&setup.env),
352
+ 5i128.into_val(&setup.env),
353
+ ];
354
+
355
+ // Wrong transfer fn name
356
+ let wrong_transfer_fn: Vec<Context> = vec![
357
+ &setup.env,
358
+ base_exec.clone(),
359
+ contract_ctx(&setup.env, setup.native_token.clone(), "not_transfer", transfer_args.clone()),
360
+ ];
361
+ assert_eq!(
362
+ check_auth(&setup, &payload, sig.clone(), &wrong_transfer_fn),
363
+ Err(Ok(ExecutorError::UnauthorizedContext))
364
+ );
365
+
366
+ // Wrong transfer contract
367
+ let wrong_transfer_contract: Vec<Context> = vec![
368
+ &setup.env,
369
+ base_exec.clone(),
370
+ contract_ctx(&setup.env, Address::generate(&setup.env), "transfer", transfer_args.clone()),
371
+ ];
372
+ assert_eq!(
373
+ check_auth(&setup, &payload, sig.clone(), &wrong_transfer_contract),
374
+ Err(Ok(ExecutorError::UnauthorizedContext))
375
+ );
376
+
377
+ // Wrong transfer amount (must match value)
378
+ let wrong_transfer_amount: Vec<Context> = vec![
379
+ &setup.env,
380
+ base_exec,
381
+ contract_ctx(
382
+ &setup.env,
383
+ setup.native_token.clone(),
384
+ "transfer",
385
+ vec![
386
+ &setup.env,
387
+ Address::generate(&setup.env).into_val(&setup.env),
388
+ Address::generate(&setup.env).into_val(&setup.env),
389
+ 6i128.into_val(&setup.env),
390
+ ],
391
+ ),
392
+ ];
393
+ assert_eq!(check_auth(&setup, &payload, sig, &wrong_transfer_amount), Err(Ok(ExecutorError::UnauthorizedContext)));
394
+ }