@layerzerolabs/protocol-stellar-v2 0.2.15 → 0.2.19

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 (262) hide show
  1. package/.turbo/turbo-build.log +365 -297
  2. package/.turbo/turbo-lint.log +142 -110
  3. package/.turbo/turbo-test.log +1273 -1222
  4. package/Cargo.lock +20 -5
  5. package/Cargo.toml +4 -1
  6. package/contracts/ERROR_SPEC.md +44 -0
  7. package/contracts/common-macros/src/auth.rs +113 -0
  8. package/contracts/common-macros/src/contract_ttl.rs +84 -0
  9. package/contracts/common-macros/src/lib.rs +181 -30
  10. package/contracts/common-macros/src/lz_contract.rs +83 -0
  11. package/contracts/common-macros/src/tests/{ownable.rs → auth.rs} +48 -15
  12. package/contracts/common-macros/src/tests/contract_ttl.rs +662 -0
  13. package/contracts/common-macros/src/tests/mod.rs +2 -2
  14. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_multisig_code.snap +20 -0
  15. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__auth__snapshot_generated_ownable_code.snap +24 -0
  16. package/contracts/common-macros/src/tests/snapshots/{common_macros__tests__ownable__snapshot_only_owner_preserves_function_signature.snap → common_macros__tests__auth__snapshot_only_auth_preserves_function_signature.snap} +4 -4
  17. package/contracts/common-macros/src/tests/snapshots/{common_macros__tests__contract_impl__snapshot_generated_contract_impl_code.snap → common_macros__tests__contract_ttl__snapshot_generated_contractimpl_code.snap} +3 -3
  18. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__contract_ttl__snapshot_generated_contracttrait_code.snap +69 -0
  19. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ttl_configurable__snapshot_generated_ttl_configurable_code.snap +7 -21
  20. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__upgradeable__snapshot_generated_upgradeable_code.snap +2 -2
  21. package/contracts/common-macros/src/ttl_configurable.rs +19 -34
  22. package/contracts/common-macros/src/ttl_extendable.rs +36 -0
  23. package/contracts/common-macros/src/upgradeable.rs +5 -5
  24. package/contracts/common-macros/src/utils.rs +9 -0
  25. package/contracts/endpoint-v2/src/constants.rs +4 -4
  26. package/contracts/endpoint-v2/src/endpoint_v2.rs +38 -40
  27. package/contracts/endpoint-v2/src/errors.rs +4 -3
  28. package/contracts/endpoint-v2/src/events.rs +1 -1
  29. package/contracts/endpoint-v2/src/message_lib_manager.rs +18 -5
  30. package/contracts/endpoint-v2/src/messaging_channel.rs +11 -1
  31. package/contracts/endpoint-v2/src/messaging_composer.rs +11 -1
  32. package/contracts/endpoint-v2/src/storage.rs +1 -1
  33. package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +3 -3
  34. package/contracts/endpoint-v2/src/tests/endpoint_v2/quote.rs +1 -1
  35. package/contracts/endpoint-v2/src/tests/endpoint_v2/require_oapp_auth.rs +2 -2
  36. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +3 -3
  37. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +4 -4
  38. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_receive_lib_for_eid.rs +3 -3
  39. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_registered.rs +1 -1
  40. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_send_lib_for_eid.rs +3 -3
  41. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +1 -1
  42. package/contracts/endpoint-v2/src/tests/messaging_channel/clear_payload.rs +4 -4
  43. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound.rs +1 -1
  44. package/contracts/layerzero-views/src/layerzero_view.rs +3 -6
  45. package/contracts/macro-integration-tests/tests/runtime/ownable/mod.rs +2 -2
  46. package/contracts/macro-integration-tests/tests/runtime/ownable/{only_owner_guard.rs → only_auth_guard.rs} +1 -1
  47. package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/configuration.rs +1 -1
  48. package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/freeze.rs +1 -1
  49. package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/mod.rs +0 -1
  50. package/contracts/macro-integration-tests/tests/ui/ownable/fail/{only_owner_missing_env.rs → only_auth_missing_env.rs} +3 -3
  51. package/contracts/macro-integration-tests/tests/ui/ownable/fail/{only_owner_missing_env.stderr → only_auth_missing_env.stderr} +4 -4
  52. package/contracts/macro-integration-tests/tests/ui/ownable/pass/namespacing_and_imports.rs +2 -3
  53. package/contracts/macro-integration-tests/tests/ui/ownable/pass/{only_owner_env_param_variants.rs → only_auth_env_param_variants.rs} +9 -9
  54. package/contracts/macro-integration-tests/tests/ui/ttl_configurable/pass/minimal_contract.rs +6 -6
  55. package/contracts/message-libs/message-lib-common/src/errors.rs +7 -2
  56. package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1/decode_packet_header.rs +3 -3
  57. package/contracts/message-libs/message-lib-common/src/tests/worker_options/append_lz_receive_option.rs +1 -2
  58. package/contracts/message-libs/message-lib-common/src/tests/worker_options/append_native_drop_option.rs +1 -2
  59. package/contracts/message-libs/message-lib-common/src/tests/worker_options/convert_legacy_options.rs +9 -9
  60. package/contracts/message-libs/message-lib-common/src/tests/worker_options/extract_type_3_options.rs +1 -1
  61. package/contracts/message-libs/message-lib-common/src/tests/worker_options/left_pad_to_bytes32.rs +1 -1
  62. package/contracts/message-libs/message-lib-common/src/tests/worker_options/split_worker_options.rs +2 -2
  63. package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +7 -9
  64. package/contracts/message-libs/treasury/src/errors.rs +2 -2
  65. package/contracts/message-libs/treasury/src/events.rs +1 -1
  66. package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +2 -2
  67. package/contracts/message-libs/treasury/src/storage.rs +1 -1
  68. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +1 -1
  69. package/contracts/message-libs/treasury/src/treasury.rs +14 -16
  70. package/contracts/message-libs/uln-302/src/receive_uln.rs +13 -2
  71. package/contracts/message-libs/uln-302/src/send_uln.rs +24 -4
  72. package/contracts/message-libs/uln-302/src/uln302.rs +6 -24
  73. package/contracts/oapps/counter/Cargo.toml +14 -1
  74. package/contracts/oapps/counter/integration_tests/mod.rs +4 -1
  75. package/contracts/oapps/counter/integration_tests/{setup.rs → setup_sml.rs} +48 -80
  76. package/contracts/oapps/counter/integration_tests/setup_uln.rs +997 -0
  77. package/contracts/oapps/counter/integration_tests/signing.rs +62 -0
  78. package/contracts/oapps/counter/integration_tests/test_with_sml.rs +24 -55
  79. package/contracts/oapps/counter/integration_tests/test_with_uln.rs +314 -0
  80. package/contracts/oapps/counter/integration_tests/utils.rs +196 -53
  81. package/contracts/oapps/counter/src/counter.rs +67 -43
  82. package/contracts/oapps/counter/src/tests/mod.rs +0 -13
  83. package/contracts/oapps/counter/src/tests/test_counter.rs +5 -7
  84. package/contracts/oapps/oapp/src/errors.rs +5 -1
  85. package/contracts/oapps/oapp/src/macro_tests/test_macros.rs +93 -78
  86. package/contracts/oapps/oapp/src/oapp_core.rs +36 -21
  87. package/contracts/oapps/oapp/src/oapp_options_type3.rs +48 -12
  88. package/contracts/oapps/oapp/src/oapp_receiver.rs +106 -41
  89. package/contracts/oapps/oapp/src/oapp_sender.rs +26 -34
  90. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +9 -8
  91. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +25 -17
  92. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +7 -7
  93. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +14 -15
  94. package/contracts/oapps/oapp-macros/src/generators.rs +128 -0
  95. package/contracts/oapps/oapp-macros/src/lib.rs +113 -56
  96. package/contracts/oapps/oft/Cargo.toml +10 -7
  97. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_oft_fee.rs +3 -4
  98. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_pausable.rs +2 -3
  99. package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/test_rate_limiter.rs +1 -1
  100. package/contracts/oapps/oft/integration-tests/mod.rs +1 -1
  101. package/contracts/oapps/oft/integration-tests/setup.rs +29 -110
  102. package/contracts/oapps/oft/integration-tests/utils.rs +254 -21
  103. package/contracts/oapps/oft/src/extensions/oft_fee.rs +13 -14
  104. package/contracts/oapps/oft/src/extensions/pausable.rs +4 -4
  105. package/contracts/oapps/oft/src/extensions/rate_limiter.rs +5 -5
  106. package/contracts/oapps/oft/src/lib.rs +11 -13
  107. package/contracts/oapps/oft/src/oft.rs +147 -225
  108. package/contracts/oapps/oft/src/oft_types/lock_unlock.rs +9 -13
  109. package/contracts/oapps/oft/src/oft_types/mint_burn.rs +31 -14
  110. package/contracts/oapps/oft/src/oft_types/mod.rs +13 -0
  111. package/contracts/oapps/{oft-std → oft-core}/Cargo.toml +6 -4
  112. package/contracts/oapps/{oft-std → oft-core}/integration-tests/mod.rs +1 -1
  113. package/contracts/oapps/{oft-std → oft-core}/integration-tests/setup.rs +129 -30
  114. package/contracts/oapps/{oft → oft-core}/integration-tests/test_with_sml.rs +3 -3
  115. package/contracts/oapps/oft-core/integration-tests/utils.rs +201 -0
  116. package/contracts/oapps/oft-core/src/errors.rs +13 -0
  117. package/contracts/oapps/oft-core/src/lib.rs +18 -0
  118. package/contracts/oapps/oft-core/src/oft_core.rs +439 -0
  119. package/contracts/oapps/{oft → oft-core}/src/storage.rs +2 -0
  120. package/contracts/oapps/{oft → oft-core}/src/tests/mod.rs +0 -2
  121. package/contracts/oapps/{oft → oft-core}/src/tests/test_decimals.rs +2 -2
  122. package/contracts/oapps/{oft → oft-core}/src/tests/test_lz_receive.rs +7 -7
  123. package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_msg_codec.rs +4 -5
  124. package/contracts/oapps/{oft → oft-core}/src/tests/test_resolve_address.rs +3 -3
  125. package/contracts/oapps/{oft → oft-core}/src/tests/test_utils.rs +78 -37
  126. package/contracts/oapps/oft-core/src/types.rs +58 -0
  127. package/contracts/oapps/{oft → oft-core}/src/utils.rs +1 -1
  128. package/contracts/upgrader/src/lib.rs +4 -4
  129. package/contracts/utils/src/auth.rs +44 -0
  130. package/contracts/utils/src/errors.rs +31 -5
  131. package/contracts/utils/src/lib.rs +3 -0
  132. package/contracts/utils/src/multisig.rs +211 -0
  133. package/contracts/utils/src/ownable.rs +137 -13
  134. package/contracts/utils/src/tests/buffer_reader.rs +6 -6
  135. package/contracts/utils/src/tests/buffer_writer.rs +6 -6
  136. package/contracts/utils/src/tests/bytes_ext.rs +2 -4
  137. package/contracts/utils/src/tests/mod.rs +1 -0
  138. package/contracts/utils/src/tests/multisig.rs +731 -0
  139. package/contracts/utils/src/tests/option_ext.rs +2 -5
  140. package/contracts/utils/src/tests/ownable.rs +456 -7
  141. package/contracts/utils/src/tests/ttl_configurable.rs +27 -16
  142. package/contracts/utils/src/tests/upgradeable.rs +4 -2
  143. package/contracts/utils/src/ttl_configurable.rs +23 -8
  144. package/contracts/utils/src/ttl_extendable.rs +27 -0
  145. package/contracts/utils/src/upgradeable.rs +2 -0
  146. package/contracts/workers/dvn/Cargo.toml +1 -1
  147. package/contracts/workers/dvn/src/auth.rs +7 -7
  148. package/contracts/workers/dvn/src/dvn.rs +10 -38
  149. package/contracts/workers/dvn/src/errors.rs +0 -7
  150. package/contracts/workers/dvn/src/events.rs +1 -14
  151. package/contracts/workers/dvn/src/interfaces/dvn.rs +2 -2
  152. package/contracts/workers/dvn/src/interfaces/mod.rs +0 -2
  153. package/contracts/workers/dvn/src/storage.rs +3 -13
  154. package/contracts/workers/dvn/src/tests/auth.rs +4 -4
  155. package/contracts/workers/dvn/src/tests/dvn.rs +1 -2
  156. package/contracts/workers/dvn/src/tests/multisig/set_signer.rs +7 -8
  157. package/contracts/workers/dvn/src/tests/multisig/set_threshold.rs +11 -8
  158. package/contracts/workers/dvn/src/tests/multisig/verify_signatures.rs +11 -12
  159. package/contracts/workers/dvn/src/tests/setup.rs +5 -5
  160. package/contracts/workers/dvn-fee-lib/Cargo.toml +1 -1
  161. package/contracts/workers/dvn-fee-lib/src/dvn_fee_lib.rs +3 -6
  162. package/contracts/workers/executor/src/auth.rs +80 -16
  163. package/contracts/workers/executor/src/executor.rs +5 -31
  164. package/contracts/workers/executor/src/storage.rs +2 -9
  165. package/contracts/workers/executor-fee-lib/Cargo.toml +1 -1
  166. package/contracts/workers/executor-fee-lib/src/executor_fee_lib.rs +3 -6
  167. package/contracts/workers/executor-helper/Cargo.toml +1 -1
  168. package/contracts/workers/executor-helper/src/executor_helper.rs +53 -73
  169. package/contracts/workers/price-feed/Cargo.toml +1 -1
  170. package/contracts/workers/price-feed/src/price_feed.rs +7 -10
  171. package/contracts/workers/worker/src/errors.rs +4 -0
  172. package/contracts/workers/worker/src/tests/worker.rs +7 -6
  173. package/contracts/workers/worker/src/worker.rs +20 -16
  174. package/package.json +7 -5
  175. package/sdk/.turbo/turbo-build.log +1 -0
  176. package/sdk/.turbo/turbo-test.log +1019 -0
  177. package/sdk/dist/generated/bml.d.ts +95 -8
  178. package/sdk/dist/generated/bml.js +95 -36
  179. package/sdk/dist/generated/counter.d.ts +289 -44
  180. package/sdk/dist/generated/counter.js +119 -49
  181. package/sdk/dist/generated/dvn.d.ts +312 -229
  182. package/sdk/dist/generated/dvn.js +144 -83
  183. package/sdk/dist/generated/dvn_fee_lib.d.ts +258 -63
  184. package/sdk/dist/generated/dvn_fee_lib.js +95 -26
  185. package/sdk/dist/generated/endpoint.d.ts +219 -24
  186. package/sdk/dist/generated/endpoint.js +108 -41
  187. package/sdk/dist/generated/executor.d.ts +239 -87
  188. package/sdk/dist/generated/executor.js +135 -63
  189. package/sdk/dist/generated/executor_fee_lib.d.ts +278 -74
  190. package/sdk/dist/generated/executor_fee_lib.js +135 -59
  191. package/sdk/dist/generated/executor_helper.d.ts +163 -21
  192. package/sdk/dist/generated/executor_helper.js +124 -52
  193. package/sdk/dist/generated/oft.d.ts +1842 -0
  194. package/sdk/dist/generated/oft.js +345 -0
  195. package/sdk/dist/generated/price_feed.d.ts +258 -63
  196. package/sdk/dist/generated/price_feed.js +95 -26
  197. package/sdk/dist/generated/sml.d.ts +235 -34
  198. package/sdk/dist/generated/sml.js +126 -53
  199. package/sdk/dist/generated/treasury.d.ts +1016 -0
  200. package/sdk/dist/generated/treasury.js +248 -0
  201. package/sdk/dist/generated/uln302.d.ts +235 -34
  202. package/sdk/dist/generated/uln302.js +126 -53
  203. package/sdk/dist/generated/upgrader.d.ts +17 -2
  204. package/sdk/dist/generated/upgrader.js +19 -1
  205. package/sdk/dist/index.d.ts +2 -1
  206. package/sdk/dist/index.js +2 -1
  207. package/sdk/package.json +6 -3
  208. package/sdk/src/index.ts +2 -1
  209. package/sdk/test/counter-sml.test.ts +376 -0
  210. package/sdk/test/counter-uln.test.ts +493 -0
  211. package/sdk/test/{oft.test.ts → oft-sml.test.ts} +196 -321
  212. package/sdk/test/suites/constants.ts +22 -2
  213. package/sdk/test/suites/globalSetup.ts +450 -0
  214. package/sdk/test/suites/localnet.ts +23 -6
  215. package/sdk/test/upgrader.test.ts +7 -16
  216. package/sdk/test/utils.ts +558 -85
  217. package/sdk/turbo.json +8 -0
  218. package/sdk/vitest.config.ts +21 -0
  219. package/tools/ts-bindings-gen/Cargo.toml +2 -0
  220. package/tools/ts-bindings-gen/src/main.rs +52 -4
  221. package/contracts/common-macros/src/contract_impl.rs +0 -52
  222. package/contracts/common-macros/src/ownable.rs +0 -41
  223. package/contracts/common-macros/src/tests/contract_impl.rs +0 -386
  224. package/contracts/common-macros/src/tests/snapshots/common_macros__tests__ownable__snapshot_generated_ownable_code.snap +0 -12
  225. package/contracts/macro-integration-tests/tests/runtime/ttl_configurable/extend_instance_ttl.rs +0 -50
  226. package/contracts/oapps/oapp-macros/src/oapp_core.rs +0 -41
  227. package/contracts/oapps/oapp-macros/src/oapp_full.rs +0 -21
  228. package/contracts/oapps/oapp-macros/src/oapp_options_type3.rs +0 -31
  229. package/contracts/oapps/oapp-macros/src/oapp_receiver.rs +0 -48
  230. package/contracts/oapps/oapp-macros/src/oapp_sender.rs +0 -21
  231. package/contracts/oapps/oapp-macros/src/util.rs +0 -107
  232. package/contracts/oapps/oft/src/constants.rs +0 -5
  233. package/contracts/oapps/oft/src/default_oft_impl.rs +0 -152
  234. package/contracts/oapps/oft/src/errors.rs +0 -8
  235. package/contracts/oapps/oft/src/interfaces/mint_burn_token.rs +0 -23
  236. package/contracts/oapps/oft/src/interfaces/mod.rs +0 -3
  237. package/contracts/oapps/oft/src/tests/extensions/mod.rs +0 -11
  238. package/contracts/oapps/oft/src/tests/extensions/setup.rs +0 -903
  239. package/contracts/oapps/oft/src/tests/extensions/test_oft_fee.rs +0 -749
  240. package/contracts/oapps/oft/src/tests/extensions/test_pausable.rs +0 -432
  241. package/contracts/oapps/oft/src/tests/extensions/test_rate_limiter.rs +0 -1078
  242. package/contracts/oapps/oft/src/types.rs +0 -38
  243. package/contracts/oapps/oft-std/integration-tests/utils.rs +0 -427
  244. package/contracts/oapps/oft-std/src/lib.rs +0 -16
  245. package/contracts/oapps/oft-std/src/oft.rs +0 -156
  246. package/contracts/workers/dvn/src/interfaces/multisig.rs +0 -56
  247. package/contracts/workers/dvn/src/multisig.rs +0 -157
  248. package/sdk/dist/generated/oft_std.d.ts +0 -1544
  249. package/sdk/dist/generated/oft_std.js +0 -271
  250. package/sdk/test/index.test.ts +0 -375
  251. /package/contracts/oapps/{oft-std → oft}/integration-tests/extensions/mod.rs +0 -0
  252. /package/contracts/oapps/{oft → oft-core}/src/codec/mod.rs +0 -0
  253. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_compose_msg_codec.rs +0 -0
  254. /package/contracts/oapps/{oft → oft-core}/src/codec/oft_msg_codec.rs +0 -0
  255. /package/contracts/oapps/{oft → oft-core}/src/events.rs +0 -0
  256. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_compose_msg_codec.rs +0 -0
  257. /package/contracts/oapps/{oft → oft-core}/src/tests/test_oft_version.rs +0 -0
  258. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_oft.rs +0 -0
  259. /package/contracts/oapps/{oft → oft-core}/src/tests/test_quote_send.rs +0 -0
  260. /package/contracts/oapps/{oft → oft-core}/src/tests/test_send.rs +0 -0
  261. /package/contracts/oapps/{oft → oft-core}/src/tests/test_token.rs +0 -0
  262. /package/sdk/test/suites/{testUpgradeable.ts → dummyContractClient.ts} +0 -0
@@ -1,1078 +0,0 @@
1
- //! Tests for the rate limiter extension functionality.
2
- //!
3
- //! Tests verify:
4
- //! - Rate limit configuration (set/unset)
5
- //! - Capacity tracking and decay over time
6
- //! - Rate limit enforcement on send (outbound)
7
- //! - Rate limit enforcement on lz_receive (inbound)
8
- //! - Capacity release on opposite direction
9
-
10
- use crate::extensions::rate_limiter::{Direction, RateLimitError};
11
- use crate::tests::test_utils::{create_origin, create_recipient_address, encode_oft_message};
12
- use crate::utils::address_to_bytes32;
13
- use endpoint_v2::MessagingFee;
14
- use soroban_sdk::{
15
- testutils::{Address as _, Ledger as _},
16
- Address, Bytes, BytesN, Env, IntoVal,
17
- };
18
-
19
- use super::setup::ExtensiveOFTTestSetup;
20
-
21
- // ==================== Rate Limit Configuration Tests ====================
22
-
23
- #[test]
24
- fn test_initial_no_rate_limit() {
25
- let env = Env::default();
26
- let setup = ExtensiveOFTTestSetup::new(&env);
27
-
28
- let dst_eid = 100u32;
29
-
30
- // No rate limit configured, capacity should be MAX
31
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
32
- assert_eq!(capacity, i128::MAX);
33
-
34
- let (limit, window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
35
- assert_eq!(limit, 0);
36
- assert_eq!(window, 0);
37
- }
38
-
39
- #[test]
40
- fn test_set_rate_limit_outbound() {
41
- let env = Env::default();
42
- let setup = ExtensiveOFTTestSetup::new(&env);
43
-
44
- let dst_eid = 100u32;
45
- let limit = 1_000_000i128;
46
- let window_seconds = 3600u64; // 1 hour
47
-
48
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
49
-
50
- let (stored_limit, stored_window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
51
- assert_eq!(stored_limit, limit);
52
- assert_eq!(stored_window, window_seconds);
53
- }
54
-
55
- #[test]
56
- fn test_set_rate_limit_inbound() {
57
- let env = Env::default();
58
- let setup = ExtensiveOFTTestSetup::new(&env);
59
-
60
- let src_eid = 100u32;
61
- let limit = 2_000_000i128;
62
- let window_seconds = 7200u64; // 2 hours
63
-
64
- setup.set_rate_limit(&Direction::Inbound, src_eid, limit, window_seconds);
65
-
66
- let (stored_limit, stored_window) = setup.rate_limit_config(&Direction::Inbound, src_eid);
67
- assert_eq!(stored_limit, limit);
68
- assert_eq!(stored_window, window_seconds);
69
- }
70
-
71
- #[test]
72
- fn test_set_rate_limit_both_directions() {
73
- let env = Env::default();
74
- let setup = ExtensiveOFTTestSetup::new(&env);
75
-
76
- let eid = 100u32;
77
-
78
- setup.set_rate_limit(&Direction::Outbound, eid, 1_000_000, 3600);
79
- setup.set_rate_limit(&Direction::Inbound, eid, 2_000_000, 7200);
80
-
81
- let (outbound_limit, outbound_window) = setup.rate_limit_config(&Direction::Outbound, eid);
82
- let (inbound_limit, inbound_window) = setup.rate_limit_config(&Direction::Inbound, eid);
83
-
84
- assert_eq!(outbound_limit, 1_000_000);
85
- assert_eq!(outbound_window, 3600);
86
- assert_eq!(inbound_limit, 2_000_000);
87
- assert_eq!(inbound_window, 7200);
88
- }
89
-
90
- #[test]
91
- fn test_set_rate_limit_zero_limit_fails() {
92
- let env = Env::default();
93
- let setup = ExtensiveOFTTestSetup::new(&env);
94
-
95
- let result = setup.try_set_rate_limit(&Direction::Outbound, 100, 0, 3600);
96
- assert_eq!(result.err().unwrap().ok().unwrap(), RateLimitError::InvalidLimit.into());
97
- }
98
-
99
- #[test]
100
- fn test_set_rate_limit_zero_window_fails() {
101
- let env = Env::default();
102
- let setup = ExtensiveOFTTestSetup::new(&env);
103
-
104
- let result = setup.try_set_rate_limit(&Direction::Outbound, 100, 1_000_000, 0);
105
- assert_eq!(result.err().unwrap().ok().unwrap(), RateLimitError::InvalidWindowSeconds.into());
106
- }
107
-
108
- #[test]
109
- fn test_set_rate_limit_same_values_fails() {
110
- let env = Env::default();
111
- let setup = ExtensiveOFTTestSetup::new(&env);
112
-
113
- let dst_eid = 100u32;
114
- let limit = 1_000_000i128;
115
- let window_seconds = 3600u64;
116
-
117
- // Set rate limit
118
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
119
-
120
- // Try to set same values again - should fail with SameValue
121
- let result = setup.try_set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
122
- assert_eq!(result.err().unwrap().ok().unwrap(), RateLimitError::SameValue.into());
123
- }
124
-
125
- #[test]
126
- fn test_unset_rate_limit() {
127
- let env = Env::default();
128
- let setup = ExtensiveOFTTestSetup::new(&env);
129
-
130
- let dst_eid = 100u32;
131
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
132
-
133
- let (limit, _) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
134
- assert_eq!(limit, 1_000_000);
135
-
136
- setup.unset_rate_limit(&Direction::Outbound, dst_eid);
137
-
138
- let (limit_after, _) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
139
- assert_eq!(limit_after, 0);
140
- }
141
-
142
- #[test]
143
- fn test_unset_rate_limit_not_found() {
144
- let env = Env::default();
145
- let setup = ExtensiveOFTTestSetup::new(&env);
146
-
147
- let dst_eid = 100u32;
148
-
149
- // Try to unset rate limit that doesn't exist - should fail with SameValue
150
- let result = setup.try_unset_rate_limit(&Direction::Outbound, dst_eid);
151
- assert_eq!(result.err().unwrap().ok().unwrap(), RateLimitError::SameValue.into());
152
- }
153
-
154
- #[test]
155
- fn test_update_rate_limit() {
156
- let env = Env::default();
157
- let setup = ExtensiveOFTTestSetup::new(&env);
158
-
159
- let dst_eid = 100u32;
160
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
161
-
162
- // Update to new values
163
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 2_000_000, 7200);
164
-
165
- let (limit, window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
166
- assert_eq!(limit, 2_000_000);
167
- assert_eq!(window, 7200);
168
- }
169
-
170
- #[test]
171
- fn test_update_rate_limit_only_limit() {
172
- let env = Env::default();
173
- let setup = ExtensiveOFTTestSetup::new(&env);
174
-
175
- let dst_eid = 100u32;
176
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
177
-
178
- // Update only the limit (keep same window)
179
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 2_000_000, 3600);
180
-
181
- let (limit, window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
182
- assert_eq!(limit, 2_000_000);
183
- assert_eq!(window, 3600);
184
- }
185
-
186
- #[test]
187
- fn test_update_rate_limit_only_window() {
188
- let env = Env::default();
189
- let setup = ExtensiveOFTTestSetup::new(&env);
190
-
191
- let dst_eid = 100u32;
192
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
193
-
194
- // Update only the window (keep same limit)
195
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 7200);
196
-
197
- let (limit, window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
198
- assert_eq!(limit, 1_000_000);
199
- assert_eq!(window, 7200);
200
- }
201
-
202
- // ==================== Capacity Tests ====================
203
-
204
- #[test]
205
- fn test_initial_capacity_equals_limit() {
206
- let env = Env::default();
207
- let setup = ExtensiveOFTTestSetup::new(&env);
208
-
209
- let dst_eid = 100u32;
210
- let limit = 1_000_000i128;
211
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
212
-
213
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
214
- assert_eq!(capacity, limit);
215
- }
216
-
217
- #[test]
218
- fn test_in_flight_initially_zero() {
219
- let env = Env::default();
220
- let setup = ExtensiveOFTTestSetup::new(&env);
221
-
222
- let dst_eid = 100u32;
223
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
224
-
225
- let in_flight = setup.rate_limit_in_flight(&Direction::Outbound, dst_eid);
226
- assert_eq!(in_flight, 0);
227
- }
228
-
229
- #[test]
230
- fn test_rate_limit_in_flight_no_rate_limit_returns_zero() {
231
- let env = Env::default();
232
- let setup = ExtensiveOFTTestSetup::new(&env);
233
-
234
- let dst_eid = 100u32;
235
-
236
- // No rate limit set - in_flight should return 0
237
- let in_flight = setup.rate_limit_in_flight(&Direction::Outbound, dst_eid);
238
- assert_eq!(in_flight, 0);
239
- }
240
-
241
- #[test]
242
- fn test_rate_limit_capacity_zero_when_in_flight_exceeds_limit() {
243
- let env = Env::default();
244
- let setup = ExtensiveOFTTestSetup::new(&env);
245
-
246
- // Set fee deposit address (required by ExtensiveOFT)
247
- let fee_collector = create_recipient_address(&env);
248
- setup.set_fee_deposit_address(&fee_collector);
249
-
250
- let sender = Address::generate(&env);
251
- let dst_eid = 100u32;
252
- let peer = BytesN::from_array(&env, &[2u8; 32]);
253
- setup.set_peer(dst_eid, &peer);
254
-
255
- // Set outbound rate limit
256
- let limit = 1_000_000i128;
257
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
258
-
259
- // Use all capacity
260
- let amount_ld = limit;
261
- setup.fund_tokens(&sender, amount_ld);
262
- setup.fund_native_fees(&sender, setup.native_fee);
263
-
264
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
265
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
266
- let oft_receipt = setup.quote_oft(&send_param);
267
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
268
-
269
- // Capacity should be exactly 0 after using all of it
270
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
271
- assert_eq!(capacity, 0);
272
-
273
- // In-flight should equal limit
274
- let in_flight = setup.rate_limit_in_flight(&Direction::Outbound, dst_eid);
275
- assert_eq!(in_flight, limit);
276
- }
277
-
278
- #[test]
279
- fn test_update_rate_limit_preserves_in_flight() {
280
- let env = Env::default();
281
- let setup = ExtensiveOFTTestSetup::new(&env);
282
-
283
- // Set fee deposit address (required by ExtensiveOFT)
284
- let fee_collector = create_recipient_address(&env);
285
- setup.set_fee_deposit_address(&fee_collector);
286
-
287
- let sender = Address::generate(&env);
288
- let dst_eid = 100u32;
289
- let peer = BytesN::from_array(&env, &[2u8; 32]);
290
- setup.set_peer(dst_eid, &peer);
291
-
292
- // Set initial rate limit
293
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
294
-
295
- // Use some capacity
296
- let amount_ld = 300_000i128;
297
- setup.fund_tokens(&sender, amount_ld);
298
- setup.fund_native_fees(&sender, setup.native_fee);
299
-
300
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
301
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
302
- let oft_receipt = setup.quote_oft(&send_param);
303
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
304
-
305
- // In-flight should be 300_000
306
- let in_flight_before = setup.rate_limit_in_flight(&Direction::Outbound, dst_eid);
307
- assert_eq!(in_flight_before, amount_ld);
308
-
309
- // Update rate limit to higher value
310
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 2_000_000, 3600);
311
-
312
- // In-flight should be preserved (checkpointed)
313
- let in_flight_after = setup.rate_limit_in_flight(&Direction::Outbound, dst_eid);
314
- assert_eq!(in_flight_after, amount_ld);
315
-
316
- // New capacity should be new_limit - in_flight
317
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
318
- assert_eq!(capacity, 2_000_000 - amount_ld);
319
- }
320
-
321
- // ==================== Capacity Decay Tests ====================
322
-
323
- #[test]
324
- fn test_rate_limit_invalid_timestamp_fails() {
325
- let env = Env::default();
326
- let setup = ExtensiveOFTTestSetup::new(&env);
327
-
328
- let dst_eid = 100u32;
329
-
330
- // Start with a timestamp in the future
331
- setup.advance_time(10000);
332
-
333
- // Set rate limit (last_update will be set to current timestamp: 10000)
334
- setup.set_rate_limit(&Direction::Outbound, dst_eid, 1_000_000, 3600);
335
-
336
- // Move time backwards by modifying ledger info directly
337
- env.ledger().with_mut(|li| {
338
- li.timestamp = 5000; // Earlier than last_update
339
- });
340
-
341
- // Querying in_flight should fail because timestamp < last_update
342
- let result = setup.try_rate_limit_in_flight(&Direction::Outbound, dst_eid);
343
- assert!(result.is_err());
344
- let err = result.err().unwrap().ok().unwrap();
345
- assert_eq!(err, RateLimitError::InvalidTimestamp.into());
346
- }
347
-
348
- #[test]
349
- fn test_consume_rate_limit_when_capacity_exactly_zero() {
350
- let env = Env::default();
351
- let setup = ExtensiveOFTTestSetup::new(&env);
352
-
353
- // Set fee deposit address (required by ExtensiveOFT)
354
- let fee_collector = create_recipient_address(&env);
355
- setup.set_fee_deposit_address(&fee_collector);
356
-
357
- let sender = Address::generate(&env);
358
- let dst_eid = 100u32;
359
- let peer = BytesN::from_array(&env, &[2u8; 32]);
360
- setup.set_peer(dst_eid, &peer);
361
-
362
- // Set outbound rate limit
363
- let limit = 1_000_000i128;
364
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
365
-
366
- // Use all capacity
367
- setup.fund_tokens(&sender, limit);
368
- setup.fund_native_fees(&sender, setup.native_fee);
369
-
370
- let send_param = setup.create_send_param(dst_eid, limit, limit);
371
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
372
- let oft_receipt = setup.quote_oft(&send_param);
373
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
374
-
375
- // Capacity should be 0 now (in_flight equals limit)
376
- assert_eq!(setup.rate_limit_capacity(&Direction::Outbound, dst_eid), 0);
377
-
378
- // Try to send a small amount - should fail because capacity is exactly 0
379
- // This tests the branch where capacity = 0 (limit <= in_flight) in __consume_rate_limit_capacity
380
- // Use amount that survives dust removal (conversion_rate = 10)
381
- let small_amount = 100i128;
382
- setup.fund_tokens(&sender, small_amount);
383
- setup.fund_native_fees(&sender, setup.native_fee);
384
-
385
- // quote_oft will report the limit in OFTLimit but won't enforce
386
- let send_param_2 = setup.create_send_param(dst_eid, small_amount, small_amount);
387
- let oft_receipt_2 = setup.quote_oft(&send_param_2);
388
-
389
- // send will fail because capacity is 0
390
- let result = setup.try_send(&sender, &send_param_2, &fee, &sender, &oft_receipt_2);
391
- assert_eq!(result.err().unwrap().ok().unwrap(), RateLimitError::ExceededRateLimit.into());
392
- }
393
-
394
- #[test]
395
- fn test_capacity_recovers_over_time() {
396
- let env = Env::default();
397
- let setup = ExtensiveOFTTestSetup::new(&env);
398
-
399
- // Set fee deposit address (required by ExtensiveOFT)
400
- let fee_collector = create_recipient_address(&env);
401
- setup.set_fee_deposit_address(&fee_collector);
402
-
403
- let sender = Address::generate(&env);
404
- let dst_eid = 100u32;
405
- let peer = BytesN::from_array(&env, &[2u8; 32]);
406
- setup.set_peer(dst_eid, &peer);
407
-
408
- // Set outbound rate limit: 1_000_000 per hour (3600 seconds)
409
- let limit = 1_000_000i128;
410
- let window_seconds = 3600u64;
411
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
412
-
413
- // Use all capacity
414
- let amount_ld = limit;
415
- setup.fund_tokens(&sender, amount_ld);
416
- setup.fund_native_fees(&sender, setup.native_fee);
417
-
418
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
419
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
420
- let oft_receipt = setup.quote_oft(&send_param);
421
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
422
-
423
- // Capacity should be 0
424
- assert_eq!(setup.rate_limit_capacity(&Direction::Outbound, dst_eid), 0);
425
-
426
- // Advance time by half the window (1800 seconds)
427
- setup.advance_time(1800);
428
-
429
- // Capacity should recover to ~50%
430
- let capacity_after_half = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
431
- assert!(capacity_after_half >= 490_000 && capacity_after_half <= 510_000);
432
-
433
- // Advance time by another half (full window elapsed)
434
- setup.advance_time(1800);
435
-
436
- // Capacity should be fully recovered
437
- let capacity_after_full = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
438
- assert_eq!(capacity_after_full, limit);
439
- }
440
-
441
- #[test]
442
- fn test_send_after_capacity_recovery() {
443
- let env = Env::default();
444
- let setup = ExtensiveOFTTestSetup::new(&env);
445
-
446
- // Set fee deposit address (required by ExtensiveOFT)
447
- let fee_collector = create_recipient_address(&env);
448
- setup.set_fee_deposit_address(&fee_collector);
449
-
450
- let sender = Address::generate(&env);
451
- let dst_eid = 100u32;
452
- let peer = BytesN::from_array(&env, &[2u8; 32]);
453
- setup.set_peer(dst_eid, &peer);
454
-
455
- // Set outbound rate limit
456
- let limit = 1_000_000i128;
457
- let window_seconds = 3600u64;
458
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
459
-
460
- // Use all capacity
461
- setup.fund_tokens(&sender, limit);
462
- setup.fund_native_fees(&sender, setup.native_fee);
463
-
464
- let send_param = setup.create_send_param(dst_eid, limit, limit);
465
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
466
- let oft_receipt = setup.quote_oft(&send_param);
467
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
468
-
469
- // Advance time to fully recover
470
- setup.advance_time(window_seconds);
471
-
472
- // Should be able to send again
473
- setup.fund_tokens(&sender, limit);
474
- setup.fund_native_fees(&sender, setup.native_fee);
475
-
476
- let send_param_2 = setup.create_send_param(dst_eid, limit, limit);
477
- let oft_receipt_2 = setup.quote_oft(&send_param_2);
478
- let (msg_receipt, _) = setup.send(&sender, &send_param_2, &fee, &sender, &oft_receipt_2);
479
- assert!(msg_receipt.nonce > 0);
480
- }
481
-
482
- // ==================== Send Tests (Outbound Rate Limit) ====================
483
-
484
- #[test]
485
- fn test_send_within_rate_limit() {
486
- let env = Env::default();
487
- let setup = ExtensiveOFTTestSetup::new(&env);
488
-
489
- // Set fee deposit address (required by ExtensiveOFT)
490
- let fee_collector = create_recipient_address(&env);
491
- setup.set_fee_deposit_address(&fee_collector);
492
-
493
- let sender = Address::generate(&env);
494
- let dst_eid = 100u32;
495
- let peer = BytesN::from_array(&env, &[2u8; 32]);
496
- setup.set_peer(dst_eid, &peer);
497
-
498
- // Set outbound rate limit
499
- let limit = 1_000_000i128;
500
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
501
-
502
- let amount_ld = 500_000i128; // Within limit
503
- setup.fund_tokens(&sender, amount_ld);
504
- setup.fund_native_fees(&sender, setup.native_fee);
505
-
506
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
507
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
508
- let oft_receipt = setup.quote_oft(&send_param);
509
-
510
- // Should succeed within limit
511
- let (msg_receipt, _) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
512
- assert!(msg_receipt.nonce > 0);
513
-
514
- // Check capacity decreased
515
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
516
- assert_eq!(capacity, limit - amount_ld);
517
- }
518
-
519
- #[test]
520
- fn test_send_exactly_at_rate_limit() {
521
- let env = Env::default();
522
- let setup = ExtensiveOFTTestSetup::new(&env);
523
-
524
- // Set fee deposit address (required by ExtensiveOFT)
525
- let fee_collector = create_recipient_address(&env);
526
- setup.set_fee_deposit_address(&fee_collector);
527
-
528
- let sender = Address::generate(&env);
529
- let dst_eid = 100u32;
530
- let peer = BytesN::from_array(&env, &[2u8; 32]);
531
- setup.set_peer(dst_eid, &peer);
532
-
533
- // Set outbound rate limit
534
- let limit = 1_000_000i128;
535
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
536
-
537
- let amount_ld = limit; // Exactly at limit
538
- setup.fund_tokens(&sender, amount_ld);
539
- setup.fund_native_fees(&sender, setup.native_fee);
540
-
541
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
542
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
543
- let oft_receipt = setup.quote_oft(&send_param);
544
-
545
- // Should succeed at exactly limit
546
- let (msg_receipt, _) = setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
547
- assert!(msg_receipt.nonce > 0);
548
-
549
- // Capacity should be zero
550
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
551
- assert_eq!(capacity, 0);
552
- }
553
-
554
- #[test]
555
- fn test_send_exceeds_rate_limit() {
556
- let env = Env::default();
557
- let setup = ExtensiveOFTTestSetup::new(&env);
558
-
559
- // Set fee deposit address (required by ExtensiveOFT)
560
- let fee_collector = create_recipient_address(&env);
561
- setup.set_fee_deposit_address(&fee_collector);
562
-
563
- let sender = Address::generate(&env);
564
- let dst_eid = 100u32;
565
- let peer = BytesN::from_array(&env, &[2u8; 32]);
566
- setup.set_peer(dst_eid, &peer);
567
-
568
- // Set outbound rate limit
569
- let limit = 1_000_000i128;
570
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
571
-
572
- // Use amount that exceeds limit and use min_amount_ld = 0 to avoid slippage errors
573
- let amount_ld = limit + 10; // Exceeds limit (use +10 to account for dust)
574
- setup.fund_tokens(&sender, amount_ld);
575
- setup.fund_native_fees(&sender, setup.native_fee);
576
-
577
- // Use min_amount_ld = 0 to avoid slippage check interference
578
- let send_param = setup.create_send_param(dst_eid, amount_ld, 0);
579
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
580
-
581
- // quote_oft returns the limit but doesn't enforce - the send will fail
582
- let (oft_limit, _, _) = setup.oft.quote_oft(&send_param);
583
- assert_eq!(oft_limit.max_amount_ld, limit); // Capacity is 1_000_000
584
-
585
- let oft_receipt = setup.quote_oft(&send_param);
586
-
587
- // Should fail at send - amount exceeds rate limit
588
- let result = setup.try_send(&sender, &send_param, &fee, &sender, &oft_receipt);
589
- assert_eq!(result.err().unwrap().ok().unwrap(), RateLimitError::ExceededRateLimit.into());
590
- }
591
-
592
- #[test]
593
- fn test_send_multiple_within_limit() {
594
- let env = Env::default();
595
- let setup = ExtensiveOFTTestSetup::new(&env);
596
-
597
- // Set fee deposit address (required by ExtensiveOFT)
598
- let fee_collector = create_recipient_address(&env);
599
- setup.set_fee_deposit_address(&fee_collector);
600
-
601
- let sender = Address::generate(&env);
602
- let dst_eid = 100u32;
603
- let peer = BytesN::from_array(&env, &[2u8; 32]);
604
- setup.set_peer(dst_eid, &peer);
605
-
606
- // Set outbound rate limit
607
- let limit = 1_000_000i128;
608
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
609
-
610
- // First send
611
- let amount_1 = 300_000i128;
612
- setup.fund_tokens(&sender, amount_1);
613
- setup.fund_native_fees(&sender, setup.native_fee);
614
-
615
- let send_param_1 = setup.create_send_param(dst_eid, amount_1, amount_1);
616
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
617
- let oft_receipt_1 = setup.quote_oft(&send_param_1);
618
- setup.send(&sender, &send_param_1, &fee, &sender, &oft_receipt_1);
619
-
620
- // Second send
621
- let amount_2 = 400_000i128;
622
- setup.fund_tokens(&sender, amount_2);
623
- setup.fund_native_fees(&sender, setup.native_fee);
624
-
625
- let send_param_2 = setup.create_send_param(dst_eid, amount_2, amount_2);
626
- let oft_receipt_2 = setup.quote_oft(&send_param_2);
627
- setup.send(&sender, &send_param_2, &fee, &sender, &oft_receipt_2);
628
-
629
- // Check remaining capacity
630
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
631
- assert_eq!(capacity, limit - amount_1 - amount_2);
632
- }
633
-
634
- #[test]
635
- fn test_send_multiple_exceeds_cumulative_limit() {
636
- let env = Env::default();
637
- let setup = ExtensiveOFTTestSetup::new(&env);
638
-
639
- // Set fee deposit address (required by ExtensiveOFT)
640
- let fee_collector = create_recipient_address(&env);
641
- setup.set_fee_deposit_address(&fee_collector);
642
-
643
- let sender = Address::generate(&env);
644
- let dst_eid = 100u32;
645
- let peer = BytesN::from_array(&env, &[2u8; 32]);
646
- setup.set_peer(dst_eid, &peer);
647
-
648
- // Set outbound rate limit
649
- let limit = 1_000_000i128;
650
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
651
-
652
- // First send - uses most of the limit
653
- let amount_1 = 800_000i128;
654
- setup.fund_tokens(&sender, amount_1);
655
- setup.fund_native_fees(&sender, setup.native_fee);
656
-
657
- let send_param_1 = setup.create_send_param(dst_eid, amount_1, amount_1);
658
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
659
- let oft_receipt_1 = setup.quote_oft(&send_param_1);
660
- setup.send(&sender, &send_param_1, &fee, &sender, &oft_receipt_1);
661
-
662
- // Verify capacity was consumed
663
- let remaining_capacity = setup.rate_limit_capacity(&Direction::Outbound, dst_eid);
664
- assert_eq!(remaining_capacity, limit - amount_1); // 200_000 remaining
665
-
666
- // Second send - would exceed remaining capacity
667
- let amount_2 = 300_000i128; // Only 200_000 capacity left
668
- setup.fund_tokens(&sender, amount_2);
669
- setup.fund_native_fees(&sender, setup.native_fee);
670
-
671
- let send_param_2 = setup.create_send_param(dst_eid, amount_2, amount_2);
672
- let oft_receipt_2 = setup.quote_oft(&send_param_2);
673
-
674
- // Should fail at send - cumulative exceeds rate limit
675
- let result = setup.try_send(&sender, &send_param_2, &fee, &sender, &oft_receipt_2);
676
- let err = result.err().unwrap().ok().unwrap();
677
- assert_eq!(err, RateLimitError::ExceededRateLimit.into());
678
- }
679
-
680
- // ==================== lz_receive Tests (Inbound Rate Limit) ====================
681
-
682
- #[test]
683
- fn test_lz_receive_within_rate_limit() {
684
- let env = Env::default();
685
- let setup = ExtensiveOFTTestSetup::new(&env);
686
-
687
- let executor = Address::generate(&env);
688
- let recipient = create_recipient_address(&env);
689
- let src_eid = 100u32;
690
- let peer = BytesN::from_array(&env, &[2u8; 32]);
691
- setup.set_peer(src_eid, &peer);
692
-
693
- // Set inbound rate limit
694
- let limit = 10_000_000i128; // 10M in local decimals
695
- setup.set_rate_limit(&Direction::Inbound, src_eid, limit, 3600);
696
-
697
- let amount_sd = 500_000u64; // Within limit (will be converted to ld)
698
- let recipient_bytes32 = address_to_bytes32(&recipient);
699
- let message = encode_oft_message(&env, &recipient_bytes32, amount_sd);
700
-
701
- let guid = BytesN::from_array(&env, &[1u8; 32]);
702
- let origin = create_origin(src_eid, &peer, 1);
703
- let extra_data = Bytes::new(&env);
704
-
705
- let initial_balance = setup.token_client.balance(&recipient);
706
-
707
- // Should succeed within limit
708
- setup.lz_receive(&executor, &origin, &guid, &message, &extra_data, 0);
709
-
710
- let conversion_rate = setup.oft.decimal_conversion_rate();
711
- let expected_amount_ld = (amount_sd as i128) * conversion_rate;
712
- assert_eq!(setup.token_client.balance(&recipient), initial_balance + expected_amount_ld);
713
- }
714
-
715
- #[test]
716
- fn test_lz_receive_exceeds_rate_limit() {
717
- let env = Env::default();
718
- let setup = ExtensiveOFTTestSetup::new(&env);
719
-
720
- let executor = Address::generate(&env);
721
- let recipient = create_recipient_address(&env);
722
- let src_eid = 100u32;
723
- let peer = BytesN::from_array(&env, &[2u8; 32]);
724
- setup.set_peer(src_eid, &peer);
725
-
726
- // Set small inbound rate limit
727
- let limit = 100_000i128; // Small limit
728
- setup.set_rate_limit(&Direction::Inbound, src_eid, limit, 3600);
729
-
730
- // Try to receive more than limit
731
- // conversion_rate is 10, so 100_000 sd = 1_000_000 ld > limit of 100_000
732
- let amount_sd = 100_000u64;
733
- let recipient_bytes32 = address_to_bytes32(&recipient);
734
- let message = encode_oft_message(&env, &recipient_bytes32, amount_sd);
735
-
736
- let guid = BytesN::from_array(&env, &[1u8; 32]);
737
- let origin = create_origin(src_eid, &peer, 1);
738
- let extra_data = Bytes::new(&env);
739
-
740
- // Should fail - exceeds limit
741
- let result = setup.try_lz_receive(&executor, &origin, &guid, &message, &extra_data, 0);
742
- assert!(result.is_err());
743
- let err = result.err().unwrap().ok().unwrap();
744
- assert_eq!(err, RateLimitError::ExceededRateLimit.into());
745
- }
746
-
747
- // ==================== Capacity Release Tests (Bidirectional) ====================
748
-
749
- #[test]
750
- fn test_inbound_release_outbound_capacity() {
751
- let env = Env::default();
752
- let setup = ExtensiveOFTTestSetup::new(&env);
753
-
754
- // Set fee deposit address (required by ExtensiveOFT)
755
- let fee_collector = create_recipient_address(&env);
756
- setup.set_fee_deposit_address(&fee_collector);
757
-
758
- let sender = Address::generate(&env);
759
- let recipient = create_recipient_address(&env);
760
- let eid = 100u32;
761
- let peer = BytesN::from_array(&env, &[2u8; 32]);
762
- setup.set_peer(eid, &peer);
763
-
764
- // Set outbound rate limit
765
- let limit = 1_000_000i128;
766
- setup.set_rate_limit(&Direction::Outbound, eid, limit, 3600);
767
-
768
- // Use half the outbound capacity
769
- let outbound_amount = 500_000i128;
770
- setup.fund_tokens(&sender, outbound_amount);
771
- setup.fund_native_fees(&sender, setup.native_fee);
772
-
773
- let send_param = setup.create_send_param(eid, outbound_amount, outbound_amount);
774
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
775
- let oft_receipt = setup.quote_oft(&send_param);
776
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
777
-
778
- // Outbound in-flight should be 500_000
779
- let in_flight_before = setup.rate_limit_in_flight(&Direction::Outbound, eid);
780
- assert_eq!(in_flight_before, outbound_amount);
781
-
782
- // Now receive tokens (which releases outbound capacity)
783
- let executor = Address::generate(&env);
784
- let amount_sd = 30_000u64; // 300_000 in ld (conversion rate is 10)
785
- let recipient_bytes32 = address_to_bytes32(&recipient);
786
- let message = encode_oft_message(&env, &recipient_bytes32, amount_sd);
787
-
788
- let guid = BytesN::from_array(&env, &[1u8; 32]);
789
- let origin = create_origin(eid, &peer, 1);
790
- let extra_data = Bytes::new(&env);
791
-
792
- setup.lz_receive(&executor, &origin, &guid, &message, &extra_data, 0);
793
-
794
- // Outbound in-flight should be reduced by inbound amount
795
- let conversion_rate = setup.oft.decimal_conversion_rate();
796
- let inbound_amount_ld = (amount_sd as i128) * conversion_rate;
797
- let in_flight_after = setup.rate_limit_in_flight(&Direction::Outbound, eid);
798
- assert_eq!(in_flight_after, outbound_amount - inbound_amount_ld);
799
- }
800
-
801
- #[test]
802
- fn test_release_rate_limit_more_than_in_flight_resets_to_zero() {
803
- let env = Env::default();
804
- let setup = ExtensiveOFTTestSetup::new(&env);
805
-
806
- // Set fee deposit address (required by ExtensiveOFT)
807
- let fee_collector = create_recipient_address(&env);
808
- setup.set_fee_deposit_address(&fee_collector);
809
-
810
- let sender = Address::generate(&env);
811
- let recipient = create_recipient_address(&env);
812
- let eid = 100u32;
813
- let peer = BytesN::from_array(&env, &[2u8; 32]);
814
- setup.set_peer(eid, &peer);
815
-
816
- // Set outbound rate limit
817
- let limit = 1_000_000i128;
818
- setup.set_rate_limit(&Direction::Outbound, eid, limit, 3600);
819
-
820
- // Use small amount of outbound capacity
821
- let outbound_amount = 100_000i128;
822
- setup.fund_tokens(&sender, outbound_amount);
823
- setup.fund_native_fees(&sender, setup.native_fee);
824
-
825
- let send_param = setup.create_send_param(eid, outbound_amount, outbound_amount);
826
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
827
- let oft_receipt = setup.quote_oft(&send_param);
828
- setup.send(&sender, &send_param, &fee, &sender, &oft_receipt);
829
-
830
- // Outbound in-flight should be 100_000
831
- let in_flight_before = setup.rate_limit_in_flight(&Direction::Outbound, eid);
832
- assert_eq!(in_flight_before, outbound_amount);
833
-
834
- // Receive MORE tokens than were sent (releases more than in-flight)
835
- let executor = Address::generate(&env);
836
- let amount_sd = 50_000u64; // 500_000 in ld (more than 100_000 in flight)
837
- let recipient_bytes32 = address_to_bytes32(&recipient);
838
- let message = encode_oft_message(&env, &recipient_bytes32, amount_sd);
839
-
840
- let guid = BytesN::from_array(&env, &[1u8; 32]);
841
- let origin = create_origin(eid, &peer, 1);
842
- let extra_data = Bytes::new(&env);
843
-
844
- setup.lz_receive(&executor, &origin, &guid, &message, &extra_data, 0);
845
-
846
- // Outbound in-flight should reset to 0 (not go negative)
847
- let in_flight_after = setup.rate_limit_in_flight(&Direction::Outbound, eid);
848
- assert_eq!(in_flight_after, 0);
849
-
850
- // Capacity should be back to full limit
851
- let capacity = setup.rate_limit_capacity(&Direction::Outbound, eid);
852
- assert_eq!(capacity, limit);
853
- }
854
-
855
- // ==================== quote_oft Tests (Rate Limit in OFTLimit) ====================
856
-
857
- #[test]
858
- fn test_quote_oft_returns_rate_limit_capacity() {
859
- let env = Env::default();
860
- let setup = ExtensiveOFTTestSetup::new(&env);
861
-
862
- // Set fee deposit address (required by ExtensiveOFT)
863
- let fee_collector = create_recipient_address(&env);
864
- setup.set_fee_deposit_address(&fee_collector);
865
-
866
- let dst_eid = 100u32;
867
- let peer = BytesN::from_array(&env, &[2u8; 32]);
868
- setup.set_peer(dst_eid, &peer);
869
-
870
- // Set outbound rate limit
871
- let limit = 1_000_000i128;
872
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, 3600);
873
-
874
- let amount_ld = 500_000i128;
875
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
876
-
877
- let (oft_limit, _, _) = setup.oft.quote_oft(&send_param);
878
-
879
- // max_amount_ld should reflect rate limit capacity
880
- assert_eq!(oft_limit.max_amount_ld, limit);
881
- }
882
-
883
- #[test]
884
- fn test_quote_oft_no_rate_limit_returns_max() {
885
- let env = Env::default();
886
- let setup = ExtensiveOFTTestSetup::new(&env);
887
-
888
- // Set fee deposit address (required by ExtensiveOFT)
889
- let fee_collector = create_recipient_address(&env);
890
- setup.set_fee_deposit_address(&fee_collector);
891
-
892
- let dst_eid = 100u32;
893
- let peer = BytesN::from_array(&env, &[2u8; 32]);
894
- setup.set_peer(dst_eid, &peer);
895
-
896
- // No rate limit set
897
-
898
- let amount_ld = 500_000i128;
899
- let send_param = setup.create_send_param(dst_eid, amount_ld, amount_ld);
900
-
901
- let (oft_limit, _, _) = setup.oft.quote_oft(&send_param);
902
-
903
- // max_amount_ld should be i128::MAX when no rate limit
904
- assert_eq!(oft_limit.max_amount_ld, i128::MAX);
905
- }
906
-
907
- // ==================== Different Destinations Tests ====================
908
-
909
- #[test]
910
- fn test_rate_limits_independent_per_destination() {
911
- let env = Env::default();
912
- let setup = ExtensiveOFTTestSetup::new(&env);
913
-
914
- // Set fee deposit address (required by ExtensiveOFT)
915
- let fee_collector = create_recipient_address(&env);
916
- setup.set_fee_deposit_address(&fee_collector);
917
-
918
- let sender = Address::generate(&env);
919
-
920
- let dst_eid_1 = 100u32;
921
- let dst_eid_2 = 200u32;
922
- let peer = BytesN::from_array(&env, &[2u8; 32]);
923
- setup.set_peer(dst_eid_1, &peer);
924
- setup.set_peer(dst_eid_2, &peer);
925
-
926
- // Set different limits for different destinations
927
- setup.set_rate_limit(&Direction::Outbound, dst_eid_1, 1_000_000, 3600);
928
- setup.set_rate_limit(&Direction::Outbound, dst_eid_2, 2_000_000, 3600);
929
-
930
- // Use all capacity for dst_eid_1
931
- let amount_1 = 1_000_000i128;
932
- setup.fund_tokens(&sender, amount_1);
933
- setup.fund_native_fees(&sender, setup.native_fee);
934
-
935
- let send_param_1 = setup.create_send_param(dst_eid_1, amount_1, amount_1);
936
- let fee = MessagingFee { native_fee: setup.native_fee, zro_fee: 0 };
937
- let oft_receipt_1 = setup.quote_oft(&send_param_1);
938
- setup.send(&sender, &send_param_1, &fee, &sender, &oft_receipt_1);
939
-
940
- // dst_eid_1 should have no capacity
941
- assert_eq!(setup.rate_limit_capacity(&Direction::Outbound, dst_eid_1), 0);
942
-
943
- // dst_eid_2 should still have full capacity
944
- assert_eq!(setup.rate_limit_capacity(&Direction::Outbound, dst_eid_2), 2_000_000);
945
-
946
- // Should be able to send to dst_eid_2
947
- let amount_2 = 1_500_000i128;
948
- setup.fund_tokens(&sender, amount_2);
949
- setup.fund_native_fees(&sender, setup.native_fee);
950
-
951
- let send_param_2 = setup.create_send_param(dst_eid_2, amount_2, amount_2);
952
- let oft_receipt_2 = setup.quote_oft(&send_param_2);
953
- let (msg_receipt, _) = setup.send(&sender, &send_param_2, &fee, &sender, &oft_receipt_2);
954
- assert!(msg_receipt.nonce > 0);
955
- }
956
-
957
- // ==================== Authentication Tests ====================
958
-
959
- #[test]
960
- fn test_set_rate_limit_requires_owner_auth() {
961
- let env = Env::default();
962
- let setup = ExtensiveOFTTestSetup::new(&env);
963
-
964
- let dst_eid = 100u32;
965
- let limit = 1_000_000i128;
966
- let window_seconds = 3600u64;
967
-
968
- // Try to set rate limit without auth
969
- let result = setup.oft.try_set_rate_limit(&Direction::Outbound, &dst_eid, &limit, &window_seconds);
970
- assert!(result.is_err());
971
-
972
- // Rate limit should not be set
973
- let (stored_limit, stored_window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
974
- assert_eq!(stored_limit, 0);
975
- assert_eq!(stored_window, 0);
976
- }
977
-
978
- #[test]
979
- fn test_set_rate_limit_wrong_auth_fails() {
980
- let env = Env::default();
981
- let setup = ExtensiveOFTTestSetup::new(&env);
982
-
983
- let non_owner = Address::generate(&env);
984
- let dst_eid = 100u32;
985
- let limit = 1_000_000i128;
986
- let window_seconds = 3600u64;
987
-
988
- // Try to set rate limit with wrong auth (non-owner)
989
- env.mock_auths(&[soroban_sdk::testutils::MockAuth {
990
- address: &non_owner,
991
- invoke: &soroban_sdk::testutils::MockAuthInvoke {
992
- contract: &setup.oft.address,
993
- fn_name: "set_rate_limit",
994
- args: (&Direction::Outbound, dst_eid, limit, window_seconds).into_val(&env),
995
- sub_invokes: &[],
996
- },
997
- }]);
998
- let result = setup.oft.try_set_rate_limit(&Direction::Outbound, &dst_eid, &limit, &window_seconds);
999
- assert!(result.is_err());
1000
-
1001
- // Rate limit should not be set
1002
- let (stored_limit, stored_window) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
1003
- assert_eq!(stored_limit, 0);
1004
- assert_eq!(stored_window, 0);
1005
- }
1006
-
1007
- #[test]
1008
- fn test_set_rate_limit_inbound_requires_owner_auth() {
1009
- let env = Env::default();
1010
- let setup = ExtensiveOFTTestSetup::new(&env);
1011
-
1012
- let src_eid = 100u32;
1013
- let limit = 1_000_000i128;
1014
- let window_seconds = 3600u64;
1015
-
1016
- // Try to set inbound rate limit without auth
1017
- let result = setup.oft.try_set_rate_limit(&Direction::Inbound, &src_eid, &limit, &window_seconds);
1018
- assert!(result.is_err());
1019
-
1020
- // Rate limit should not be set
1021
- let (stored_limit, stored_window) = setup.rate_limit_config(&Direction::Inbound, src_eid);
1022
- assert_eq!(stored_limit, 0);
1023
- assert_eq!(stored_window, 0);
1024
- }
1025
-
1026
- #[test]
1027
- fn test_unset_rate_limit_requires_owner_auth() {
1028
- let env = Env::default();
1029
- let setup = ExtensiveOFTTestSetup::new(&env);
1030
-
1031
- let dst_eid = 100u32;
1032
- let limit = 1_000_000i128;
1033
- let window_seconds = 3600u64;
1034
-
1035
- // First set rate limit as owner
1036
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
1037
- let (stored_limit, _) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
1038
- assert_eq!(stored_limit, limit);
1039
-
1040
- // Try to unset rate limit without auth
1041
- let result = setup.oft.try_unset_rate_limit(&Direction::Outbound, &dst_eid);
1042
- assert!(result.is_err());
1043
-
1044
- // Rate limit should still be set
1045
- let (stored_limit, _) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
1046
- assert_eq!(stored_limit, limit);
1047
- }
1048
-
1049
- #[test]
1050
- fn test_unset_rate_limit_wrong_auth_fails() {
1051
- let env = Env::default();
1052
- let setup = ExtensiveOFTTestSetup::new(&env);
1053
-
1054
- let non_owner = Address::generate(&env);
1055
- let dst_eid = 100u32;
1056
- let limit = 1_000_000i128;
1057
- let window_seconds = 3600u64;
1058
-
1059
- // First set rate limit as owner
1060
- setup.set_rate_limit(&Direction::Outbound, dst_eid, limit, window_seconds);
1061
-
1062
- // Try to unset rate limit with wrong auth (non-owner)
1063
- env.mock_auths(&[soroban_sdk::testutils::MockAuth {
1064
- address: &non_owner,
1065
- invoke: &soroban_sdk::testutils::MockAuthInvoke {
1066
- contract: &setup.oft.address,
1067
- fn_name: "unset_rate_limit",
1068
- args: (&Direction::Outbound, dst_eid).into_val(&env),
1069
- sub_invokes: &[],
1070
- },
1071
- }]);
1072
- let result = setup.oft.try_unset_rate_limit(&Direction::Outbound, &dst_eid);
1073
- assert!(result.is_err());
1074
-
1075
- // Rate limit should still be set
1076
- let (stored_limit, _) = setup.rate_limit_config(&Direction::Outbound, dst_eid);
1077
- assert_eq!(stored_limit, limit);
1078
- }