@layerzerolabs/protocol-stellar-v2 0.2.19 → 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 (249) hide show
  1. package/.turbo/turbo-build.log +795 -791
  2. package/.turbo/turbo-lint.log +325 -155
  3. package/.turbo/turbo-test.log +1398 -1277
  4. package/Cargo.lock +122 -111
  5. package/Cargo.toml +32 -16
  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 +18 -7
  9. package/contracts/common-macros/src/lib.rs +31 -14
  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/contract_ttl.rs +1 -1
  13. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +6 -12
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +12 -17
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
  16. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +2 -7
  17. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +20 -14
  18. package/contracts/common-macros/src/tests/upgradeable.rs +26 -4
  19. package/contracts/common-macros/src/ttl_configurable.rs +2 -10
  20. package/contracts/common-macros/src/ttl_extendable.rs +2 -10
  21. package/contracts/common-macros/src/upgradeable.rs +61 -26
  22. package/contracts/common-macros/src/utils.rs +0 -9
  23. package/contracts/endpoint-v2/src/lib.rs +3 -2
  24. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +2 -2
  25. package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +3 -3
  26. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +4 -4
  27. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +17 -5
  28. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
  29. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +2 -2
  30. package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +2 -2
  31. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +6 -6
  32. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +67 -37
  33. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +5 -5
  34. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +44 -54
  35. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +7 -7
  36. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +8 -8
  37. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +3 -3
  38. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +4 -4
  39. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +3 -3
  40. package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +2 -2
  41. package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +3 -3
  42. package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +2 -2
  43. package/contracts/layerzero-views/Cargo.toml +0 -1
  44. package/contracts/layerzero-views/src/layerzero_view.rs +1 -13
  45. package/contracts/macro-integration-tests/Cargo.toml +5 -15
  46. package/contracts/macro-integration-tests/tests/runtime/oapp/mod.rs +48 -0
  47. package/contracts/macro-integration-tests/tests/runtime/oapp/oapp_core.rs +170 -0
  48. package/contracts/macro-integration-tests/tests/runtime/oapp/options_type3.rs +154 -0
  49. package/contracts/macro-integration-tests/tests/runtime/oapp/receiver.rs +338 -0
  50. package/contracts/macro-integration-tests/tests/runtime/oapp/sender.rs +435 -0
  51. package/contracts/macro-integration-tests/tests/runtime.rs +1 -0
  52. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.rs +8 -0
  53. package/contracts/macro-integration-tests/tests/ui/oapp/fail/custom_wrong_value.stderr +5 -0
  54. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.rs +8 -0
  55. package/contracts/macro-integration-tests/tests/ui/oapp/fail/missing_lz_receive_internal.stderr +71 -0
  56. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.rs +10 -0
  57. package/contracts/macro-integration-tests/tests/ui/oapp/fail/non_struct_input.stderr +5 -0
  58. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.rs +8 -0
  59. package/contracts/macro-integration-tests/tests/ui/oapp/fail/unknown_custom_option.stderr +5 -0
  60. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.rs +8 -0
  61. package/contracts/macro-integration-tests/tests/ui/oapp/fail/wrong_key.stderr +5 -0
  62. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_all.rs +38 -0
  63. package/contracts/macro-integration-tests/tests/ui/oapp/pass/custom_single_trait.rs +96 -0
  64. package/contracts/macro-integration-tests/tests/ui/oapp/pass/minimal_contract.rs +64 -0
  65. package/contracts/macro-integration-tests/tests/ui/oapp/pass/struct_with_fields.rs +46 -0
  66. package/contracts/macro-integration-tests/tests/ui/ownable/fail/only_auth_missing_env.stderr +8 -0
  67. package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +1 -1
  68. package/contracts/macro-integration-tests/tests/ui/ownable/pass/only_auth_env_param_variants.rs +1 -1
  69. package/contracts/macro-integration-tests/tests/ui_oapp.rs +11 -0
  70. package/contracts/message-libs/message-lib-common/Cargo.toml +0 -1
  71. package/contracts/message-libs/message-lib-common/src/errors.rs +1 -1
  72. package/contracts/message-libs/treasury/Cargo.toml +0 -2
  73. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +2 -2
  74. package/contracts/message-libs/uln-302/src/events.rs +4 -0
  75. package/contracts/message-libs/uln-302/src/send_uln.rs +22 -6
  76. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +2 -2
  77. package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +2 -2
  78. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +2 -2
  79. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +2 -2
  80. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +2 -2
  81. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +21 -67
  82. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +2 -2
  83. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +2 -2
  84. package/contracts/oapps/counter/Cargo.toml +5 -6
  85. package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
  86. package/contracts/oapps/counter/integration_tests/utils.rs +19 -12
  87. package/contracts/oapps/oapp/src/errors.rs +1 -1
  88. package/contracts/oapps/oapp/src/interfaces/mod.rs +3 -0
  89. package/contracts/oapps/oapp/src/interfaces/oapp_msg_inspector.rs +47 -0
  90. package/contracts/oapps/oapp/src/lib.rs +1 -0
  91. package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +4 -4
  92. package/contracts/oapps/oapp/src/oapp_core.rs +5 -5
  93. package/contracts/oapps/oapp/src/oapp_options_type3.rs +12 -4
  94. package/contracts/oapps/oapp/src/oapp_receiver.rs +14 -9
  95. package/contracts/oapps/oapp/src/tests/mod.rs +4 -4
  96. package/contracts/oapps/oapp/src/tests/oapp_core.rs +223 -0
  97. package/contracts/oapps/oapp/src/tests/oapp_options_type3.rs +240 -0
  98. package/contracts/oapps/oapp/src/tests/oapp_receiver.rs +381 -0
  99. package/contracts/oapps/oapp/src/tests/oapp_sender.rs +569 -0
  100. package/contracts/oapps/oapp-macros/Cargo.toml +8 -4
  101. package/contracts/oapps/oapp-macros/src/generators.rs +9 -34
  102. package/contracts/oapps/oapp-macros/src/lib.rs +3 -0
  103. package/contracts/oapps/oapp-macros/src/tests/mod.rs +2 -0
  104. package/contracts/oapps/oapp-macros/src/tests/oapp.rs +88 -0
  105. package/contracts/oapps/oapp-macros/src/tests/parse_custom_impls.rs +86 -0
  106. package/contracts/oapps/oapp-macros/src/tests/snapshots/oapp_macros__tests__oapp__snapshot_generate_oapp.snap +103 -0
  107. package/contracts/oapps/oft/integration-tests/utils.rs +28 -8
  108. package/contracts/oapps/oft/src/extensions/oft_fee.rs +153 -75
  109. package/contracts/oapps/oft/src/extensions/pausable.rs +61 -12
  110. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +198 -134
  111. package/contracts/oapps/oft/src/oft.rs +45 -50
  112. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +1 -1
  113. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +4 -26
  114. package/contracts/oapps/oft-core/Cargo.toml +1 -4
  115. package/contracts/oapps/oft-core/integration-tests/setup.rs +3 -3
  116. package/contracts/oapps/oft-core/integration-tests/utils.rs +21 -3
  117. package/contracts/oapps/oft-core/src/errors.rs +3 -2
  118. package/contracts/oapps/oft-core/src/events.rs +6 -0
  119. package/contracts/oapps/oft-core/src/lib.rs +1 -1
  120. package/contracts/oapps/oft-core/src/oft_core.rs +341 -246
  121. package/contracts/oapps/oft-core/src/storage.rs +7 -3
  122. package/contracts/oapps/oft-core/src/tests/mod.rs +1 -0
  123. package/contracts/oapps/oft-core/src/tests/test_decimals.rs +37 -2
  124. package/contracts/oapps/oft-core/src/tests/test_lz_receive.rs +2 -2
  125. package/contracts/oapps/oft-core/src/tests/test_msg_inspector.rs +323 -0
  126. package/contracts/oapps/oft-core/src/tests/test_send.rs +2 -2
  127. package/contracts/oapps/oft-core/src/tests/test_utils.rs +61 -16
  128. package/contracts/upgrader/src/lib.rs +30 -57
  129. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
  130. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
  131. package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
  132. package/contracts/utils/Cargo.toml +0 -1
  133. package/contracts/utils/src/buffer_reader.rs +1 -0
  134. package/contracts/utils/src/errors.rs +4 -2
  135. package/contracts/utils/src/multisig.rs +17 -8
  136. package/contracts/utils/src/ownable.rs +6 -6
  137. package/contracts/utils/src/testing_utils.rs +124 -54
  138. package/contracts/utils/src/tests/multisig.rs +12 -12
  139. package/contracts/utils/src/tests/ownable.rs +6 -6
  140. package/contracts/utils/src/tests/testing_utils.rs +50 -167
  141. package/contracts/utils/src/tests/ttl_configurable.rs +5 -5
  142. package/contracts/utils/src/tests/upgradeable.rs +372 -175
  143. package/contracts/utils/src/ttl_configurable.rs +13 -7
  144. package/contracts/utils/src/upgradeable.rs +48 -23
  145. package/contracts/workers/dvn/Cargo.toml +6 -6
  146. package/contracts/workers/dvn/src/auth.rs +12 -42
  147. package/contracts/workers/dvn/src/dvn.rs +15 -40
  148. package/contracts/workers/dvn/src/errors.rs +0 -1
  149. package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
  150. package/contracts/workers/dvn/src/lib.rs +4 -3
  151. package/contracts/workers/dvn/src/tests/auth.rs +1 -1
  152. package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
  153. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
  154. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
  155. package/contracts/workers/dvn/src/tests/setup.rs +5 -9
  156. package/contracts/workers/dvn-fee-lib/Cargo.toml +2 -2
  157. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +38 -22
  158. package/contracts/workers/dvn-fee-lib/src/lib.rs +12 -2
  159. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +17 -16
  160. package/contracts/workers/executor/Cargo.toml +4 -0
  161. package/contracts/workers/executor/src/executor.rs +15 -36
  162. package/contracts/workers/executor/src/lib.rs +2 -2
  163. package/contracts/workers/executor/src/tests/auth.rs +394 -0
  164. package/contracts/workers/executor/src/tests/executor.rs +410 -0
  165. package/contracts/workers/executor/src/tests/mod.rs +3 -0
  166. package/contracts/workers/executor/src/tests/setup.rs +250 -0
  167. package/contracts/workers/executor-fee-lib/Cargo.toml +7 -1
  168. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +62 -15
  169. package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
  170. package/contracts/workers/executor-fee-lib/src/lib.rs +11 -2
  171. package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
  172. package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
  173. package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
  174. package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
  175. package/contracts/workers/executor-helper/Cargo.toml +0 -1
  176. package/contracts/workers/executor-helper/src/lib.rs +3 -0
  177. package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
  178. package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
  179. package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
  180. package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
  181. package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
  182. package/contracts/workers/price-feed/Cargo.toml +7 -1
  183. package/contracts/workers/price-feed/src/events.rs +1 -1
  184. package/contracts/workers/price-feed/src/lib.rs +12 -4
  185. package/contracts/workers/price-feed/src/price_feed.rs +5 -21
  186. package/contracts/workers/price-feed/src/storage.rs +1 -1
  187. package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
  188. package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
  189. package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
  190. package/contracts/workers/price-feed/src/types.rs +1 -1
  191. package/contracts/workers/worker/src/errors.rs +1 -4
  192. package/contracts/workers/worker/src/lib.rs +0 -2
  193. package/contracts/workers/worker/src/storage.rs +32 -29
  194. package/contracts/workers/worker/src/tests/setup.rs +2 -8
  195. package/contracts/workers/worker/src/tests/worker.rs +96 -74
  196. package/contracts/workers/worker/src/worker.rs +75 -75
  197. package/docs/error-spec.md +55 -0
  198. package/docs/layerzero-v2-on-stellar.md +447 -0
  199. package/docs/oapp-guide.md +212 -0
  200. package/docs/oft-guide.md +314 -0
  201. package/package.json +3 -3
  202. package/sdk/.turbo/turbo-test.log +268 -263
  203. package/sdk/dist/generated/bml.d.ts +12 -4
  204. package/sdk/dist/generated/bml.js +9 -7
  205. package/sdk/dist/generated/counter.d.ts +306 -298
  206. package/sdk/dist/generated/counter.js +48 -46
  207. package/sdk/dist/generated/dvn.d.ts +450 -411
  208. package/sdk/dist/generated/dvn.js +66 -64
  209. package/sdk/dist/generated/dvn_fee_lib.d.ts +294 -338
  210. package/sdk/dist/generated/dvn_fee_lib.js +33 -64
  211. package/sdk/dist/generated/endpoint.d.ts +108 -100
  212. package/sdk/dist/generated/endpoint.js +21 -19
  213. package/sdk/dist/generated/executor.d.ts +414 -370
  214. package/sdk/dist/generated/executor.js +58 -55
  215. package/sdk/dist/generated/executor_fee_lib.d.ts +333 -377
  216. package/sdk/dist/generated/executor_fee_lib.js +34 -65
  217. package/sdk/dist/generated/executor_helper.d.ts +26 -190
  218. package/sdk/dist/generated/executor_helper.js +23 -28
  219. package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
  220. package/sdk/dist/generated/layerzero_view.js +294 -0
  221. package/sdk/dist/generated/oft.d.ts +408 -385
  222. package/sdk/dist/generated/oft.js +89 -92
  223. package/sdk/dist/generated/price_feed.d.ts +385 -429
  224. package/sdk/dist/generated/price_feed.js +50 -81
  225. package/sdk/dist/generated/sml.d.ts +108 -100
  226. package/sdk/dist/generated/sml.js +21 -19
  227. package/sdk/dist/generated/treasury.d.ts +108 -100
  228. package/sdk/dist/generated/treasury.js +21 -19
  229. package/sdk/dist/generated/uln302.d.ts +108 -100
  230. package/sdk/dist/generated/uln302.js +23 -21
  231. package/sdk/dist/generated/upgrader.d.ts +189 -18
  232. package/sdk/dist/generated/upgrader.js +84 -4
  233. package/sdk/dist/index.d.ts +1 -0
  234. package/sdk/dist/index.js +2 -0
  235. package/sdk/package.json +1 -1
  236. package/sdk/src/index.ts +3 -0
  237. package/sdk/test/oft-sml.test.ts +4 -4
  238. package/sdk/test/suites/localnet.ts +84 -20
  239. package/sdk/test/upgrader.test.ts +2 -3
  240. package/tools/ts-bindings-gen/src/main.rs +2 -1
  241. package/contracts/ERROR_SPEC.md +0 -44
  242. package/contracts/endpoint-v2/ARCHITECTURE.md +0 -233
  243. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +0 -175
  244. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +0 -212
  245. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +0 -153
  246. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +0 -294
  247. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
  248. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
  249. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
@@ -0,0 +1,701 @@
1
+ use fee_lib_interfaces::{FeeEstimate, FeeParams};
2
+ use soroban_sdk::{contract, contractimpl, testutils::Address as _, Address, Bytes, Env};
3
+
4
+ use crate::errors::ExecutorFeeLibError;
5
+ use crate::ExecutorFeeLib;
6
+
7
+ use super::setup::{
8
+ bytes32, option_lz_compose, option_lz_receive, option_native_drop, option_ordered_execution, TestSetup,
9
+ };
10
+
11
+ // Mock contracts
12
+
13
+ #[contract]
14
+ struct MockPriceFeedEchoGas;
15
+
16
+ #[contractimpl]
17
+ impl MockPriceFeedEchoGas {
18
+ // Returns total_gas_fee = gas, ratio=1, denom=1, native_price_usd=0
19
+ pub fn estimate_fee_by_eid(
20
+ _env: &Env,
21
+ _fee_lib: &Address,
22
+ _dst_eid: u32,
23
+ _calldata_size: u32,
24
+ gas: u128,
25
+ ) -> FeeEstimate {
26
+ FeeEstimate { total_gas_fee: gas as i128, price_ratio: 1, price_ratio_denominator: 1, native_price_usd: 0 }
27
+ }
28
+ }
29
+
30
+ #[contract]
31
+ struct MockPriceFeedNegativeFee;
32
+
33
+ #[contractimpl]
34
+ impl MockPriceFeedNegativeFee {
35
+ // Returns negative total_gas_fee to trigger InvalidFee error
36
+ pub fn estimate_fee_by_eid(
37
+ _env: &Env,
38
+ _fee_lib: &Address,
39
+ _dst_eid: u32,
40
+ _calldata_size: u32,
41
+ _gas: u128,
42
+ ) -> FeeEstimate {
43
+ FeeEstimate { total_gas_fee: -1, price_ratio: 1, price_ratio_denominator: 1, native_price_usd: 0 }
44
+ }
45
+ }
46
+
47
+ #[contract]
48
+ struct MockPriceFeedWithRatio;
49
+
50
+ #[contractimpl]
51
+ impl MockPriceFeedWithRatio {
52
+ // Returns configurable values for testing value conversion and margin
53
+ pub fn estimate_fee_by_eid(
54
+ _env: &Env,
55
+ _fee_lib: &Address,
56
+ _dst_eid: u32,
57
+ _calldata_size: u32,
58
+ gas: u128,
59
+ ) -> FeeEstimate {
60
+ FeeEstimate {
61
+ total_gas_fee: gas as i128,
62
+ price_ratio: 20_000_000_000, // 2e10 (2:1 ratio)
63
+ price_ratio_denominator: 10_000_000_000, // 1e10
64
+ native_price_usd: 20_000_000_000_000, // 2000e10
65
+ }
66
+ }
67
+ }
68
+
69
+ // version
70
+
71
+ #[test]
72
+ fn test_version() {
73
+ let setup = TestSetup::new();
74
+ assert_eq!(setup.client.version(), (1, 1));
75
+ }
76
+
77
+ // get_fee
78
+
79
+ #[test]
80
+ fn test_get_fee_basic_lz_receive_only() {
81
+ let setup = TestSetup::new();
82
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
83
+
84
+ // Simple case: only lzReceive gas
85
+ let mut options = Bytes::new(&setup.env);
86
+ options.append(&option_lz_receive(&setup.env, 200_000, None));
87
+
88
+ let params = FeeParams {
89
+ sender: Address::generate(&setup.env),
90
+ dst_eid: 30_000,
91
+ calldata_size: 0,
92
+ options,
93
+ price_feed,
94
+ default_multiplier_bps: 12_000,
95
+ lz_receive_base_gas: 1,
96
+ lz_compose_base_gas: 0,
97
+ floor_margin_usd: 0,
98
+ native_cap: 222_000,
99
+ multiplier_bps: 10_000,
100
+ };
101
+
102
+ // total_gas = base(1) + lzReceive(200,000) = 200,001
103
+ // no value, multiplier=1.0x => fee = 200,001
104
+ let executor = Address::generate(&setup.env);
105
+ let fee = setup.client.get_fee(&executor, &params);
106
+ assert_eq!(fee, 200_001);
107
+ }
108
+
109
+ #[test]
110
+ fn test_get_fee_lz_receive_with_value_on_v2() {
111
+ let setup = TestSetup::new();
112
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
113
+
114
+ // lzReceive with value (32 bytes format) - allowed on V2
115
+ let mut options = Bytes::new(&setup.env);
116
+ options.append(&option_lz_receive(&setup.env, 200_000, Some(5)));
117
+
118
+ let params = FeeParams {
119
+ sender: Address::generate(&setup.env),
120
+ dst_eid: 30_000, // V2
121
+ calldata_size: 0,
122
+ options,
123
+ price_feed,
124
+ default_multiplier_bps: 12_000,
125
+ lz_receive_base_gas: 1,
126
+ lz_compose_base_gas: 0,
127
+ floor_margin_usd: 0,
128
+ native_cap: 222_000,
129
+ multiplier_bps: 10_000,
130
+ };
131
+
132
+ // total_gas = 1 + 200,000 = 200,001
133
+ // total_value = 5, ratio=1, denom=1 => value_fee = 5
134
+ // total = 200,006
135
+ let executor = Address::generate(&setup.env);
136
+ let fee = setup.client.get_fee(&executor, &params);
137
+ assert_eq!(fee, 200_006);
138
+ }
139
+
140
+ #[test]
141
+ fn test_get_fee_multiple_lz_receive_accumulates_gas() {
142
+ let setup = TestSetup::new();
143
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
144
+
145
+ // Multiple lzReceive options should accumulate gas
146
+ let mut options = Bytes::new(&setup.env);
147
+ options.append(&option_lz_receive(&setup.env, 20, None));
148
+ options.append(&option_lz_receive(&setup.env, 30, None));
149
+
150
+ let params = FeeParams {
151
+ sender: Address::generate(&setup.env),
152
+ dst_eid: 30_000,
153
+ calldata_size: 0,
154
+ options,
155
+ price_feed,
156
+ default_multiplier_bps: 12_000,
157
+ lz_receive_base_gas: 1,
158
+ lz_compose_base_gas: 0,
159
+ floor_margin_usd: 0,
160
+ native_cap: 222_000,
161
+ multiplier_bps: 10_000,
162
+ };
163
+
164
+ // total_gas = base(1) + lzReceive(20 + 30) = 51
165
+ let executor = Address::generate(&setup.env);
166
+ let fee = setup.client.get_fee(&executor, &params);
167
+ assert_eq!(fee, 51);
168
+ }
169
+
170
+ #[test]
171
+ fn test_get_fee_multiple_native_drop_accumulates_value() {
172
+ let setup = TestSetup::new();
173
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
174
+
175
+ let receiver1 = bytes32(&setup.env, 0xAA);
176
+ let receiver2 = bytes32(&setup.env, 0xBB);
177
+ let mut options = Bytes::new(&setup.env);
178
+ options.append(&option_lz_receive(&setup.env, 10, None));
179
+ options.append(&option_native_drop(&setup.env, 5, &receiver1));
180
+ options.append(&option_native_drop(&setup.env, 7, &receiver2));
181
+
182
+ let params = FeeParams {
183
+ sender: Address::generate(&setup.env),
184
+ dst_eid: 30_000,
185
+ calldata_size: 0,
186
+ options,
187
+ price_feed,
188
+ default_multiplier_bps: 12_000,
189
+ lz_receive_base_gas: 1,
190
+ lz_compose_base_gas: 0,
191
+ floor_margin_usd: 0,
192
+ native_cap: 222_000,
193
+ multiplier_bps: 10_000,
194
+ };
195
+
196
+ // total_gas = 1 + 10 = 11
197
+ // total_value = 5 + 7 = 12
198
+ // fee = 11 + 12 = 23
199
+ let executor = Address::generate(&setup.env);
200
+ let fee = setup.client.get_fee(&executor, &params);
201
+ assert_eq!(fee, 23);
202
+ }
203
+
204
+ #[test]
205
+ fn test_get_fee_multiple_lz_compose_accumulates_gas_and_value() {
206
+ let setup = TestSetup::new();
207
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
208
+
209
+ let mut options = Bytes::new(&setup.env);
210
+ options.append(&option_lz_receive(&setup.env, 10, None));
211
+ options.append(&option_lz_compose(&setup.env, 0, 20, Some(3)));
212
+ options.append(&option_lz_compose(&setup.env, 1, 30, None));
213
+
214
+ let params = FeeParams {
215
+ sender: Address::generate(&setup.env),
216
+ dst_eid: 30_000,
217
+ calldata_size: 0,
218
+ options,
219
+ price_feed,
220
+ default_multiplier_bps: 12_000,
221
+ lz_receive_base_gas: 1,
222
+ lz_compose_base_gas: 15,
223
+ floor_margin_usd: 0,
224
+ native_cap: 222_000,
225
+ multiplier_bps: 10_000,
226
+ };
227
+
228
+ // total_gas = base(1) + lzReceive(10) + lzCompose(20+30) + compose_base(15*2) = 91
229
+ // total_value = 3
230
+ // fee = 91 + 3 = 94
231
+ let executor = Address::generate(&setup.env);
232
+ let fee = setup.client.get_fee(&executor, &params);
233
+ assert_eq!(fee, 94);
234
+ }
235
+
236
+ #[test]
237
+ fn test_get_fee_ordered_execution_adds_overhead() {
238
+ let setup = TestSetup::new();
239
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
240
+
241
+ let mut options = Bytes::new(&setup.env);
242
+ // lz_receive_gas must be non-zero (use larger gas to show ordered overhead)
243
+ options.append(&option_lz_receive(&setup.env, 9_000, None));
244
+ options.append(&option_ordered_execution(&setup.env));
245
+
246
+ let params = FeeParams {
247
+ sender: Address::generate(&setup.env),
248
+ dst_eid: 30_000,
249
+ calldata_size: 0,
250
+ options,
251
+ price_feed,
252
+ default_multiplier_bps: 12_000,
253
+ lz_receive_base_gas: 1_000,
254
+ lz_compose_base_gas: 0,
255
+ floor_margin_usd: 0,
256
+ native_cap: 222_000,
257
+ multiplier_bps: 10_000,
258
+ };
259
+
260
+ // total_gas = base(1_000) + lzReceive(9_000) = 10_000, with ordered: (10_000 * 102) / 100 = 10_200
261
+ let executor = Address::generate(&setup.env);
262
+ let fee = setup.client.get_fee(&executor, &params);
263
+ assert_eq!(fee, 10_200);
264
+ }
265
+
266
+ #[test]
267
+ fn test_get_fee_computes_gas_and_value_components() {
268
+ let setup = TestSetup::new();
269
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
270
+
271
+ // Build options:
272
+ // - lzReceive gas=9_000, value=0
273
+ // - nativeDrop amount=700
274
+ // - lzCompose index=0 gas=3_000 value=500
275
+ // - ordered execution enabled
276
+ let receiver = bytes32(&setup.env, 0xAB);
277
+ let mut options = Bytes::new(&setup.env);
278
+ options.append(&option_lz_receive(&setup.env, 9_000, None));
279
+ options.append(&option_native_drop(&setup.env, 700, &receiver));
280
+ options.append(&option_lz_compose(&setup.env, 0, 3_000, Some(500)));
281
+ options.append(&option_ordered_execution(&setup.env));
282
+
283
+ let params = FeeParams {
284
+ sender: Address::generate(&setup.env),
285
+ dst_eid: 30_000, // v2
286
+ calldata_size: 0,
287
+ options,
288
+ price_feed,
289
+ default_multiplier_bps: 12_000,
290
+ lz_receive_base_gas: 1_000,
291
+ lz_compose_base_gas: 2_000,
292
+ floor_margin_usd: 0,
293
+ native_cap: 222_000,
294
+ multiplier_bps: 10_000,
295
+ };
296
+
297
+ // total_value = nativeDrop(700) + lzCompose.value(500) = 1_200
298
+ // total_gas before ordered = base_receive(1_000) + lzReceive(9_000) + lzCompose(3_000) + compose_base(2_000*1) = 15_000
299
+ // ordered overhead: (15_000 * 102) / 100 = 15_300
300
+ // MockPriceFeedEchoGas returns total_gas_fee = gas (15_300), ratio=1, denom=1
301
+ // multiplier=1.0x, so gas fee stays 15_300; value fee = 1_200
302
+ // total = 16_500
303
+ let executor = Address::generate(&setup.env);
304
+ let fee = setup.client.get_fee(&executor, &params);
305
+ assert_eq!(fee, 16_500);
306
+ }
307
+
308
+ #[test]
309
+ fn test_get_fee_uses_dst_multiplier_when_nonzero() {
310
+ let setup = TestSetup::new();
311
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
312
+
313
+ let mut options = Bytes::new(&setup.env);
314
+ // lz_receive_gas must be non-zero (use larger gas to show multiplier effect)
315
+ options.append(&option_lz_receive(&setup.env, 9_000, None));
316
+
317
+ let params = FeeParams {
318
+ sender: Address::generate(&setup.env),
319
+ dst_eid: 30_000,
320
+ calldata_size: 0,
321
+ options,
322
+ price_feed,
323
+ default_multiplier_bps: 12_000,
324
+ lz_receive_base_gas: 1_000,
325
+ lz_compose_base_gas: 0,
326
+ floor_margin_usd: 0,
327
+ native_cap: 222_000,
328
+ multiplier_bps: 15_000, // 1.5x
329
+ };
330
+
331
+ // total_gas = base(1_000) + lzReceive(9_000) = 10_000, multiplier = 1.5x => (10_000 * 15000) / 10000 = 15_000
332
+ let executor = Address::generate(&setup.env);
333
+ let fee = setup.client.get_fee(&executor, &params);
334
+ assert_eq!(fee, 15_000);
335
+ }
336
+
337
+ #[test]
338
+ fn test_get_fee_uses_default_multiplier_when_multiplier_bps_is_zero() {
339
+ let setup = TestSetup::new();
340
+ let price_feed = setup.env.register(MockPriceFeedEchoGas, ());
341
+
342
+ let mut options = Bytes::new(&setup.env);
343
+ // lz_receive_gas must be non-zero (use larger gas to show multiplier effect)
344
+ options.append(&option_lz_receive(&setup.env, 9_000, None));
345
+
346
+ let params = FeeParams {
347
+ sender: Address::generate(&setup.env),
348
+ dst_eid: 30_000,
349
+ calldata_size: 0,
350
+ options,
351
+ price_feed,
352
+ default_multiplier_bps: 12_000, // 1.2x
353
+ lz_receive_base_gas: 1_000,
354
+ lz_compose_base_gas: 0,
355
+ floor_margin_usd: 0,
356
+ native_cap: 222_000,
357
+ multiplier_bps: 0, // Use default
358
+ };
359
+
360
+ // total_gas = base(1_000) + lzReceive(9_000) = 10_000, multiplier = 1.2x => (10_000 * 12000) / 10000 = 12_000
361
+ let executor = Address::generate(&setup.env);
362
+ let fee = setup.client.get_fee(&executor, &params);
363
+ assert_eq!(fee, 12_000);
364
+ }
365
+
366
+ #[test]
367
+ fn test_get_fee_converts_and_multiplies_native_value() {
368
+ let setup = TestSetup::new();
369
+ let price_feed = setup.env.register(MockPriceFeedWithRatio, ());
370
+
371
+ let receiver = bytes32(&setup.env, 0xAB);
372
+ let mut options = Bytes::new(&setup.env);
373
+ // lz_receive_gas must be non-zero
374
+ options.append(&option_lz_receive(&setup.env, 1, None));
375
+ options.append(&option_native_drop(&setup.env, 10, &receiver));
376
+
377
+ let params = FeeParams {
378
+ sender: Address::generate(&setup.env),
379
+ dst_eid: 30_000,
380
+ calldata_size: 0,
381
+ options,
382
+ price_feed,
383
+ default_multiplier_bps: 12_000,
384
+ lz_receive_base_gas: 1,
385
+ lz_compose_base_gas: 0,
386
+ floor_margin_usd: 0,
387
+ native_cap: 222_000,
388
+ multiplier_bps: 10_000, // 1.0x
389
+ };
390
+
391
+ // total_gas = base(1) + lzReceive(1) = 2, gas_fee = 2
392
+ // total_value = 10, ratio=2e10, denom=1e10 => converted = (10 * 2e10) / 1e10 = 20
393
+ // value_fee = (20 * 10000) / 10000 = 20
394
+ // total = 2 (gas) + 20 (value) = 22
395
+ let executor = Address::generate(&setup.env);
396
+ let fee = setup.client.get_fee(&executor, &params);
397
+ assert_eq!(fee, 22);
398
+ }
399
+
400
+ #[test]
401
+ fn test_get_fee_applies_floor_margin_when_gas_fee_is_low() {
402
+ let setup = TestSetup::new();
403
+ let price_feed = setup.env.register(MockPriceFeedWithRatio, ());
404
+
405
+ let mut options = Bytes::new(&setup.env);
406
+ // lz_receive_gas must be non-zero
407
+ options.append(&option_lz_receive(&setup.env, 1, None));
408
+
409
+ let params = FeeParams {
410
+ sender: Address::generate(&setup.env),
411
+ dst_eid: 30_000,
412
+ calldata_size: 0,
413
+ options,
414
+ price_feed,
415
+ default_multiplier_bps: 12_000,
416
+ lz_receive_base_gas: 1,
417
+ lz_compose_base_gas: 0,
418
+ floor_margin_usd: 30_000_000_000, // 3e10
419
+ native_cap: 222_000,
420
+ multiplier_bps: 10_000,
421
+ };
422
+
423
+ // total_gas = 2, gas_fee = 2
424
+ // margin_usd=3e10, native_price_usd=2000e10 => margin_in_native = (3e10 * 10^7) / 2000e10 = 15000
425
+ // fee_with_margin = 2 + 15000 = 15002, fee_with_multiplier = 2
426
+ let executor = Address::generate(&setup.env);
427
+ let fee = setup.client.get_fee(&executor, &params);
428
+ assert_eq!(fee, 15002);
429
+ }
430
+
431
+ #[test]
432
+ fn test_get_fee_multiplier_wins_over_floor_margin() {
433
+ let setup = TestSetup::new();
434
+ let price_feed = setup.env.register(MockPriceFeedWithRatio, ());
435
+
436
+ let mut options = Bytes::new(&setup.env);
437
+ // lz_receive_gas must be non-zero
438
+ options.append(&option_lz_receive(&setup.env, 100_000, None));
439
+
440
+ let params = FeeParams {
441
+ sender: Address::generate(&setup.env),
442
+ dst_eid: 30_000,
443
+ calldata_size: 0,
444
+ options,
445
+ price_feed,
446
+ default_multiplier_bps: 12_000,
447
+ lz_receive_base_gas: 1,
448
+ lz_compose_base_gas: 0,
449
+ floor_margin_usd: 30_000_000_000, // 3e10
450
+ native_cap: 222_000,
451
+ multiplier_bps: 15_000,
452
+ };
453
+
454
+ // total_gas = 100,001, gas_fee = 100,001
455
+ // margin_usd=3e10, native_price_usd=2000e10 => margin_in_native = 15000
456
+ // fee_with_margin = 100,001 + 15000 = 115,001
457
+ // fee_with_multiplier = (100,001 * 15000) / 10000 = 150,001
458
+ let executor = Address::generate(&setup.env);
459
+ let fee = setup.client.get_fee(&executor, &params);
460
+ assert_eq!(fee, 150_001);
461
+ }
462
+
463
+ #[test]
464
+ fn test_get_fee_errors_eid_not_supported_when_base_gas_zero() {
465
+ let setup = TestSetup::new();
466
+
467
+ let params = FeeParams {
468
+ sender: Address::generate(&setup.env),
469
+ dst_eid: 30_000,
470
+ calldata_size: 0,
471
+ options: Bytes::new(&setup.env),
472
+ price_feed: Address::generate(&setup.env),
473
+ default_multiplier_bps: 12_000,
474
+ lz_receive_base_gas: 0,
475
+ lz_compose_base_gas: 0,
476
+ floor_margin_usd: 0,
477
+ native_cap: 0,
478
+ multiplier_bps: 0,
479
+ };
480
+
481
+ let executor = Address::generate(&setup.env);
482
+ assert_eq!(
483
+ setup.client.try_get_fee(&executor, &params).unwrap_err().unwrap(),
484
+ ExecutorFeeLibError::EidNotSupported.into()
485
+ );
486
+ }
487
+
488
+ #[test]
489
+ fn test_get_fee_errors_no_options() {
490
+ let setup = TestSetup::new();
491
+
492
+ let params = FeeParams {
493
+ sender: Address::generate(&setup.env),
494
+ dst_eid: 30_000,
495
+ calldata_size: 0,
496
+ options: Bytes::new(&setup.env),
497
+ price_feed: Address::generate(&setup.env), // not called (fails during option parsing)
498
+ default_multiplier_bps: 12_000,
499
+ lz_receive_base_gas: 1,
500
+ lz_compose_base_gas: 0,
501
+ floor_margin_usd: 0,
502
+ native_cap: 1_000,
503
+ multiplier_bps: 10_000,
504
+ };
505
+
506
+ let executor = Address::generate(&setup.env);
507
+ assert_eq!(
508
+ setup.client.try_get_fee(&executor, &params).unwrap_err().unwrap(),
509
+ ExecutorFeeLibError::NoOptions.into()
510
+ );
511
+ }
512
+
513
+ #[test]
514
+ fn test_get_fee_errors_invalid_fee_when_price_feed_returns_negative_total_gas_fee() {
515
+ let setup = TestSetup::new();
516
+ let price_feed = setup.env.register(MockPriceFeedNegativeFee, ());
517
+
518
+ let mut options = Bytes::new(&setup.env);
519
+ options.append(&option_lz_receive(&setup.env, 1, None));
520
+
521
+ let params = FeeParams {
522
+ sender: Address::generate(&setup.env),
523
+ dst_eid: 30_000,
524
+ calldata_size: 0,
525
+ options,
526
+ price_feed,
527
+ default_multiplier_bps: 12_000,
528
+ lz_receive_base_gas: 1,
529
+ lz_compose_base_gas: 0,
530
+ floor_margin_usd: 0,
531
+ native_cap: 0,
532
+ multiplier_bps: 10_000,
533
+ };
534
+
535
+ let executor = Address::generate(&setup.env);
536
+ assert_eq!(
537
+ setup.client.try_get_fee(&executor, &params).unwrap_err().unwrap(),
538
+ ExecutorFeeLibError::InvalidFee.into()
539
+ );
540
+ }
541
+
542
+ // internal helpers
543
+
544
+ #[test]
545
+ fn test_is_v1_eid() {
546
+ let env = Env::default();
547
+
548
+ // V1: eid < 30000
549
+ assert_eq!(ExecutorFeeLib::is_v1_eid_for_test(&env, 0), true);
550
+ assert_eq!(ExecutorFeeLib::is_v1_eid_for_test(&env, 1), true);
551
+ assert_eq!(ExecutorFeeLib::is_v1_eid_for_test(&env, 29_999), true);
552
+
553
+ // V2: eid >= 30000
554
+ assert_eq!(ExecutorFeeLib::is_v1_eid_for_test(&env, 30_000), false);
555
+ assert_eq!(ExecutorFeeLib::is_v1_eid_for_test(&env, 30_001), false);
556
+ }
557
+
558
+ #[test]
559
+ fn test_safe_u128_to_i128() {
560
+ let env = Env::default();
561
+
562
+ assert_eq!(ExecutorFeeLib::safe_u128_to_i128_for_test(&env, 0), 0);
563
+ assert_eq!(ExecutorFeeLib::safe_u128_to_i128_for_test(&env, 123), 123);
564
+ assert_eq!(ExecutorFeeLib::safe_u128_to_i128_for_test(&env, i128::MAX as u128), i128::MAX);
565
+ }
566
+
567
+ #[test]
568
+ #[should_panic(expected = "Error(Contract, #9)")] // ExecutorFeeLibError::Overflow
569
+ fn test_safe_u128_to_i128_overflow() {
570
+ let env = Env::default();
571
+ // Value exceeds i128::MAX, should panic with Overflow error
572
+ let _ = ExecutorFeeLib::safe_u128_to_i128_for_test(&env, (i128::MAX as u128) + 1);
573
+ }
574
+
575
+ #[test]
576
+ fn test_get_effective_multiplier_bps() {
577
+ let env = Env::default();
578
+
579
+ // When multiplier_bps == 0, use default
580
+ let params = FeeParams {
581
+ sender: Address::generate(&env),
582
+ dst_eid: 1,
583
+ calldata_size: 1,
584
+ options: Bytes::new(&env),
585
+ price_feed: Address::generate(&env),
586
+ default_multiplier_bps: 12_000,
587
+ lz_receive_base_gas: 1,
588
+ lz_compose_base_gas: 0,
589
+ floor_margin_usd: 0,
590
+ native_cap: 0,
591
+ multiplier_bps: 0,
592
+ };
593
+ assert_eq!(ExecutorFeeLib::get_effective_multiplier_bps_for_test(&env, &params), 12_000);
594
+
595
+ // When multiplier_bps != 0, use it instead of default
596
+ let params = FeeParams { multiplier_bps: 15_000, ..params };
597
+ assert_eq!(ExecutorFeeLib::get_effective_multiplier_bps_for_test(&env, &params), 15_000);
598
+ }
599
+
600
+ #[test]
601
+ fn test_apply_premium_to_gas_multiplier_only() {
602
+ let env = Env::default();
603
+
604
+ // When native_price_usd == 0, only apply fee_with_multiplier
605
+ let fee = ExecutorFeeLib::apply_premium_to_gas_for_test(&env, 100, 12_000, 10, 0);
606
+ assert_eq!(fee, 120); // (100 * 12000) / 10000 = 120
607
+
608
+ // When margin_usd == 0, only apply fee_with_multiplier
609
+ let fee = ExecutorFeeLib::apply_premium_to_gas_for_test(&env, 100, 12_000, 0, 20_000_000_000_000);
610
+ assert_eq!(fee, 120);
611
+ }
612
+
613
+ #[test]
614
+ fn test_apply_premium_to_gas_margin_wins() {
615
+ let env = Env::default();
616
+
617
+ // margin_usd=3e10, native_price_usd=2000e10
618
+ // margin_in_native = (3e10 * 10^7) / 2000e10 = 15000
619
+ // fee_with_margin = 15000 + 100 = 15100
620
+ // fee_with_multiplier = (100 * 10000) / 10000 = 100
621
+ // max(15100, 100) = 15100
622
+ let fee = ExecutorFeeLib::apply_premium_to_gas_for_test(&env, 100, 10_000, 30_000_000_000, 20_000_000_000_000);
623
+ assert_eq!(fee, 15100);
624
+ }
625
+
626
+ #[test]
627
+ fn test_apply_premium_to_gas_multiplier_wins() {
628
+ let env = Env::default();
629
+
630
+ // margin_usd=1e9, native_price_usd=2000e10 => margin_in_native = (1e9 * 10^7) / 2000e10 = 500
631
+ // fee_with_margin = 500 + 100 = 600
632
+ // fee_with_multiplier = (100 * 15000) / 10000 = 150
633
+ // In this case margin wins if we use fee=100.
634
+ // Let's use fee=2000.
635
+ // fee=2000, multiplier=1.5x => 3000
636
+ // fee_with_margin = 500 + 2000 = 2500
637
+ // max(2500, 3000) = 3000
638
+ let fee = ExecutorFeeLib::apply_premium_to_gas_for_test(&env, 2000, 15_000, 1_000_000_000, 20_000_000_000_000);
639
+ assert_eq!(fee, 3000);
640
+ }
641
+
642
+ #[test]
643
+ fn test_convert_and_apply_premium_to_value() {
644
+ let env = Env::default();
645
+
646
+ // When value == 0, return 0 immediately
647
+ let fee =
648
+ ExecutorFeeLib::convert_and_apply_premium_to_value_for_test(&env, 0, 10_000_000_000, 10_000_000_000, 12_000);
649
+ assert_eq!(fee, 0);
650
+
651
+ // Normal case: value=10, ratio=2:1, multiplier=1.2x
652
+ // converted = (10 * 2e10) / 1e10 = 20
653
+ // fee = (20 * 12000) / 10000 = 24
654
+ let fee =
655
+ ExecutorFeeLib::convert_and_apply_premium_to_value_for_test(&env, 10, 20_000_000_000, 10_000_000_000, 12_000);
656
+ assert_eq!(fee, 24);
657
+ }
658
+
659
+ #[test]
660
+ fn test_decode_executor_options() {
661
+ let env = Env::default();
662
+
663
+ // Only lzReceive
664
+ let mut options = Bytes::new(&env);
665
+ options.append(&option_lz_receive(&env, 50, None));
666
+ let (value, gas) = ExecutorFeeLib::decode_executor_options_for_test(&env, &options, 30_000, 1, 20, 222_000);
667
+ assert_eq!(value, 0);
668
+ assert_eq!(gas, 51); // base(1) + lzReceive(50)
669
+
670
+ // lzReceive with value
671
+ let mut options = Bytes::new(&env);
672
+ options.append(&option_lz_receive(&env, 50, Some(25)));
673
+ let (value, gas) = ExecutorFeeLib::decode_executor_options_for_test(&env, &options, 30_000, 1, 20, 222_000);
674
+ assert_eq!(value, 25);
675
+ assert_eq!(gas, 51);
676
+
677
+ // With nativeDrop
678
+ let receiver = bytes32(&env, 0xAB);
679
+ let mut options = Bytes::new(&env);
680
+ options.append(&option_lz_receive(&env, 10, None));
681
+ options.append(&option_native_drop(&env, 30, &receiver));
682
+ let (value, gas) = ExecutorFeeLib::decode_executor_options_for_test(&env, &options, 30_000, 1, 20, 222_000);
683
+ assert_eq!(value, 30);
684
+ assert_eq!(gas, 11);
685
+
686
+ // With lzCompose (gas + value + compose_base)
687
+ let mut options = Bytes::new(&env);
688
+ options.append(&option_lz_receive(&env, 10, None));
689
+ options.append(&option_lz_compose(&env, 0, 30, Some(5)));
690
+ let (value, gas) = ExecutorFeeLib::decode_executor_options_for_test(&env, &options, 30_000, 1, 20, 222_000);
691
+ assert_eq!(value, 5);
692
+ assert_eq!(gas, 61); // base(1) + lzReceive(10) + lzCompose(30) + compose_base(20*1)
693
+
694
+ // With ordered execution overhead (lz_receive_gas must be non-zero)
695
+ let mut options = Bytes::new(&env);
696
+ options.append(&option_lz_receive(&env, 9_000, None));
697
+ options.append(&option_ordered_execution(&env));
698
+ let (value, gas) = ExecutorFeeLib::decode_executor_options_for_test(&env, &options, 30_000, 1_000, 0, 222_000);
699
+ assert_eq!(value, 0);
700
+ assert_eq!(gas, 10_200); // ((1_000 + 9_000) * 102) / 100 = 10_200
701
+ }