@layerzerolabs/protocol-stellar-v2 0.2.18 → 0.2.20

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 (213) hide show
  1. package/.turbo/turbo-build.log +303 -253
  2. package/.turbo/turbo-lint.log +66 -65
  3. package/.turbo/turbo-test.log +1312 -1282
  4. package/Cargo.lock +21 -8
  5. package/Cargo.toml +2 -0
  6. package/contracts/ERROR_SPEC.md +9 -2
  7. package/contracts/common-macros/src/contract_ttl.rs +18 -7
  8. package/contracts/common-macros/src/lib.rs +4 -4
  9. package/contracts/common-macros/src/tests/contract_ttl.rs +1 -1
  10. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap +2 -1
  11. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +7 -12
  12. package/contracts/common-macros/src/upgradeable.rs +15 -21
  13. package/contracts/message-libs/uln-302/src/events.rs +4 -0
  14. package/contracts/message-libs/uln-302/src/send_uln.rs +23 -7
  15. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +38 -64
  16. package/contracts/oapps/counter/Cargo.toml +1 -0
  17. package/contracts/oapps/counter/integration_tests/setup_uln.rs +1 -1
  18. package/contracts/oapps/oapp/src/oapp_receiver.rs +1 -1
  19. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +113 -65
  20. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +111 -82
  21. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +293 -65
  22. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +331 -56
  23. package/contracts/oapps/oft/Cargo.toml +10 -7
  24. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_oft_fee.rs +3 -4
  25. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_pausable.rs +2 -3
  26. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_rate_limiter.rs +1 -1
  27. package/contracts/oapps/oft/integration-tests/mod.rs +1 -1
  28. package/contracts/oapps/oft/integration-tests/setup.rs +28 -127
  29. package/contracts/oapps/oft/integration-tests/utils.rs +254 -21
  30. package/contracts/oapps/oft/src/extensions/oft_fee.rs +23 -8
  31. package/contracts/oapps/oft/src/extensions/pausable.rs +19 -4
  32. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +52 -28
  33. package/contracts/oapps/oft/src/lib.rs +10 -14
  34. package/contracts/oapps/oft/src/oft.rs +143 -193
  35. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +9 -11
  36. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +12 -14
  37. package/contracts/oapps/oft/src/oft_types/mod.rs +13 -0
  38. package/contracts/oapps/{oft-std → oft-core}/Cargo.toml +6 -4
  39. package/contracts/oapps/{oft-std → oft-core}/integration-tests/mod.rs +1 -1
  40. package/contracts/oapps/{oft-std → oft-core}/integration-tests/setup.rs +126 -29
  41. package/contracts/oapps/{oft → oft-core}/integration-tests/test_with_sml.rs +3 -3
  42. package/contracts/oapps/oft-core/integration-tests/utils.rs +201 -0
  43. package/contracts/oapps/oft-core/src/lib.rs +18 -0
  44. package/contracts/oapps/oft-core/src/oft_core.rs +479 -0
  45. package/contracts/oapps/{oft → oft-core}/src/tests/mod.rs +0 -2
  46. package/contracts/oapps/{oft → oft-core}/src/tests/test_lz_receive.rs +7 -7
  47. package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_msg_codec.rs +4 -4
  48. package/contracts/oapps/{oft → oft-core}/src/tests/test_resolve_address.rs +3 -3
  49. package/contracts/oapps/{oft → oft-core}/src/tests/test_utils.rs +46 -27
  50. package/contracts/oapps/{oft → oft-core}/src/utils.rs +1 -1
  51. package/contracts/upgrader/src/lib.rs +30 -57
  52. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract1.wasm +0 -0
  53. package/contracts/upgrader/src/tests/test_data/test_upgradeable_contract2.wasm +0 -0
  54. package/contracts/upgrader/src/tests/test_upgrader.rs +44 -35
  55. package/contracts/utils/src/buffer_reader.rs +1 -0
  56. package/contracts/utils/src/errors.rs +8 -2
  57. package/contracts/utils/src/ownable.rs +125 -3
  58. package/contracts/utils/src/tests/option_ext.rs +1 -1
  59. package/contracts/utils/src/tests/ownable.rs +445 -7
  60. package/contracts/utils/src/tests/ttl_configurable.rs +2 -2
  61. package/contracts/utils/src/tests/upgradeable.rs +372 -175
  62. package/contracts/utils/src/ttl_configurable.rs +3 -3
  63. package/contracts/utils/src/upgradeable.rs +48 -23
  64. package/contracts/workers/dvn/Cargo.toml +1 -0
  65. package/contracts/workers/dvn/src/auth.rs +12 -42
  66. package/contracts/workers/dvn/src/dvn.rs +16 -31
  67. package/contracts/workers/dvn/src/errors.rs +0 -1
  68. package/contracts/workers/dvn/src/interfaces/dvn.rs +35 -0
  69. package/contracts/workers/dvn/src/lib.rs +4 -3
  70. package/contracts/workers/dvn/src/tests/auth.rs +1 -1
  71. package/contracts/workers/dvn/src/tests/dvn.rs +19 -15
  72. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +2 -4
  73. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +1 -3
  74. package/contracts/workers/dvn/src/tests/setup.rs +5 -9
  75. package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
  76. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +3 -5
  77. package/contracts/workers/dvn-fee-lib/src/tests/dvn_fee_lib.rs +2 -3
  78. package/contracts/workers/executor/Cargo.toml +1 -0
  79. package/contracts/workers/executor/src/executor.rs +15 -26
  80. package/contracts/workers/executor-fee-lib/Cargo.toml +2 -1
  81. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +63 -5
  82. package/contracts/workers/executor-fee-lib/src/executor_option.rs +28 -1
  83. package/contracts/workers/executor-fee-lib/src/lib.rs +3 -0
  84. package/contracts/workers/executor-fee-lib/src/tests/executor_fee_lib.rs +701 -0
  85. package/contracts/workers/executor-fee-lib/src/tests/executor_option.rs +370 -0
  86. package/contracts/workers/executor-fee-lib/src/tests/mod.rs +4 -0
  87. package/contracts/workers/executor-fee-lib/src/tests/setup.rs +60 -0
  88. package/contracts/workers/executor-helper/src/lib.rs +3 -0
  89. package/contracts/workers/executor-helper/src/tests/executor_helper.rs +184 -0
  90. package/contracts/workers/executor-helper/src/tests/mod.rs +2 -0
  91. package/contracts/workers/executor-helper/src/tests/setup.rs +366 -0
  92. package/contracts/workers/fee-lib-interfaces/Cargo.toml +14 -0
  93. package/contracts/workers/{worker/src/interfaces/mod.rs → fee-lib-interfaces/src/lib.rs} +4 -3
  94. package/contracts/workers/price-feed/Cargo.toml +2 -1
  95. package/contracts/workers/price-feed/src/events.rs +1 -1
  96. package/contracts/workers/price-feed/src/lib.rs +3 -0
  97. package/contracts/workers/price-feed/src/price_feed.rs +6 -12
  98. package/contracts/workers/price-feed/src/storage.rs +1 -1
  99. package/contracts/workers/price-feed/src/tests/mod.rs +2 -0
  100. package/contracts/workers/price-feed/src/tests/price_feed.rs +869 -0
  101. package/contracts/workers/price-feed/src/tests/setup.rs +70 -0
  102. package/contracts/workers/price-feed/src/types.rs +1 -1
  103. package/contracts/workers/worker/src/errors.rs +0 -3
  104. package/contracts/workers/worker/src/lib.rs +0 -2
  105. package/contracts/workers/worker/src/storage.rs +32 -29
  106. package/contracts/workers/worker/src/tests/setup.rs +1 -7
  107. package/contracts/workers/worker/src/tests/worker.rs +50 -42
  108. package/contracts/workers/worker/src/worker.rs +49 -58
  109. package/package.json +4 -5
  110. package/sdk/.turbo/turbo-test.log +229 -217
  111. package/sdk/dist/generated/bml.d.ts +39 -1
  112. package/sdk/dist/generated/bml.js +33 -8
  113. package/sdk/dist/generated/counter.d.ts +131 -3
  114. package/sdk/dist/generated/counter.js +41 -10
  115. package/sdk/dist/generated/dvn.d.ts +431 -362
  116. package/sdk/dist/generated/dvn.js +80 -55
  117. package/sdk/dist/generated/dvn_fee_lib.d.ts +327 -251
  118. package/sdk/dist/generated/dvn_fee_lib.js +55 -57
  119. package/sdk/dist/generated/endpoint.d.ts +131 -3
  120. package/sdk/dist/generated/endpoint.js +41 -10
  121. package/sdk/dist/generated/executor.d.ts +503 -339
  122. package/sdk/dist/generated/executor.js +80 -48
  123. package/sdk/dist/generated/executor_fee_lib.d.ts +395 -319
  124. package/sdk/dist/generated/executor_fee_lib.js +54 -56
  125. package/sdk/dist/generated/executor_helper.d.ts +53 -187
  126. package/sdk/dist/generated/executor_helper.js +47 -29
  127. package/sdk/dist/generated/layerzero_view.d.ts +1271 -0
  128. package/sdk/dist/generated/layerzero_view.js +294 -0
  129. package/sdk/dist/generated/oft.d.ts +1851 -0
  130. package/sdk/dist/generated/oft.js +347 -0
  131. package/sdk/dist/generated/price_feed.d.ts +329 -253
  132. package/sdk/dist/generated/price_feed.js +55 -57
  133. package/sdk/dist/generated/sml.d.ts +131 -3
  134. package/sdk/dist/generated/sml.js +41 -10
  135. package/sdk/dist/generated/treasury.d.ts +131 -3
  136. package/sdk/dist/generated/treasury.js +41 -10
  137. package/sdk/dist/generated/uln302.d.ts +131 -3
  138. package/sdk/dist/generated/uln302.js +43 -12
  139. package/sdk/dist/generated/upgrader.d.ts +201 -15
  140. package/sdk/dist/generated/upgrader.js +99 -1
  141. package/sdk/dist/index.d.ts +2 -2
  142. package/sdk/dist/index.js +3 -3
  143. package/sdk/package.json +3 -2
  144. package/sdk/src/index.ts +3 -3
  145. package/sdk/test/oft-sml.test.ts +20 -20
  146. package/sdk/test/upgrader.test.ts +2 -3
  147. package/sdk/turbo.json +8 -0
  148. package/tools/ts-bindings-gen/Cargo.toml +2 -0
  149. package/tools/ts-bindings-gen/src/main.rs +53 -5
  150. package/turbo.json +0 -2
  151. package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +0 -23
  152. package/contracts/oapps/oft/src/interfaces/mod.rs +0 -3
  153. package/contracts/oapps/oft/src/oft_impl.rs +0 -201
  154. package/contracts/oapps/oft/src/tests/extensions/mod.rs +0 -11
  155. package/contracts/oapps/oft/src/tests/extensions/setup.rs +0 -917
  156. package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +0 -751
  157. package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +0 -434
  158. package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +0 -1080
  159. package/contracts/oapps/oft-std/integration-tests/utils.rs +0 -427
  160. package/contracts/oapps/oft-std/src/lib.rs +0 -16
  161. package/contracts/oapps/oft-std/src/oft.rs +0 -174
  162. package/sdk/dist/generated/oft_std.d.ts +0 -1722
  163. package/sdk/dist/generated/oft_std.js +0 -316
  164. package/sdk/dist/wasm/blocked-message-lib.d.ts +0 -1
  165. package/sdk/dist/wasm/blocked-message-lib.js +0 -2
  166. package/sdk/dist/wasm/counter.d.ts +0 -1
  167. package/sdk/dist/wasm/counter.js +0 -2
  168. package/sdk/dist/wasm/dvn-fee-lib.d.ts +0 -1
  169. package/sdk/dist/wasm/dvn-fee-lib.js +0 -2
  170. package/sdk/dist/wasm/dvn.d.ts +0 -1
  171. package/sdk/dist/wasm/dvn.js +0 -2
  172. package/sdk/dist/wasm/endpoint-v2.d.ts +0 -1
  173. package/sdk/dist/wasm/endpoint-v2.js +0 -2
  174. package/sdk/dist/wasm/executor-fee-lib.d.ts +0 -1
  175. package/sdk/dist/wasm/executor-fee-lib.js +0 -2
  176. package/sdk/dist/wasm/executor-helper.d.ts +0 -1
  177. package/sdk/dist/wasm/executor-helper.js +0 -2
  178. package/sdk/dist/wasm/executor.d.ts +0 -1
  179. package/sdk/dist/wasm/executor.js +0 -2
  180. package/sdk/dist/wasm/layerzero-views.d.ts +0 -1
  181. package/sdk/dist/wasm/layerzero-views.js +0 -2
  182. package/sdk/dist/wasm/oft-std.d.ts +0 -1
  183. package/sdk/dist/wasm/oft-std.js +0 -2
  184. package/sdk/dist/wasm/price-feed.d.ts +0 -1
  185. package/sdk/dist/wasm/price-feed.js +0 -2
  186. package/sdk/dist/wasm/simple-message-lib.d.ts +0 -1
  187. package/sdk/dist/wasm/simple-message-lib.js +0 -2
  188. package/sdk/dist/wasm/treasury.d.ts +0 -1
  189. package/sdk/dist/wasm/treasury.js +0 -2
  190. package/sdk/dist/wasm/uln302.d.ts +0 -1
  191. package/sdk/dist/wasm/uln302.js +0 -2
  192. package/sdk/dist/wasm/upgrader.d.ts +0 -1
  193. package/sdk/dist/wasm/upgrader.js +0 -2
  194. package/sdk/dist/wasm.d.ts +0 -15
  195. package/sdk/dist/wasm.js +0 -15
  196. /package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/mod.rs +0 -0
  197. /package/contracts/oapps/{oft → oft-core}/src/codec/mod.rs +0 -0
  198. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_compose_msg_codec.rs +0 -0
  199. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_msg_codec.rs +0 -0
  200. /package/contracts/oapps/{oft → oft-core}/src/errors.rs +0 -0
  201. /package/contracts/oapps/{oft → oft-core}/src/events.rs +0 -0
  202. /package/contracts/oapps/{oft → oft-core}/src/storage.rs +0 -0
  203. /package/contracts/oapps/{oft → oft-core}/src/tests/test_decimals.rs +0 -0
  204. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_compose_msg_codec.rs +0 -0
  205. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_version.rs +0 -0
  206. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_oft.rs +0 -0
  207. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_send.rs +0 -0
  208. /package/contracts/oapps/{oft → oft-core}/src/tests/test_send.rs +0 -0
  209. /package/contracts/oapps/{oft → oft-core}/src/tests/test_token.rs +0 -0
  210. /package/contracts/oapps/{oft → oft-core}/src/types.rs +0 -0
  211. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/dvn_fee_lib.rs +0 -0
  212. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/executor_fee_lib.rs +0 -0
  213. /package/contracts/workers/{worker/src/interfaces → fee-lib-interfaces/src}/price_feed.rs +0 -0
@@ -0,0 +1,370 @@
1
+ use soroban_sdk::{Bytes, Env};
2
+
3
+ use crate::executor_option;
4
+
5
+ use super::setup::{
6
+ bytes32, option_header, option_lz_compose, option_lz_receive, option_native_drop, option_ordered_execution,
7
+ };
8
+
9
+ // parse_executor_options
10
+
11
+ #[test]
12
+ fn test_parse_executor_options_aggregates_values() {
13
+ let env = Env::default();
14
+ let receiver = bytes32(&env, 0x11);
15
+
16
+ let mut options = Bytes::new(&env);
17
+ options.append(&option_lz_receive(&env, 10, Some(2))); // gas=10, value=2
18
+ options.append(&option_native_drop(&env, 5, &receiver)); // value=5
19
+ options.append(&option_lz_compose(&env, 0, 7, Some(3))); // gas=7, value=3
20
+ options.append(&option_ordered_execution(&env)); // flag only
21
+
22
+ let agg = executor_option::parse_executor_options(&env, &options, false, 1_000);
23
+ assert_eq!(agg.total_gas, 17); // 10 + 7
24
+ assert_eq!(agg.total_value, 10); // 2 + 5 + 3
25
+ assert_eq!(agg.num_lz_compose, 1);
26
+ assert_eq!(agg.ordered, true);
27
+ }
28
+
29
+ #[test]
30
+ fn test_parse_executor_options_counts_multiple_lz_compose() {
31
+ let env = Env::default();
32
+
33
+ let mut options = Bytes::new(&env);
34
+ options.append(&option_lz_receive(&env, 10, None));
35
+ options.append(&option_lz_compose(&env, 0, 7, None));
36
+ options.append(&option_lz_compose(&env, 1, 8, Some(1)));
37
+
38
+ let agg = executor_option::parse_executor_options(&env, &options, false, 1_000);
39
+ assert_eq!(agg.num_lz_compose, 2);
40
+ assert_eq!(agg.total_gas, 25); // 10 + 7 + 8
41
+ assert_eq!(agg.total_value, 1); // only compose value
42
+ }
43
+
44
+ #[test]
45
+ fn test_parse_executor_options_accumulates_multiple_lz_receive_gas_and_value() {
46
+ let env = Env::default();
47
+
48
+ let mut options = Bytes::new(&env);
49
+ options.append(&option_lz_receive(&env, 10, Some(2))); // gas=10, value=2
50
+ options.append(&option_lz_receive(&env, 20, Some(3))); // gas=20, value=3
51
+
52
+ let agg = executor_option::parse_executor_options(&env, &options, false, 1_000);
53
+ assert_eq!(agg.total_gas, 30);
54
+ assert_eq!(agg.total_value, 5);
55
+ assert_eq!(agg.num_lz_compose, 0);
56
+ assert_eq!(agg.ordered, false);
57
+ }
58
+
59
+ #[test]
60
+ fn test_parse_executor_options_allows_total_value_equal_to_native_cap() {
61
+ let env = Env::default();
62
+ let receiver = bytes32(&env, 0x33);
63
+
64
+ // total_value = lzReceive.value(50) + nativeDrop(50) = 100, cap=100 should pass (<=).
65
+ let mut options = Bytes::new(&env);
66
+ options.append(&option_lz_receive(&env, 1, Some(50)));
67
+ options.append(&option_native_drop(&env, 50, &receiver));
68
+
69
+ let agg = executor_option::parse_executor_options(&env, &options, false, 100);
70
+ assert_eq!(agg.total_value, 100);
71
+ assert_eq!(agg.total_gas, 1);
72
+ }
73
+
74
+ #[test]
75
+ #[should_panic(expected = "Error(Contract, #8)")] // ExecutorFeeLibError::NoOptions
76
+ fn test_parse_executor_options_no_options() {
77
+ let env = Env::default();
78
+ executor_option::parse_executor_options(&env, &Bytes::new(&env), false, 1_000);
79
+ }
80
+
81
+ #[test]
82
+ #[should_panic(expected = "Error(Contract, #5)")] // ExecutorFeeLibError::InvalidLzReceiveOption
83
+ fn test_parse_executor_options_rejects_invalid_lz_receive_payload_length() {
84
+ let env = Env::default();
85
+ let mut options = Bytes::new(&env);
86
+
87
+ // Bad lzReceive payload (15 bytes instead of 16 or 32). Still wrapped in a valid option header.
88
+ let bad = Bytes::from_slice(&env, &[0u8; 15]);
89
+ options.append(&option_header(&env, message_lib_common::worker_options::EXECUTOR_OPTION_TYPE_LZRECEIVE, bad));
90
+
91
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
92
+ }
93
+
94
+ #[test]
95
+ #[should_panic(expected = "Error(Contract, #6)")] // ExecutorFeeLibError::InvalidNativeDropOption
96
+ fn test_parse_executor_options_rejects_invalid_native_drop_payload_length() {
97
+ let env = Env::default();
98
+ let mut options = Bytes::new(&env);
99
+
100
+ // Need a non-zero lzReceive gas, otherwise we'd fail with ZeroLzReceiveGasProvided first.
101
+ options.append(&option_lz_receive(&env, 1, None));
102
+
103
+ // Bad nativeDrop payload (47 bytes instead of 48).
104
+ let bad = Bytes::from_slice(&env, &[0u8; 47]);
105
+ options.append(&option_header(&env, message_lib_common::worker_options::EXECUTOR_OPTION_TYPE_NATIVE_DROP, bad));
106
+
107
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
108
+ }
109
+
110
+ #[test]
111
+ #[should_panic(expected = "Error(Contract, #4)")] // ExecutorFeeLibError::InvalidLzComposeOption
112
+ fn test_parse_executor_options_rejects_invalid_lz_compose_payload_length() {
113
+ let env = Env::default();
114
+ let mut options = Bytes::new(&env);
115
+
116
+ // Need a non-zero lzReceive gas, otherwise we'd fail with ZeroLzReceiveGasProvided first.
117
+ options.append(&option_lz_receive(&env, 1, None));
118
+
119
+ // Bad lzCompose payload (17 bytes instead of 18 or 34).
120
+ let bad = Bytes::from_slice(&env, &[0u8; 17]);
121
+ options.append(&option_header(&env, crate::executor_option::EXECUTOR_OPTION_TYPE_LZCOMPOSE, bad));
122
+
123
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
124
+ }
125
+
126
+ #[test]
127
+ #[should_panic(expected = "Error(Contract, #10)")] // ExecutorFeeLibError::UnsupportedOptionType
128
+ fn test_parse_executor_options_v1_rejects_lz_receive_with_value() {
129
+ let env = Env::default();
130
+
131
+ let mut options = Bytes::new(&env);
132
+ options.append(&option_lz_receive(&env, 1, Some(1)));
133
+
134
+ executor_option::parse_executor_options(&env, &options, true, 1_000);
135
+ }
136
+
137
+ #[test]
138
+ #[should_panic(expected = "Error(Contract, #10)")] // ExecutorFeeLibError::UnsupportedOptionType
139
+ fn test_parse_executor_options_v1_rejects_lz_compose() {
140
+ let env = Env::default();
141
+
142
+ let mut options = Bytes::new(&env);
143
+ options.append(&option_lz_receive(&env, 1, None));
144
+ options.append(&option_lz_compose(&env, 0, 1, None));
145
+
146
+ executor_option::parse_executor_options(&env, &options, true, 1_000);
147
+ }
148
+
149
+ #[test]
150
+ #[should_panic(expected = "Error(Contract, #11)")] // ExecutorFeeLibError::ZeroLzComposeGasProvided
151
+ fn test_parse_executor_options_zero_lz_compose_gas() {
152
+ let env = Env::default();
153
+
154
+ let mut options = Bytes::new(&env);
155
+ options.append(&option_lz_receive(&env, 1, None));
156
+ options.append(&option_lz_compose(&env, 0, 0, None));
157
+
158
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
159
+ }
160
+
161
+ #[test]
162
+ #[should_panic(expected = "Error(Contract, #10)")] // ExecutorFeeLibError::UnsupportedOptionType
163
+ fn test_parse_executor_options_unknown_option_type() {
164
+ let env = Env::default();
165
+
166
+ let mut options = Bytes::new(&env);
167
+ options.append(&option_lz_receive(&env, 1, None));
168
+ options.append(&option_header(&env, 0xFE, Bytes::new(&env)));
169
+
170
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
171
+ }
172
+
173
+ #[test]
174
+ #[should_panic(expected = "Error(Contract, #7)")] // ExecutorFeeLibError::NativeAmountExceedsCap
175
+ fn test_parse_executor_options_native_amount_exceeds_cap() {
176
+ let env = Env::default();
177
+ let receiver = bytes32(&env, 0x22);
178
+
179
+ let mut options = Bytes::new(&env);
180
+ options.append(&option_lz_receive(&env, 1, None));
181
+ options.append(&option_native_drop(&env, 101, &receiver)); // cap=100
182
+
183
+ executor_option::parse_executor_options(&env, &options, false, 100);
184
+ }
185
+
186
+ #[test]
187
+ #[should_panic(expected = "Error(Contract, #12)")] // ExecutorFeeLibError::ZeroLzReceiveGasProvided
188
+ fn test_parse_executor_options_zero_lz_receive_gas() {
189
+ let env = Env::default();
190
+ let options = option_ordered_execution(&env);
191
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
192
+ }
193
+
194
+ #[test]
195
+ #[should_panic(expected = "Error(Contract, #12)")] // ExecutorFeeLibError::ZeroLzReceiveGasProvided
196
+ fn test_parse_executor_options_treats_zero_lz_receive_gas_as_missing() {
197
+ let env = Env::default();
198
+ let mut options = Bytes::new(&env);
199
+ options.append(&option_lz_receive(&env, 0, None)); // lzReceive present but gas=0
200
+ executor_option::parse_executor_options(&env, &options, false, 1_000);
201
+ }
202
+
203
+ // next_executor_option
204
+
205
+ #[test]
206
+ fn test_next_executor_option() {
207
+ let env = Env::default();
208
+
209
+ // Extract option type and data correctly
210
+ let data = Bytes::from_slice(&env, &[0x01, 0x02]);
211
+ let option = option_header(&env, 1, data.clone()); // type 1
212
+ let mut reader = utils::buffer_reader::BufferReader::new(&option);
213
+ let (option_type, option_data) = executor_option::test::next_executor_option_for_test(&mut reader);
214
+ assert_eq!(option_type, 1);
215
+ assert_eq!(option_data.len(), 2);
216
+ assert_eq!(option_data.get(0).unwrap(), 0x01);
217
+ assert_eq!(option_data.get(1).unwrap(), 0x02);
218
+ }
219
+
220
+ #[test]
221
+ #[should_panic(expected = "Error(Contract, #1000)")] // BufferReaderError::InvalidLength (wrapped option_size)
222
+ fn test_next_executor_option_rejects_zero_option_size() {
223
+ let env = Env::default();
224
+ use utils::buffer_writer::BufferWriter;
225
+
226
+ // [worker_id=1][option_size=0][...]
227
+ let mut w = BufferWriter::new(&env);
228
+ w.write_u8(super::setup::EXECUTOR_WORKER_ID).write_u16(0);
229
+ let raw = w.to_bytes();
230
+
231
+ let mut reader = utils::buffer_reader::BufferReader::new(&raw);
232
+ let _ = executor_option::test::next_executor_option_for_test(&mut reader);
233
+ }
234
+
235
+ // next_executor_option (invalid/truncated)
236
+
237
+ #[test]
238
+ #[should_panic(expected = "Error(Contract, #1000)")] // BufferReaderError::InvalidLength
239
+ fn test_next_executor_option_rejects_truncated_option_data() {
240
+ let env = Env::default();
241
+ use utils::buffer_writer::BufferWriter;
242
+
243
+ // Claims option_size=3 => [option_type (1) + option_data (2)]
244
+ // But we only provide option_type and 1 byte of data => truncated.
245
+ let mut w = BufferWriter::new(&env);
246
+ w.write_u8(super::setup::EXECUTOR_WORKER_ID)
247
+ .write_u16(3)
248
+ .write_u8(0xAA) // option_type
249
+ .write_u8(0x01); // only 1 byte data (should be 2)
250
+ let raw = w.to_bytes();
251
+
252
+ let mut reader = utils::buffer_reader::BufferReader::new(&raw);
253
+ let _ = executor_option::test::next_executor_option_for_test(&mut reader);
254
+ }
255
+
256
+ // decode_lz_receive_option
257
+
258
+ #[test]
259
+ fn test_decode_lz_receive_option() {
260
+ let env = Env::default();
261
+ use utils::buffer_writer::BufferWriter;
262
+
263
+ // 16 bytes: gas only
264
+ let mut w = BufferWriter::new(&env);
265
+ w.write_u128(1);
266
+ let (gas, value) = executor_option::test::decode_lz_receive_option_for_test(&env, &w.to_bytes());
267
+ assert_eq!(gas, 1);
268
+ assert_eq!(value, 0);
269
+
270
+ // 32 bytes: gas + value
271
+ let mut w = BufferWriter::new(&env);
272
+ w.write_u128(1).write_u128(2);
273
+ let (gas, value) = executor_option::test::decode_lz_receive_option_for_test(&env, &w.to_bytes());
274
+ assert_eq!(gas, 1);
275
+ assert_eq!(value, 2);
276
+ }
277
+
278
+ #[test]
279
+ #[should_panic(expected = "Error(Contract, #5)")] // ExecutorFeeLibError::InvalidLzReceiveOption
280
+ fn test_decode_lz_receive_option_invalid_length_15() {
281
+ let env = Env::default();
282
+ // Invalid length: 15 bytes (not 16 or 32)
283
+ let bad = Bytes::from_slice(&env, &[0u8; 15]);
284
+ let _ = executor_option::test::decode_lz_receive_option_for_test(&env, &bad);
285
+ }
286
+
287
+ #[test]
288
+ #[should_panic(expected = "Error(Contract, #5)")] // ExecutorFeeLibError::InvalidLzReceiveOption
289
+ fn test_decode_lz_receive_option_invalid_length_33() {
290
+ let env = Env::default();
291
+ // Invalid length: 33 bytes (not 16 or 32)
292
+ let bad = Bytes::from_slice(&env, &[0u8; 33]);
293
+ let _ = executor_option::test::decode_lz_receive_option_for_test(&env, &bad);
294
+ }
295
+
296
+ // decode_native_drop_option
297
+
298
+ #[test]
299
+ fn test_decode_native_drop_option() {
300
+ let env = Env::default();
301
+ use utils::buffer_writer::BufferWriter;
302
+
303
+ // 48 bytes: amount + receiver
304
+ let receiver = bytes32(&env, 0x12);
305
+ let mut w = BufferWriter::new(&env);
306
+ w.write_u128(1).write_bytes_n(&receiver);
307
+ let (amount, recv) = executor_option::test::decode_native_drop_option_for_test(&env, &w.to_bytes());
308
+ assert_eq!(amount, 1);
309
+ assert_eq!(recv, receiver);
310
+ }
311
+
312
+ #[test]
313
+ #[should_panic(expected = "Error(Contract, #6)")] // ExecutorFeeLibError::InvalidNativeDropOption
314
+ fn test_decode_native_drop_option_invalid_length_47() {
315
+ let env = Env::default();
316
+ // Invalid length: 47 bytes (not 48)
317
+ let bad = Bytes::from_slice(&env, &[0u8; 47]);
318
+ let _ = executor_option::test::decode_native_drop_option_for_test(&env, &bad);
319
+ }
320
+
321
+ #[test]
322
+ #[should_panic(expected = "Error(Contract, #6)")] // ExecutorFeeLibError::InvalidNativeDropOption
323
+ fn test_decode_native_drop_option_invalid_length_49() {
324
+ let env = Env::default();
325
+ // Invalid length: 49 bytes (not 48)
326
+ let bad = Bytes::from_slice(&env, &[0u8; 49]);
327
+ let _ = executor_option::test::decode_native_drop_option_for_test(&env, &bad);
328
+ }
329
+
330
+ // decode_lz_compose_option
331
+
332
+ #[test]
333
+ fn test_decode_lz_compose_option() {
334
+ let env = Env::default();
335
+ use utils::buffer_writer::BufferWriter;
336
+
337
+ // 18 bytes: index + gas (no value)
338
+ let mut w = BufferWriter::new(&env);
339
+ w.write_u16(0).write_u128(1);
340
+ let (index, gas, value) = executor_option::test::decode_lz_compose_option_for_test(&env, &w.to_bytes());
341
+ assert_eq!(index, 0);
342
+ assert_eq!(gas, 1);
343
+ assert_eq!(value, 0);
344
+
345
+ // 34 bytes: index + gas + value
346
+ let mut w = BufferWriter::new(&env);
347
+ w.write_u16(0).write_u128(1).write_u128(2);
348
+ let (index, gas, value) = executor_option::test::decode_lz_compose_option_for_test(&env, &w.to_bytes());
349
+ assert_eq!(index, 0);
350
+ assert_eq!(gas, 1);
351
+ assert_eq!(value, 2);
352
+ }
353
+
354
+ #[test]
355
+ #[should_panic(expected = "Error(Contract, #4)")] // ExecutorFeeLibError::InvalidLzComposeOption
356
+ fn test_decode_lz_compose_option_invalid_length_17() {
357
+ let env = Env::default();
358
+ // Invalid length: 17 bytes (not 18 or 34) - InvalidLzComposeOption
359
+ let bad = Bytes::from_slice(&env, &[0u8; 17]);
360
+ let _ = executor_option::test::decode_lz_compose_option_for_test(&env, &bad);
361
+ }
362
+
363
+ #[test]
364
+ #[should_panic(expected = "Error(Contract, #4)")] // ExecutorFeeLibError::InvalidLzComposeOption
365
+ fn test_decode_lz_compose_option_invalid_length_35() {
366
+ let env = Env::default();
367
+ // Invalid length: 35 bytes (not 18 or 34) - InvalidLzComposeOption
368
+ let bad = Bytes::from_slice(&env, &[0u8; 35]);
369
+ let _ = executor_option::test::decode_lz_compose_option_for_test(&env, &bad);
370
+ }
@@ -0,0 +1,4 @@
1
+ mod setup;
2
+
3
+ mod executor_fee_lib;
4
+ mod executor_option;
@@ -0,0 +1,60 @@
1
+ use soroban_sdk::{testutils::Address as _, Address, Bytes, BytesN, Env};
2
+ use utils::buffer_writer::BufferWriter;
3
+
4
+ use crate::{ExecutorFeeLib, ExecutorFeeLibClient};
5
+
6
+ pub const EXECUTOR_WORKER_ID: u8 = 1;
7
+
8
+ pub struct TestSetup<'a> {
9
+ pub env: Env,
10
+ pub client: ExecutorFeeLibClient<'a>,
11
+ }
12
+
13
+ impl<'a> TestSetup<'a> {
14
+ pub fn new() -> Self {
15
+ let env = Env::default();
16
+ let owner = Address::generate(&env);
17
+ let contract_id = env.register(ExecutorFeeLib, (&owner,));
18
+ let client = ExecutorFeeLibClient::new(&env, &contract_id);
19
+ Self { env, client }
20
+ }
21
+ }
22
+
23
+ pub fn bytes32(env: &Env, fill: u8) -> BytesN<32> {
24
+ BytesN::from_array(env, &[fill; 32])
25
+ }
26
+
27
+ pub fn option_header(env: &Env, option_type: u8, option_data: Bytes) -> Bytes {
28
+ let mut w = BufferWriter::new(env);
29
+ let option_size = 1u16 + (option_data.len() as u16);
30
+ w.write_u8(EXECUTOR_WORKER_ID).write_u16(option_size).write_u8(option_type).write_bytes(&option_data);
31
+ w.to_bytes()
32
+ }
33
+
34
+ pub fn option_lz_receive(env: &Env, gas: u128, value: Option<u128>) -> Bytes {
35
+ let mut w = BufferWriter::new(env);
36
+ w.write_u128(gas);
37
+ if let Some(v) = value {
38
+ w.write_u128(v);
39
+ }
40
+ option_header(env, message_lib_common::worker_options::EXECUTOR_OPTION_TYPE_LZRECEIVE, w.to_bytes())
41
+ }
42
+
43
+ pub fn option_native_drop(env: &Env, amount: u128, receiver: &BytesN<32>) -> Bytes {
44
+ let mut w = BufferWriter::new(env);
45
+ w.write_u128(amount).write_bytes_n(receiver);
46
+ option_header(env, message_lib_common::worker_options::EXECUTOR_OPTION_TYPE_NATIVE_DROP, w.to_bytes())
47
+ }
48
+
49
+ pub fn option_lz_compose(env: &Env, index: u16, gas: u128, value: Option<u128>) -> Bytes {
50
+ let mut w = BufferWriter::new(env);
51
+ w.write_u16(index).write_u128(gas);
52
+ if let Some(v) = value {
53
+ w.write_u128(v);
54
+ }
55
+ option_header(env, crate::executor_option::EXECUTOR_OPTION_TYPE_LZCOMPOSE, w.to_bytes())
56
+ }
57
+
58
+ pub fn option_ordered_execution(env: &Env) -> Bytes {
59
+ option_header(env, crate::executor_option::EXECUTOR_OPTION_TYPE_ORDERED_EXECUTION, Bytes::new(env))
60
+ }
@@ -3,3 +3,6 @@
3
3
  mod executor_helper;
4
4
 
5
5
  pub use executor_helper::*;
6
+
7
+ #[cfg(test)]
8
+ mod tests;
@@ -0,0 +1,184 @@
1
+ use super::setup::TestSetup;
2
+ use endpoint_v2::Origin;
3
+ use executor::NativeDropParams;
4
+ use soroban_sdk::{testutils::Address as _, vec, Address, Bytes, BytesN, Vec};
5
+
6
+ // =============================================================================
7
+ // execute() tests
8
+ // =============================================================================
9
+
10
+ #[test]
11
+ fn test_execute_without_value() {
12
+ let setup = TestSetup::new();
13
+ let mut params = setup.default_execution_params();
14
+ assert_eq!(params.value, 0);
15
+ // Verifies that `origin` is forwarded unchanged (merged from the former `test_execute_with_different_origins`).
16
+ params.origin = Origin { src_eid: 999, sender: BytesN::from_array(&setup.env, &[0xABu8; 32]), nonce: 12345 };
17
+
18
+ // Mint tokens to admin to prove transfer is skipped when value == 0
19
+ setup.mint_native(&setup.admin, 100);
20
+ let admin_before = setup.balance_native(&setup.admin);
21
+
22
+ setup.mock_lz_receive_auth(&setup.executor, &params);
23
+
24
+ setup.executor_helper_client.execute(&setup.executor, &params, &setup.admin);
25
+
26
+ // Verify lz_receive was called with correct params
27
+ let record = setup.receiver_client().get_lz_receive();
28
+ assert!(record.is_some());
29
+ let record = record.unwrap();
30
+ assert_eq!(record.executor, setup.executor);
31
+ assert_eq!(record.origin, params.origin);
32
+ assert_eq!(record.origin.src_eid, 999);
33
+ assert_eq!(record.origin.nonce, 12345);
34
+ assert_eq!(record.guid, params.guid);
35
+ assert_eq!(record.message, params.message);
36
+ assert_eq!(record.extra_data, params.extra_data);
37
+ assert_eq!(record.value, params.value);
38
+
39
+ // Verify no token transfer occurred
40
+ assert_eq!(setup.balance_native(&setup.admin), admin_before);
41
+ }
42
+
43
+ #[test]
44
+ fn test_execute_with_large_message() {
45
+ let setup = TestSetup::new();
46
+ let mut params = setup.default_execution_params();
47
+
48
+ // Create a larger message
49
+ let large_data: [u8; 256] = [0xFFu8; 256];
50
+ params.message = Bytes::from_slice(&setup.env, &large_data);
51
+
52
+ setup.mock_lz_receive_auth(&setup.executor, &params);
53
+
54
+ setup.executor_helper_client.execute(&setup.executor, &params, &setup.admin);
55
+
56
+ let record = setup.receiver_client().get_lz_receive();
57
+ assert!(record.is_some());
58
+ assert_eq!(record.unwrap().message.len(), 256);
59
+ }
60
+
61
+ #[test]
62
+ fn test_execute_with_empty_message() {
63
+ let setup = TestSetup::new();
64
+ let mut params = setup.default_execution_params();
65
+ params.message = Bytes::new(&setup.env);
66
+ params.extra_data = Bytes::new(&setup.env);
67
+
68
+ setup.mock_lz_receive_auth(&setup.executor, &params);
69
+
70
+ setup.executor_helper_client.execute(&setup.executor, &params, &setup.admin);
71
+
72
+ let record = setup.receiver_client().get_lz_receive();
73
+ assert!(record.is_some());
74
+ let record = record.unwrap();
75
+ assert_eq!(record.message.len(), 0);
76
+ assert_eq!(record.extra_data.len(), 0);
77
+ }
78
+
79
+ // =============================================================================
80
+ // compose() tests
81
+ // =============================================================================
82
+
83
+ #[test]
84
+ fn test_compose_without_value() {
85
+ let setup = TestSetup::new();
86
+ let params = setup.default_compose_params();
87
+ assert_eq!(params.value, 0);
88
+
89
+ // Mint tokens to admin to prove transfer is skipped when value == 0
90
+ setup.mint_native(&setup.admin, 100);
91
+ let admin_before = setup.balance_native(&setup.admin);
92
+
93
+ setup.mock_lz_compose_auth(&setup.executor, &params);
94
+
95
+ setup.executor_helper_client.compose(&setup.executor, &params, &setup.admin);
96
+
97
+ // Verify lz_compose was called with correct params
98
+ let record = setup.composer_client().get_lz_compose();
99
+ assert!(record.is_some());
100
+ let record = record.unwrap();
101
+ assert_eq!(record.executor, setup.executor);
102
+ assert_eq!(record.from, params.from);
103
+ assert_eq!(record.guid, params.guid);
104
+ assert_eq!(record.index, params.index);
105
+ assert_eq!(record.message, params.message);
106
+ assert_eq!(record.extra_data, params.extra_data);
107
+ assert_eq!(record.value, params.value);
108
+
109
+ // Verify no token transfer occurred
110
+ assert_eq!(setup.balance_native(&setup.admin), admin_before);
111
+ }
112
+
113
+ #[test]
114
+ fn test_compose_with_empty_data() {
115
+ let setup = TestSetup::new();
116
+ let mut params = setup.default_compose_params();
117
+ params.message = Bytes::new(&setup.env);
118
+ params.extra_data = Bytes::new(&setup.env);
119
+
120
+ setup.mock_lz_compose_auth(&setup.executor, &params);
121
+
122
+ setup.executor_helper_client.compose(&setup.executor, &params, &setup.admin);
123
+
124
+ let record = setup.composer_client().get_lz_compose();
125
+ assert!(record.is_some());
126
+ let record = record.unwrap();
127
+ assert_eq!(record.message.len(), 0);
128
+ assert_eq!(record.extra_data.len(), 0);
129
+ }
130
+
131
+ // =============================================================================
132
+ // native_drop() tests
133
+ // =============================================================================
134
+
135
+ #[test]
136
+ fn test_native_drop_delegates_to_executor() {
137
+ let setup = TestSetup::new();
138
+ let origin = setup.default_origin();
139
+ let dst_eid = 2u32;
140
+ let oapp = Address::generate(&setup.env);
141
+
142
+ let receiver1 = Address::generate(&setup.env);
143
+ let receiver2 = Address::generate(&setup.env);
144
+ let params: Vec<NativeDropParams> = vec![
145
+ &setup.env,
146
+ NativeDropParams { receiver: receiver1.clone(), amount: 10 },
147
+ NativeDropParams { receiver: receiver2.clone(), amount: 20 },
148
+ ];
149
+
150
+ setup.mock_native_drop_auth(&setup.executor, &setup.admin, &origin, dst_eid, &oapp, &params);
151
+
152
+ setup.executor_helper_client.native_drop(&setup.executor, &setup.admin, &origin, &dst_eid, &oapp, &params);
153
+
154
+ // Verify native_drop was called on executor with correct params
155
+ let record = setup.executor_client().get_native_drop();
156
+ assert!(record.is_some());
157
+ let record = record.unwrap();
158
+ assert_eq!(record.admin, setup.admin);
159
+ assert_eq!(record.origin, origin);
160
+ assert_eq!(record.dst_eid, dst_eid);
161
+ assert_eq!(record.oapp, oapp);
162
+ assert_eq!(record.params.len(), 2);
163
+ assert_eq!(record.params.get(0).unwrap().receiver, receiver1);
164
+ assert_eq!(record.params.get(0).unwrap().amount, 10);
165
+ assert_eq!(record.params.get(1).unwrap().receiver, receiver2);
166
+ assert_eq!(record.params.get(1).unwrap().amount, 20);
167
+ }
168
+
169
+ #[test]
170
+ fn test_native_drop_with_empty_params() {
171
+ let setup = TestSetup::new();
172
+ let origin = setup.default_origin();
173
+ let dst_eid = 1u32;
174
+ let oapp = Address::generate(&setup.env);
175
+ let params: Vec<NativeDropParams> = vec![&setup.env];
176
+
177
+ setup.mock_native_drop_auth(&setup.executor, &setup.admin, &origin, dst_eid, &oapp, &params);
178
+
179
+ setup.executor_helper_client.native_drop(&setup.executor, &setup.admin, &origin, &dst_eid, &oapp, &params);
180
+
181
+ let record = setup.executor_client().get_native_drop();
182
+ assert!(record.is_some());
183
+ assert_eq!(record.unwrap().params.len(), 0);
184
+ }
@@ -0,0 +1,2 @@
1
+ mod executor_helper;
2
+ mod setup;