@layerzerolabs/protocol-stellar-v2 0.2.8

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 (265) hide show
  1. package/.turbo/turbo-build.log +727 -0
  2. package/.turbo/turbo-lint.log +158 -0
  3. package/.turbo/turbo-test.log +796 -0
  4. package/Cargo.lock +2237 -0
  5. package/Cargo.toml +63 -0
  6. package/clippy.toml +7 -0
  7. package/contracts/common-macros/Cargo.toml +20 -0
  8. package/contracts/common-macros/src/error.rs +53 -0
  9. package/contracts/common-macros/src/event.rs +16 -0
  10. package/contracts/common-macros/src/lib.rs +255 -0
  11. package/contracts/common-macros/src/ownable.rs +63 -0
  12. package/contracts/common-macros/src/snapshots/common_macros__tests__tests__snapshot_generated_storage_code.snap +310 -0
  13. package/contracts/common-macros/src/storage.rs +439 -0
  14. package/contracts/common-macros/src/tests.rs +287 -0
  15. package/contracts/common-macros/src/ttl_configurable.rs +60 -0
  16. package/contracts/endpoint-v2/ARCHITECTURE.md +233 -0
  17. package/contracts/endpoint-v2/Cargo.toml +30 -0
  18. package/contracts/endpoint-v2/src/constants.rs +52 -0
  19. package/contracts/endpoint-v2/src/endpoint_v2.rs +305 -0
  20. package/contracts/endpoint-v2/src/errors.rs +29 -0
  21. package/contracts/endpoint-v2/src/events.rs +207 -0
  22. package/contracts/endpoint-v2/src/interfaces/layerzero_composer.rs +26 -0
  23. package/contracts/endpoint-v2/src/interfaces/layerzero_endpoint_v2.rs +170 -0
  24. package/contracts/endpoint-v2/src/interfaces/layerzero_receiver.rs +43 -0
  25. package/contracts/endpoint-v2/src/interfaces/message_lib.rs +62 -0
  26. package/contracts/endpoint-v2/src/interfaces/message_lib_manager.rs +220 -0
  27. package/contracts/endpoint-v2/src/interfaces/messaging_channel.rs +121 -0
  28. package/contracts/endpoint-v2/src/interfaces/messaging_composer.rs +63 -0
  29. package/contracts/endpoint-v2/src/interfaces/mod.rs +17 -0
  30. package/contracts/endpoint-v2/src/interfaces/send_lib.rs +70 -0
  31. package/contracts/endpoint-v2/src/lib.rs +22 -0
  32. package/contracts/endpoint-v2/src/message_lib_manager.rs +315 -0
  33. package/contracts/endpoint-v2/src/messaging_channel.rs +218 -0
  34. package/contracts/endpoint-v2/src/messaging_composer.rs +76 -0
  35. package/contracts/endpoint-v2/src/storage.rs +78 -0
  36. package/contracts/endpoint-v2/src/tests/endpoint_setup.rs +131 -0
  37. package/contracts/endpoint-v2/src/tests/endpoint_v2/clear.rs +237 -0
  38. package/contracts/endpoint-v2/src/tests/endpoint_v2/delegate.rs +42 -0
  39. package/contracts/endpoint-v2/src/tests/endpoint_v2/initializable.rs +76 -0
  40. package/contracts/endpoint-v2/src/tests/endpoint_v2/lz_receive_alert.rs +211 -0
  41. package/contracts/endpoint-v2/src/tests/endpoint_v2/mod.rs +18 -0
  42. package/contracts/endpoint-v2/src/tests/endpoint_v2/native_token.rs +10 -0
  43. package/contracts/endpoint-v2/src/tests/endpoint_v2/owner.rs +10 -0
  44. package/contracts/endpoint-v2/src/tests/endpoint_v2/pay_messaging_fees.rs +424 -0
  45. package/contracts/endpoint-v2/src/tests/endpoint_v2/quote.rs +144 -0
  46. package/contracts/endpoint-v2/src/tests/endpoint_v2/recover_token.rs +72 -0
  47. package/contracts/endpoint-v2/src/tests/endpoint_v2/require_oapp_auth.rs +29 -0
  48. package/contracts/endpoint-v2/src/tests/endpoint_v2/send.rs +513 -0
  49. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_delegate.rs +43 -0
  50. package/contracts/endpoint-v2/src/tests/endpoint_v2/set_zro.rs +27 -0
  51. package/contracts/endpoint-v2/src/tests/endpoint_v2/transfer_ownership.rs +30 -0
  52. package/contracts/endpoint-v2/src/tests/endpoint_v2/ttl_config.rs +202 -0
  53. package/contracts/endpoint-v2/src/tests/endpoint_v2/verifiable.rs +59 -0
  54. package/contracts/endpoint-v2/src/tests/endpoint_v2/verify.rs +172 -0
  55. package/contracts/endpoint-v2/src/tests/endpoint_v2/zro.rs +23 -0
  56. package/contracts/endpoint-v2/src/tests/message_lib_manager/mod.rs +10 -0
  57. package/contracts/endpoint-v2/src/tests/message_lib_manager/register_library.rs +131 -0
  58. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_registered.rs +35 -0
  59. package/contracts/endpoint-v2/src/tests/message_lib_manager/require_supported_eid.rs +28 -0
  60. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_config.rs +79 -0
  61. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_lib_timeout.rs +246 -0
  62. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_receive_library.rs +285 -0
  63. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_default_send_library.rs +180 -0
  64. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library.rs +405 -0
  65. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_receive_library_timeout.rs +80 -0
  66. package/contracts/endpoint-v2/src/tests/message_lib_manager/set_send_library.rs +131 -0
  67. package/contracts/endpoint-v2/src/tests/messaging_channel/burn.rs +358 -0
  68. package/contracts/endpoint-v2/src/tests/messaging_channel/clear.rs +316 -0
  69. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_nonce.rs +288 -0
  70. package/contracts/endpoint-v2/src/tests/messaging_channel/inbound_payload_hash.rs +316 -0
  71. package/contracts/endpoint-v2/src/tests/messaging_channel/internal.rs +388 -0
  72. package/contracts/endpoint-v2/src/tests/messaging_channel/lazy_inbound_nonce.rs +307 -0
  73. package/contracts/endpoint-v2/src/tests/messaging_channel/mod.rs +10 -0
  74. package/contracts/endpoint-v2/src/tests/messaging_channel/next_guid.rs +239 -0
  75. package/contracts/endpoint-v2/src/tests/messaging_channel/nilify.rs +324 -0
  76. package/contracts/endpoint-v2/src/tests/messaging_channel/outbound_nonce.rs +242 -0
  77. package/contracts/endpoint-v2/src/tests/messaging_channel/skip.rs +232 -0
  78. package/contracts/endpoint-v2/src/tests/messaging_composer/clear_compose.rs +212 -0
  79. package/contracts/endpoint-v2/src/tests/messaging_composer/compose_queue.rs +213 -0
  80. package/contracts/endpoint-v2/src/tests/messaging_composer/lz_compose_alert.rs +269 -0
  81. package/contracts/endpoint-v2/src/tests/messaging_composer/mod.rs +4 -0
  82. package/contracts/endpoint-v2/src/tests/messaging_composer/send_compose.rs +173 -0
  83. package/contracts/endpoint-v2/src/tests/mock.rs +132 -0
  84. package/contracts/endpoint-v2/src/tests/mod.rs +12 -0
  85. package/contracts/endpoint-v2/src/tests/util/build_payload.rs +126 -0
  86. package/contracts/endpoint-v2/src/tests/util/compute_guid.rs +82 -0
  87. package/contracts/endpoint-v2/src/tests/util/keccak256.rs +115 -0
  88. package/contracts/endpoint-v2/src/tests/util/mod.rs +3 -0
  89. package/contracts/endpoint-v2/src/util.rs +52 -0
  90. package/contracts/message-libs/Cargo.toml +12 -0
  91. package/contracts/message-libs/block-message-lib/Cargo.toml +19 -0
  92. package/contracts/message-libs/block-message-lib/src/lib.rs +70 -0
  93. package/contracts/message-libs/lib.rs +2 -0
  94. package/contracts/message-libs/message-lib-common/Cargo.toml +24 -0
  95. package/contracts/message-libs/message-lib-common/src/errors.rs +20 -0
  96. package/contracts/message-libs/message-lib-common/src/interfaces/dvn.rs +55 -0
  97. package/contracts/message-libs/message-lib-common/src/interfaces/executor.rs +46 -0
  98. package/contracts/message-libs/message-lib-common/src/interfaces/mod.rs +7 -0
  99. package/contracts/message-libs/message-lib-common/src/interfaces/treasury.rs +17 -0
  100. package/contracts/message-libs/message-lib-common/src/lib.rs +14 -0
  101. package/contracts/message-libs/message-lib-common/src/packet_codec_v1.rs +99 -0
  102. package/contracts/message-libs/message-lib-common/src/testing_utils.rs +27 -0
  103. package/contracts/message-libs/message-lib-common/src/tests/mod.rs +2 -0
  104. package/contracts/message-libs/message-lib-common/src/tests/packet_codec_v1.rs +162 -0
  105. package/contracts/message-libs/message-lib-common/src/tests/worker_options.rs +319 -0
  106. package/contracts/message-libs/message-lib-common/src/worker_options.rs +190 -0
  107. package/contracts/message-libs/simple-message-lib/Cargo.toml +26 -0
  108. package/contracts/message-libs/simple-message-lib/src/errors.rs +11 -0
  109. package/contracts/message-libs/simple-message-lib/src/lib.rs +14 -0
  110. package/contracts/message-libs/simple-message-lib/src/simple_message_lib.rs +136 -0
  111. package/contracts/message-libs/simple-message-lib/src/storage.rs +27 -0
  112. package/contracts/message-libs/simple-message-lib/src/test.rs +280 -0
  113. package/contracts/message-libs/treasury/Cargo.toml +27 -0
  114. package/contracts/message-libs/treasury/src/errors.rs +10 -0
  115. package/contracts/message-libs/treasury/src/events.rs +28 -0
  116. package/contracts/message-libs/treasury/src/interfaces/mod.rs +3 -0
  117. package/contracts/message-libs/treasury/src/interfaces/zro_fee_lib.rs +20 -0
  118. package/contracts/message-libs/treasury/src/lib.rs +20 -0
  119. package/contracts/message-libs/treasury/src/storage.rs +18 -0
  120. package/contracts/message-libs/treasury/src/tests/mod.rs +2 -0
  121. package/contracts/message-libs/treasury/src/tests/setup.rs +112 -0
  122. package/contracts/message-libs/treasury/src/tests/treasury_tests.rs +562 -0
  123. package/contracts/message-libs/treasury/src/treasury.rs +140 -0
  124. package/contracts/message-libs/uln-302/Cargo.toml +28 -0
  125. package/contracts/message-libs/uln-302/src/config_validation.rs +173 -0
  126. package/contracts/message-libs/uln-302/src/errors.rs +29 -0
  127. package/contracts/message-libs/uln-302/src/events.rs +72 -0
  128. package/contracts/message-libs/uln-302/src/interfaces/mod.rs +5 -0
  129. package/contracts/message-libs/uln-302/src/interfaces/receive.rs +82 -0
  130. package/contracts/message-libs/uln-302/src/interfaces/send.rs +159 -0
  131. package/contracts/message-libs/uln-302/src/lib.rs +20 -0
  132. package/contracts/message-libs/uln-302/src/receive.rs +199 -0
  133. package/contracts/message-libs/uln-302/src/send.rs +349 -0
  134. package/contracts/message-libs/uln-302/src/storage.rs +47 -0
  135. package/contracts/message-libs/uln-302/src/tests/config/mod.rs +2 -0
  136. package/contracts/message-libs/uln-302/src/tests/config/oapp_uln_config.rs +291 -0
  137. package/contracts/message-libs/uln-302/src/tests/config/uln_config.rs +163 -0
  138. package/contracts/message-libs/uln-302/src/tests/mod.rs +7 -0
  139. package/contracts/message-libs/uln-302/src/tests/receive_uln302/commit_verification.rs +183 -0
  140. package/contracts/message-libs/uln-302/src/tests/receive_uln302/confirmations.rs +128 -0
  141. package/contracts/message-libs/uln-302/src/tests/receive_uln302/effective_receive_uln_config.rs +104 -0
  142. package/contracts/message-libs/uln-302/src/tests/receive_uln302/mod.rs +66 -0
  143. package/contracts/message-libs/uln-302/src/tests/receive_uln302/set_default_receive_uln_configs.rs +79 -0
  144. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verifiable.rs +463 -0
  145. package/contracts/message-libs/uln-302/src/tests/receive_uln302/verify.rs +173 -0
  146. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_executor_config.rs +132 -0
  147. package/contracts/message-libs/uln-302/src/tests/send_uln302/effective_send_uln_config.rs +117 -0
  148. package/contracts/message-libs/uln-302/src/tests/send_uln302/mod.rs +6 -0
  149. package/contracts/message-libs/uln-302/src/tests/send_uln302/quote.rs +586 -0
  150. package/contracts/message-libs/uln-302/src/tests/send_uln302/send.rs +834 -0
  151. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_executor_configs.rs +95 -0
  152. package/contracts/message-libs/uln-302/src/tests/send_uln302/set_default_send_uln_configs.rs +80 -0
  153. package/contracts/message-libs/uln-302/src/tests/setup.rs +268 -0
  154. package/contracts/message-libs/uln-302/src/tests/testing_utils.rs +47 -0
  155. package/contracts/message-libs/uln-302/src/tests/uln302/get_app_receive_uln_config.rs +51 -0
  156. package/contracts/message-libs/uln-302/src/tests/uln302/get_app_send_uln_config.rs +51 -0
  157. package/contracts/message-libs/uln-302/src/tests/uln302/get_oapp_executor_config.rs +48 -0
  158. package/contracts/message-libs/uln-302/src/tests/uln302/mod.rs +4 -0
  159. package/contracts/message-libs/uln-302/src/tests/uln302/set_config.rs +998 -0
  160. package/contracts/message-libs/uln-302/src/uln302.rs +117 -0
  161. package/contracts/oapp-macros/Cargo.toml +21 -0
  162. package/contracts/oapp-macros/src/lib.rs +408 -0
  163. package/contracts/oapp-macros/src/oapp_core.rs +49 -0
  164. package/contracts/oapp-macros/src/oapp_full.rs +15 -0
  165. package/contracts/oapp-macros/src/oapp_options_type3.rs +46 -0
  166. package/contracts/oapp-macros/src/oapp_receiver.rs +67 -0
  167. package/contracts/oapp-macros/src/oapp_sender.rs +23 -0
  168. package/contracts/oapp-macros/src/util.rs +103 -0
  169. package/contracts/oapp-macros/tests/test_macros.rs +522 -0
  170. package/contracts/oapps/Cargo.toml +12 -0
  171. package/contracts/oapps/counter/Cargo.toml +24 -0
  172. package/contracts/oapps/counter/integration_tests/mod.rs +3 -0
  173. package/contracts/oapps/counter/integration_tests/setup.rs +201 -0
  174. package/contracts/oapps/counter/integration_tests/test_with_sml.rs +166 -0
  175. package/contracts/oapps/counter/integration_tests/utils.rs +144 -0
  176. package/contracts/oapps/counter/src/codec.rs +63 -0
  177. package/contracts/oapps/counter/src/counter.rs +235 -0
  178. package/contracts/oapps/counter/src/errors.rs +9 -0
  179. package/contracts/oapps/counter/src/lib.rs +16 -0
  180. package/contracts/oapps/counter/src/options.rs +30 -0
  181. package/contracts/oapps/counter/src/storage.rs +33 -0
  182. package/contracts/oapps/counter/src/tests/mod.rs +37 -0
  183. package/contracts/oapps/counter/src/tests/test_codec.rs +64 -0
  184. package/contracts/oapps/counter/src/tests/test_counter.rs +390 -0
  185. package/contracts/oapps/counter/src/u256_ext.rs +21 -0
  186. package/contracts/oapps/lib.rs +2 -0
  187. package/contracts/oapps/oapp/Cargo.toml +21 -0
  188. package/contracts/oapps/oapp/src/errors.rs +9 -0
  189. package/contracts/oapps/oapp/src/lib.rs +10 -0
  190. package/contracts/oapps/oapp/src/oapp_core.rs +92 -0
  191. package/contracts/oapps/oapp/src/oapp_options_type3.rs +89 -0
  192. package/contracts/oapps/oapp/src/oapp_receiver.rs +72 -0
  193. package/contracts/oapps/oapp/src/oapp_sender.rs +66 -0
  194. package/contracts/oapps/oapp/src/tests/mod.rs +4 -0
  195. package/contracts/oapps/oapp/src/tests/test_oapp_core.rs +162 -0
  196. package/contracts/oapps/oapp/src/tests/test_oapp_options_type3.rs +180 -0
  197. package/contracts/oapps/oapp/src/tests/test_oapp_receiver.rs +157 -0
  198. package/contracts/oapps/oapp/src/tests/test_oapp_sender.rs +283 -0
  199. package/contracts/utils/Cargo.toml +21 -0
  200. package/contracts/utils/src/buffer_reader.rs +143 -0
  201. package/contracts/utils/src/buffer_writer.rs +117 -0
  202. package/contracts/utils/src/bytes_ext.rs +19 -0
  203. package/contracts/utils/src/errors.rs +30 -0
  204. package/contracts/utils/src/lib.rs +15 -0
  205. package/contracts/utils/src/option_ext.rs +38 -0
  206. package/contracts/utils/src/ownable.rs +88 -0
  207. package/contracts/utils/src/testing_utils.rs +100 -0
  208. package/contracts/utils/src/tests/buffer_reader.rs +1006 -0
  209. package/contracts/utils/src/tests/buffer_writer.rs +330 -0
  210. package/contracts/utils/src/tests/bytes_ext.rs +77 -0
  211. package/contracts/utils/src/tests/mod.rs +4 -0
  212. package/contracts/utils/src/tests/ownable.rs +149 -0
  213. package/contracts/utils/src/ttl.rs +164 -0
  214. package/contracts/workers/Cargo.toml +13 -0
  215. package/contracts/workers/executor/Cargo.toml +26 -0
  216. package/contracts/workers/executor/src/events.rs +22 -0
  217. package/contracts/workers/executor/src/executor.rs +347 -0
  218. package/contracts/workers/executor/src/interfaces/executor.rs +40 -0
  219. package/contracts/workers/executor/src/interfaces/mod.rs +5 -0
  220. package/contracts/workers/executor/src/interfaces/types.rs +51 -0
  221. package/contracts/workers/executor/src/lib.rs +10 -0
  222. package/contracts/workers/executor/src/storage.rs +23 -0
  223. package/contracts/workers/lib.rs +2 -0
  224. package/contracts/workers/worker-common/Cargo.toml +18 -0
  225. package/contracts/workers/worker-common/src/constants.rs +17 -0
  226. package/contracts/workers/worker-common/src/errors.rs +6 -0
  227. package/contracts/workers/worker-common/src/events.rs +34 -0
  228. package/contracts/workers/worker-common/src/interfaces/executor_fee_lib.rs +35 -0
  229. package/contracts/workers/worker-common/src/interfaces/mod.rs +7 -0
  230. package/contracts/workers/worker-common/src/interfaces/price_feed.rs +40 -0
  231. package/contracts/workers/worker-common/src/interfaces/worker.rs +60 -0
  232. package/contracts/workers/worker-common/src/lib.rs +19 -0
  233. package/contracts/workers/worker-common/src/storage.rs +32 -0
  234. package/contracts/workers/worker-common/src/worker_common.rs +166 -0
  235. package/package.json +25 -0
  236. package/rust-toolchain.toml +4 -0
  237. package/rustfmt.toml +17 -0
  238. package/sdk/.turbo/turbo-build.log +4 -0
  239. package/sdk/dist/generated/bml.d.ts +452 -0
  240. package/sdk/dist/generated/bml.js +72 -0
  241. package/sdk/dist/generated/counter.d.ts +824 -0
  242. package/sdk/dist/generated/counter.js +125 -0
  243. package/sdk/dist/generated/endpoint.d.ts +1676 -0
  244. package/sdk/dist/generated/endpoint.js +216 -0
  245. package/sdk/dist/generated/sml.d.ts +810 -0
  246. package/sdk/dist/generated/sml.js +132 -0
  247. package/sdk/dist/generated/uln302.d.ts +1227 -0
  248. package/sdk/dist/generated/uln302.js +185 -0
  249. package/sdk/dist/index.d.ts +5 -0
  250. package/sdk/dist/index.js +5 -0
  251. package/sdk/node_modules/.bin/tsc +21 -0
  252. package/sdk/node_modules/.bin/tsserver +21 -0
  253. package/sdk/node_modules/.bin/vitest +21 -0
  254. package/sdk/node_modules/.bin/zx +21 -0
  255. package/sdk/package.json +40 -0
  256. package/sdk/src/index.ts +5 -0
  257. package/sdk/test/index.test.ts +271 -0
  258. package/sdk/test/suites/constants.ts +13 -0
  259. package/sdk/test/suites/deploy.ts +277 -0
  260. package/sdk/test/suites/localnet.ts +42 -0
  261. package/sdk/test/suites/scan.ts +189 -0
  262. package/sdk/tsconfig.json +106 -0
  263. package/tools/ts-bindings-gen/Cargo.toml +14 -0
  264. package/tools/ts-bindings-gen/src/main.rs +147 -0
  265. package/turbo.json +12 -0
@@ -0,0 +1,562 @@
1
+ extern crate std;
2
+
3
+ use soroban_sdk::testutils::{Address as _, Events as _};
4
+
5
+ use crate::{
6
+ errors::TreasuryError,
7
+ tests::setup::{setup, BPS_DENOMINATOR},
8
+ };
9
+
10
+ // ============================================================================
11
+ // Initialization Tests
12
+ // ============================================================================
13
+
14
+ #[test]
15
+ fn test_treasury_initialization() {
16
+ let setup = setup();
17
+
18
+ // Verify initial state matches defaults
19
+ assert_eq!(setup.treasury.native_fee_bp(), 0);
20
+ assert!(!setup.treasury.fee_enabled());
21
+ assert!(setup.treasury.zro_fee_lib().is_none());
22
+ }
23
+
24
+ // ============================================================================
25
+ // Core Fee Logic Tests
26
+ // ============================================================================
27
+
28
+ #[test]
29
+ fn test_get_fee_disabled_by_default() {
30
+ let setup = setup();
31
+
32
+ let sender = soroban_sdk::Address::generate(&setup.env);
33
+ let dst_eid = 101_u32;
34
+
35
+ // When fee_enabled = false, should return 0 regardless of other settings
36
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
37
+ assert_eq!(fee, 0);
38
+ }
39
+
40
+ #[test]
41
+ fn test_get_fee_native_payment_enabled() {
42
+ let setup = setup();
43
+
44
+ let sender = soroban_sdk::Address::generate(&setup.env);
45
+ let dst_eid = 101_u32;
46
+
47
+ // Configure treasury with 5% native fee (500 BPS)
48
+ setup.configure_treasury(500);
49
+
50
+ // Test various amounts
51
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
52
+ assert_eq!(fee, 50); // 1000 * 500 / 10000 = 50
53
+
54
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &10000, &false);
55
+ assert_eq!(fee, 500); // 10000 * 500 / 10000 = 500
56
+
57
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &0, &false);
58
+ assert_eq!(fee, 0); // 0 * 500 / 10000 = 0
59
+ }
60
+
61
+ #[test]
62
+ fn test_get_fee_zro_payment_requires_fee_lib() {
63
+ let setup = setup();
64
+
65
+ let sender = soroban_sdk::Address::generate(&setup.env);
66
+ let dst_eid = 101_u32;
67
+
68
+ // Configure treasury without ZRO fee lib
69
+ setup.configure_treasury(500);
70
+
71
+ // Should fail when trying to pay in ZRO without fee lib set
72
+ let result = setup.treasury.try_get_fee(&sender, &dst_eid, &1000, &true);
73
+ assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::ZROFeeLibNotSet.into());
74
+ }
75
+
76
+ // ============================================================================
77
+ // Admin Configuration Tests
78
+ // ============================================================================
79
+
80
+ #[test]
81
+ fn test_set_fee_enabled() {
82
+ let setup = setup();
83
+
84
+ // Initially disabled
85
+ assert!(!setup.treasury.fee_enabled());
86
+
87
+ // Enable fees
88
+ setup.mock_owner_auth("set_fee_enabled", (&true,));
89
+ setup.treasury.set_fee_enabled(&true);
90
+ assert!(setup.treasury.fee_enabled());
91
+
92
+ // Disable fees again
93
+ setup.mock_owner_auth("set_fee_enabled", (&false,));
94
+ setup.treasury.set_fee_enabled(&false);
95
+ assert!(!setup.treasury.fee_enabled());
96
+ }
97
+
98
+ #[test]
99
+ fn test_set_native_fee_bp() {
100
+ let setup = setup();
101
+
102
+ // Test valid BPS values
103
+ setup.mock_owner_auth("set_native_fee_bp", (&0_u32,));
104
+ setup.treasury.set_native_fee_bp(&0);
105
+ assert_eq!(setup.treasury.native_fee_bp(), 0);
106
+
107
+ setup.mock_owner_auth("set_native_fee_bp", (&500_u32,));
108
+ setup.treasury.set_native_fee_bp(&500); // 5%
109
+ assert_eq!(setup.treasury.native_fee_bp(), 500);
110
+
111
+ setup.mock_owner_auth("set_native_fee_bp", (&10000_u32,));
112
+ setup.treasury.set_native_fee_bp(&10000); // 100%
113
+ assert_eq!(setup.treasury.native_fee_bp(), 10000);
114
+ }
115
+
116
+ #[test]
117
+ fn test_set_native_fee_bp_invalid() {
118
+ let setup = setup();
119
+
120
+ // Should fail with BPS > 10000
121
+ setup.mock_owner_auth("set_native_fee_bp", (&10001_u32,));
122
+ let result = setup.treasury.try_set_native_fee_bp(&10001);
123
+ assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::InvalidNativeFeeBp.into());
124
+ }
125
+
126
+ #[test]
127
+ fn test_set_zro_fee_lib() {
128
+ let setup = setup();
129
+
130
+ // Use contract address since it needs to pass .exists() check
131
+ let fee_lib = setup.create_contract_address();
132
+
133
+ // Initially no fee lib
134
+ assert!(setup.treasury.zro_fee_lib().is_none());
135
+
136
+ // Set fee lib
137
+ setup.mock_owner_auth("set_zro_fee_lib", (&Some(fee_lib.clone()),));
138
+ setup.treasury.set_zro_fee_lib(&Some(fee_lib.clone()));
139
+ assert_eq!(setup.treasury.zro_fee_lib(), Some(fee_lib));
140
+
141
+ // Remove fee lib
142
+ let none_val: Option<soroban_sdk::Address> = None;
143
+ setup.mock_owner_auth("set_zro_fee_lib", (&none_val,));
144
+ setup.treasury.set_zro_fee_lib(&none_val);
145
+ assert!(setup.treasury.zro_fee_lib().is_none());
146
+ }
147
+
148
+ #[test]
149
+ fn test_set_zro_fee_lib_invalid_address() {
150
+ let setup = setup();
151
+
152
+ // Generate an address that doesn't exist (won't pass .exists() check)
153
+ let non_existent_lib = soroban_sdk::Address::generate(&setup.env);
154
+
155
+ // Try to set non-existent fee lib
156
+ setup.mock_owner_auth("set_zro_fee_lib", (&Some(non_existent_lib.clone()),));
157
+ let result = setup.treasury.try_set_zro_fee_lib(&Some(non_existent_lib));
158
+ assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::InvalidZROFeeLib.into());
159
+ }
160
+
161
+ // ============================================================================
162
+ // Edge Cases & Boundary Tests
163
+ // ============================================================================
164
+
165
+ #[test]
166
+ fn test_fee_calculation_edge_cases() {
167
+ let setup = setup();
168
+
169
+ let sender = soroban_sdk::Address::generate(&setup.env);
170
+ let dst_eid = 101_u32;
171
+
172
+ setup.configure_treasury(0);
173
+
174
+ // Test 0% fee (0 BPS)
175
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
176
+ assert_eq!(fee, 0);
177
+
178
+ // Test 100% fee (10000 BPS)
179
+ setup.mock_owner_auth("set_native_fee_bp", (&10000_u32,));
180
+ setup.treasury.set_native_fee_bp(&10000);
181
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &1000, &false);
182
+ assert_eq!(fee, 1000); // 1000 * 10000 / 10000 = 1000
183
+
184
+ // Test maximum total fee with minimal BPS
185
+ let max_safe_input: i128 = i128::MAX / BPS_DENOMINATOR as i128; // Avoid overflow
186
+ setup.mock_owner_auth("set_native_fee_bp", (&1_u32,));
187
+ setup.treasury.set_native_fee_bp(&1); // 0.01%
188
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &max_safe_input, &false);
189
+ assert_eq!(fee, max_safe_input / BPS_DENOMINATOR as i128);
190
+ }
191
+
192
+ #[test]
193
+ fn test_precision_and_rounding() {
194
+ let setup = setup();
195
+
196
+ let sender = soroban_sdk::Address::generate(&setup.env);
197
+ let dst_eid = 101_u32;
198
+
199
+ setup.configure_treasury(1); // 0.01%
200
+
201
+ // Test rounding behavior (integer division truncates)
202
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &9999, &false);
203
+ assert_eq!(fee, 0); // 9999 * 1 / 10000 = 0 (rounded down)
204
+
205
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &10000, &false);
206
+ assert_eq!(fee, 1); // 10000 * 1 / 10000 = 1
207
+
208
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &20000, &false);
209
+ assert_eq!(fee, 2); // 20000 * 1 / 10000 = 2
210
+ }
211
+
212
+ #[test]
213
+ fn test_get_fee_rejects_negative_total_native_fee() {
214
+ let setup = setup();
215
+
216
+ let sender = soroban_sdk::Address::generate(&setup.env);
217
+ let dst_eid = 101_u32;
218
+
219
+ setup.configure_treasury(500);
220
+
221
+ let result = setup.treasury.try_get_fee(&sender, &dst_eid, &(-1_i128), &false);
222
+ assert_eq!(result.err().unwrap().ok().unwrap(), TreasuryError::InvalidTotalNativeFee.into());
223
+ }
224
+
225
+ // ============================================================================
226
+ // Withdraw Token Tests
227
+ // ============================================================================
228
+
229
+ #[test]
230
+ fn test_withdraw_token_valid() {
231
+ let setup = setup();
232
+
233
+ // Create recipient address (must exist)
234
+ let recipient = setup.create_contract_address();
235
+
236
+ // Deploy a test token
237
+ let token = setup.deploy_test_token();
238
+
239
+ // Mint tokens to the treasury contract
240
+ let withdraw_amount = 1000_i128;
241
+ setup.mint_tokens(&token, &setup.treasury.address, withdraw_amount);
242
+
243
+ // Verify initial balance
244
+ let initial_balance = setup.get_token_balance(&token, &setup.treasury.address);
245
+ assert_eq!(initial_balance, withdraw_amount);
246
+
247
+ // Withdraw tokens as owner
248
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &withdraw_amount));
249
+ setup.treasury.withdraw_token(&token, &recipient, &withdraw_amount);
250
+
251
+ // Verify balances after withdrawal
252
+ let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
253
+ let recipient_balance = setup.get_token_balance(&token, &recipient);
254
+ assert_eq!(treasury_balance, 0);
255
+ assert_eq!(recipient_balance, withdraw_amount);
256
+ }
257
+
258
+ #[test]
259
+ fn test_withdraw_token_partial_amount() {
260
+ let setup = setup();
261
+
262
+ let recipient = setup.create_contract_address();
263
+ let token = setup.deploy_test_token();
264
+
265
+ let initial_amount = 10000_i128;
266
+ let withdraw_amount = 3000_i128;
267
+
268
+ setup.mint_tokens(&token, &setup.treasury.address, initial_amount);
269
+
270
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &withdraw_amount));
271
+ setup.treasury.withdraw_token(&token, &recipient, &withdraw_amount);
272
+
273
+ // Verify partial withdrawal
274
+ let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
275
+ let recipient_balance = setup.get_token_balance(&token, &recipient);
276
+ assert_eq!(treasury_balance, initial_amount - withdraw_amount);
277
+ assert_eq!(recipient_balance, withdraw_amount);
278
+ }
279
+
280
+ #[test]
281
+ fn test_withdraw_token_invalid_amount_zero() {
282
+ let setup = setup();
283
+
284
+ let recipient = setup.create_contract_address();
285
+ let token = setup.deploy_test_token();
286
+
287
+ setup.mint_tokens(&token, &setup.treasury.address, 1000);
288
+
289
+ // With current implementation, withdrawing 0 is allowed (token contract permits it).
290
+ let treasury_balance_before = setup.get_token_balance(&token, &setup.treasury.address);
291
+ let recipient_balance_before = setup.get_token_balance(&token, &recipient);
292
+
293
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &0_i128));
294
+ let result = setup.treasury.try_withdraw_token(&token, &recipient, &0);
295
+ assert!(result.is_ok());
296
+
297
+ let treasury_balance_after = setup.get_token_balance(&token, &setup.treasury.address);
298
+ let recipient_balance_after = setup.get_token_balance(&token, &recipient);
299
+ assert_eq!(treasury_balance_after, treasury_balance_before);
300
+ assert_eq!(recipient_balance_after, recipient_balance_before);
301
+ }
302
+
303
+ #[test]
304
+ fn test_withdraw_token_invalid_amount_negative() {
305
+ let setup = setup();
306
+
307
+ let recipient = setup.create_contract_address();
308
+ let token = setup.deploy_test_token();
309
+
310
+ setup.mint_tokens(&token, &setup.treasury.address, 1000);
311
+
312
+ // Try to withdraw negative amount
313
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &(-100_i128)));
314
+ let result = setup.treasury.try_withdraw_token(&token, &recipient, &-100);
315
+ assert!(result.is_err());
316
+ }
317
+
318
+ #[test]
319
+ fn test_withdraw_token_invalid_recipient() {
320
+ let setup = setup();
321
+
322
+ // Generate an address that doesn't exist as a contract (won't pass `.exists()`),
323
+ // but token transfers to such addresses are still allowed.
324
+ let non_existent_recipient = soroban_sdk::Address::generate(&setup.env);
325
+ let token = setup.deploy_test_token();
326
+
327
+ setup.mint_tokens(&token, &setup.treasury.address, 1000);
328
+
329
+ let treasury_balance_before = setup.get_token_balance(&token, &setup.treasury.address);
330
+ let recipient_balance_before = setup.get_token_balance(&token, &non_existent_recipient);
331
+
332
+ // Withdraw to a non-contract address (should succeed)
333
+ setup.mock_owner_auth("withdraw_token", (&token, &non_existent_recipient, &500_i128));
334
+ let result = setup.treasury.try_withdraw_token(&token, &non_existent_recipient, &500);
335
+ assert!(result.is_ok());
336
+
337
+ let treasury_balance_after = setup.get_token_balance(&token, &setup.treasury.address);
338
+ let recipient_balance_after = setup.get_token_balance(&token, &non_existent_recipient);
339
+ assert_eq!(treasury_balance_after, treasury_balance_before - 500);
340
+ assert_eq!(recipient_balance_after, recipient_balance_before + 500);
341
+ }
342
+
343
+ #[test]
344
+ fn test_withdraw_token_insufficient_balance() {
345
+ let setup = setup();
346
+
347
+ let recipient = setup.create_contract_address();
348
+ let token = setup.deploy_test_token();
349
+
350
+ let balance = 500_i128;
351
+ let withdraw_amount = 1000_i128;
352
+
353
+ setup.mint_tokens(&token, &setup.treasury.address, balance);
354
+
355
+ // Try to withdraw more than balance
356
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &withdraw_amount));
357
+ let result = setup.treasury.try_withdraw_token(&token, &recipient, &withdraw_amount);
358
+ assert!(result.is_err());
359
+ }
360
+
361
+ #[test]
362
+ #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
363
+ fn test_withdraw_token_not_owner() {
364
+ let setup = setup();
365
+
366
+ let non_owner = soroban_sdk::Address::generate(&setup.env);
367
+ let recipient = setup.create_contract_address();
368
+ let token = setup.deploy_test_token();
369
+
370
+ setup.mint_tokens(&token, &setup.treasury.address, 1000);
371
+
372
+ // Try to withdraw as non-owner
373
+ setup.mock_auth(&non_owner, "withdraw_token", (&token, &recipient, &500_i128));
374
+ setup.treasury.withdraw_token(&token, &recipient, &500);
375
+ }
376
+
377
+ #[test]
378
+ fn test_withdraw_token_entire_balance() {
379
+ let setup = setup();
380
+
381
+ let recipient = setup.create_contract_address();
382
+ let token = setup.deploy_test_token();
383
+
384
+ let total_balance = 5000_i128;
385
+ setup.mint_tokens(&token, &setup.treasury.address, total_balance);
386
+
387
+ // Withdraw entire balance
388
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &total_balance));
389
+ setup.treasury.withdraw_token(&token, &recipient, &total_balance);
390
+
391
+ // Verify complete withdrawal
392
+ let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
393
+ let recipient_balance = setup.get_token_balance(&token, &recipient);
394
+ assert_eq!(treasury_balance, 0);
395
+ assert_eq!(recipient_balance, total_balance);
396
+ }
397
+
398
+ #[test]
399
+ fn test_withdraw_token_multiple_withdrawals() {
400
+ let setup = setup();
401
+
402
+ let recipient1 = setup.create_contract_address();
403
+ let recipient2 = setup.create_contract_address();
404
+ let token = setup.deploy_test_token();
405
+
406
+ let initial_balance = 10000_i128;
407
+ let first_withdrawal = 3000_i128;
408
+ let second_withdrawal = 2000_i128;
409
+
410
+ setup.mint_tokens(&token, &setup.treasury.address, initial_balance);
411
+
412
+ // First withdrawal
413
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient1, &first_withdrawal));
414
+ setup.treasury.withdraw_token(&token, &recipient1, &first_withdrawal);
415
+
416
+ // Second withdrawal to different recipient
417
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient2, &second_withdrawal));
418
+ setup.treasury.withdraw_token(&token, &recipient2, &second_withdrawal);
419
+
420
+ // Verify all balances
421
+ let treasury_balance = setup.get_token_balance(&token, &setup.treasury.address);
422
+ let recipient1_balance = setup.get_token_balance(&token, &recipient1);
423
+ let recipient2_balance = setup.get_token_balance(&token, &recipient2);
424
+
425
+ assert_eq!(treasury_balance, initial_balance - first_withdrawal - second_withdrawal);
426
+ assert_eq!(recipient1_balance, first_withdrawal);
427
+ assert_eq!(recipient2_balance, second_withdrawal);
428
+ }
429
+
430
+ #[test]
431
+ fn test_withdraw_token_multiple_tokens() {
432
+ let setup = setup();
433
+
434
+ let recipient = setup.create_contract_address();
435
+ let token1 = setup.deploy_test_token();
436
+ let token2 = setup.deploy_test_token();
437
+
438
+ let amount1 = 1000_i128;
439
+ let amount2 = 2000_i128;
440
+
441
+ // Setup balances for two different tokens
442
+ setup.mint_tokens(&token1, &setup.treasury.address, amount1);
443
+ setup.mint_tokens(&token2, &setup.treasury.address, amount2);
444
+
445
+ // Withdraw from first token
446
+ setup.mock_owner_auth("withdraw_token", (&token1, &recipient, &amount1));
447
+ setup.treasury.withdraw_token(&token1, &recipient, &amount1);
448
+
449
+ // Withdraw from second token
450
+ setup.mock_owner_auth("withdraw_token", (&token2, &recipient, &amount2));
451
+ setup.treasury.withdraw_token(&token2, &recipient, &amount2);
452
+
453
+ // Verify balances for both tokens
454
+ assert_eq!(setup.get_token_balance(&token1, &setup.treasury.address), 0);
455
+ assert_eq!(setup.get_token_balance(&token2, &setup.treasury.address), 0);
456
+ assert_eq!(setup.get_token_balance(&token1, &recipient), amount1);
457
+ assert_eq!(setup.get_token_balance(&token2, &recipient), amount2);
458
+ }
459
+
460
+ #[test]
461
+ fn test_withdraw_token_events_emitted() {
462
+ let setup = setup();
463
+
464
+ let recipient = setup.create_contract_address();
465
+ let token = setup.deploy_test_token();
466
+ let amount = 500_i128;
467
+
468
+ setup.mint_tokens(&token, &setup.treasury.address, amount);
469
+
470
+ // Count events before withdrawal
471
+ let events_before = setup.env.events().all().len();
472
+
473
+ // Withdraw tokens and check that events are emitted
474
+ setup.mock_owner_auth("withdraw_token", (&token, &recipient, &amount));
475
+ setup.treasury.withdraw_token(&token, &recipient, &amount);
476
+
477
+ // Verify that new events were published
478
+ let events_after = setup.env.events().all().len();
479
+ assert!(events_after > events_before, "TokenWithdrawn event should be emitted");
480
+ }
481
+
482
+ // ============================================================================
483
+ // Integration Tests
484
+ // ============================================================================
485
+
486
+ #[test]
487
+ fn test_complete_workflow() {
488
+ let setup = setup();
489
+
490
+ let sender = soroban_sdk::Address::generate(&setup.env);
491
+ let dst_eid = 101_u32;
492
+
493
+ // === STEP 1: Initial Configuration ===
494
+ setup.configure_treasury(250);
495
+
496
+ // === STEP 2: Test Native Fee Calculation ===
497
+ let total_worker_fee: i128 = 10000;
498
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &total_worker_fee, &false);
499
+ assert_eq!(fee, 250); // 10000 * 250 / 10000 = 250
500
+
501
+ // === STEP 3: Test Fee Disable ===
502
+ setup.mock_owner_auth("set_fee_enabled", (&false,));
503
+ setup.treasury.set_fee_enabled(&false);
504
+ let fee = setup.treasury.get_fee(&sender, &dst_eid, &total_worker_fee, &false);
505
+ assert_eq!(fee, 0); // Should return 0 when disabled
506
+ }
507
+
508
+ // ============================================================================
509
+ // View Function Tests
510
+ // ============================================================================
511
+
512
+ #[test]
513
+ fn test_view_functions_consistency() {
514
+ let setup = setup();
515
+
516
+ let native_fee_bp: u32 = 750; // 7.5%
517
+
518
+ setup.configure_treasury(native_fee_bp);
519
+
520
+ // Verify all view functions return correct values
521
+ assert_eq!(setup.treasury.native_fee_bp(), native_fee_bp);
522
+ assert!(setup.treasury.fee_enabled());
523
+ }
524
+
525
+ // ============================================================================
526
+ // Authorization Tests
527
+ // ============================================================================
528
+
529
+ #[test]
530
+ #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
531
+ fn test_set_native_fee_bp_not_owner() {
532
+ let setup = setup();
533
+
534
+ let non_owner = soroban_sdk::Address::generate(&setup.env);
535
+
536
+ setup.mock_auth(&non_owner, "set_native_fee_bp", (&500_u32,));
537
+ setup.treasury.set_native_fee_bp(&500);
538
+ }
539
+
540
+ #[test]
541
+ #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
542
+ fn test_set_fee_enabled_not_owner() {
543
+ let setup = setup();
544
+
545
+ let non_owner = soroban_sdk::Address::generate(&setup.env);
546
+
547
+ setup.mock_auth(&non_owner, "set_fee_enabled", (&true,));
548
+ setup.treasury.set_fee_enabled(&true);
549
+ }
550
+
551
+ #[test]
552
+ #[should_panic(expected = "HostError: Error(Auth, InvalidAction)")]
553
+ fn test_set_zro_fee_lib_not_owner() {
554
+ let setup = setup();
555
+
556
+ let non_owner = soroban_sdk::Address::generate(&setup.env);
557
+ // Use contract address since it needs to pass .exists() check
558
+ let fee_lib = setup.create_contract_address();
559
+
560
+ setup.mock_auth(&non_owner, "set_zro_fee_lib", (&Some(fee_lib.clone()),));
561
+ setup.treasury.set_zro_fee_lib(&Some(fee_lib));
562
+ }
@@ -0,0 +1,140 @@
1
+ use crate::{
2
+ errors::TreasuryError,
3
+ events::{FeeEnabledSet, NativeFeeBpSet, TokenWithdrawn, ZROFeeLibSet},
4
+ interfaces::ZROFeeLibClient,
5
+ storage::TreasuryStorage,
6
+ };
7
+ use common_macros::{only_owner, ttl_configurable};
8
+ use message_lib_common::ILayerZeroTreasury;
9
+ use soroban_sdk::{assert_with_error, contract, contractimpl, token::Client, Address, Env, Executable};
10
+ use utils::option_ext::OptionExt;
11
+
12
+ /// Denominator for basis point calculations (10000 = 100%).
13
+ const BPS_DENOMINATOR: u32 = 10000;
14
+
15
+ #[contract]
16
+ #[ttl_configurable]
17
+ pub struct Treasury;
18
+
19
+ #[contractimpl]
20
+ impl Treasury {
21
+ pub fn __constructor(env: &Env, owner: &Address) {
22
+ Self::__init_owner(env, owner);
23
+ }
24
+
25
+ // ===== Admin Functions =====
26
+
27
+ /// Sets the native fee percentage in basis points.
28
+ ///
29
+ /// # Arguments
30
+ /// * `native_fee_bp` - Fee percentage in basis points (0-10000, where 10000 = 100%)
31
+ #[only_owner]
32
+ pub fn set_native_fee_bp(env: &Env, native_fee_bp: u32) {
33
+ assert_with_error!(env, native_fee_bp <= BPS_DENOMINATOR, TreasuryError::InvalidNativeFeeBp);
34
+ TreasuryStorage::set_native_fee_bp(env, &native_fee_bp);
35
+ NativeFeeBpSet { native_fee_bp }.publish(env);
36
+ }
37
+
38
+ /// Enables or disables fee collection globally.
39
+ ///
40
+ /// # Arguments
41
+ /// * `fee_enabled` - Whether fee collection is enabled
42
+ #[only_owner]
43
+ pub fn set_fee_enabled(env: &Env, fee_enabled: bool) {
44
+ TreasuryStorage::set_fee_enabled(env, &fee_enabled);
45
+ FeeEnabledSet { fee_enabled }.publish(env);
46
+ }
47
+
48
+ /// Sets or removes the ZRO fee library for custom ZRO token fee calculations.
49
+ ///
50
+ /// # Arguments
51
+ /// * `zro_fee_lib` - The ZRO fee library contract address, or `None` to remove
52
+ #[only_owner]
53
+ pub fn set_zro_fee_lib(env: &Env, zro_fee_lib: &Option<Address>) {
54
+ if let Some(ref lib) = zro_fee_lib {
55
+ assert_with_error!(
56
+ env,
57
+ matches!(lib.executable(), Some(Executable::Wasm(_))),
58
+ TreasuryError::InvalidZROFeeLib
59
+ );
60
+ TreasuryStorage::set_zro_fee_lib(env, lib);
61
+ } else {
62
+ TreasuryStorage::remove_zro_fee_lib(env);
63
+ }
64
+ ZROFeeLibSet { zro_fee_lib: zro_fee_lib.clone() }.publish(env);
65
+ }
66
+
67
+ /// Withdraws any token (including native XLM) from the contract to a specified address.
68
+ ///
69
+ /// Only the contract owner can execute this method.
70
+ ///
71
+ /// # Arguments
72
+ /// * `token` - The token contract address (can be native XLM or any other token)
73
+ /// * `to` - The recipient address
74
+ /// * `amount` - The amount to withdraw (must be positive)
75
+ #[only_owner]
76
+ pub fn withdraw_token(env: &Env, token: &Address, to: &Address, amount: i128) {
77
+ let token_client = Client::new(env, token);
78
+ token_client.transfer(&env.current_contract_address(), to, &amount);
79
+
80
+ TokenWithdrawn { token: token.clone(), to: to.clone(), amount }.publish(env);
81
+ }
82
+
83
+ // ===== View Functions =====
84
+
85
+ /// Returns the native fee percentage in basis points.
86
+ pub fn native_fee_bp(env: &Env) -> u32 {
87
+ TreasuryStorage::native_fee_bp(env).unwrap_or(0)
88
+ }
89
+
90
+ /// Returns whether fee collection is enabled.
91
+ pub fn fee_enabled(env: &Env) -> bool {
92
+ TreasuryStorage::fee_enabled(env).unwrap_or(false)
93
+ }
94
+
95
+ /// Returns the ZRO fee library address if set.
96
+ pub fn zro_fee_lib(env: &Env) -> Option<Address> {
97
+ TreasuryStorage::zro_fee_lib(env)
98
+ }
99
+
100
+ // ===== Internal Functions =====
101
+
102
+ /// Calculates the treasury fee based on the total native fee and configured basis points.
103
+ fn calculate_native_fee(env: &Env, total_native_fee: i128) -> i128 {
104
+ total_native_fee * Self::native_fee_bp(env) as i128 / BPS_DENOMINATOR as i128
105
+ }
106
+
107
+ /// Returns the ZRO fee library client, panics if not set.
108
+ fn get_zro_fee_lib_client(env: &Env) -> ZROFeeLibClient<'static> {
109
+ let fee_lib = Self::zro_fee_lib(env).unwrap_or_panic(env, TreasuryError::ZROFeeLibNotSet);
110
+ ZROFeeLibClient::new(env, &fee_lib)
111
+ }
112
+ }
113
+
114
+ // ============================================================================
115
+ // ILayerZeroTreasury Implementation
116
+ // ============================================================================
117
+
118
+ #[contractimpl]
119
+ impl ILayerZeroTreasury for Treasury {
120
+ /// Get the treasury fee for a cross-chain message.
121
+ ///
122
+ /// Returns 0 if fee collection is disabled. For ZRO payments, delegates to the ZRO fee library.
123
+ fn get_fee(env: &Env, sender: &Address, dst_eid: u32, total_native_fee: i128, pay_in_zro: bool) -> i128 {
124
+ assert_with_error!(env, total_native_fee >= 0, TreasuryError::InvalidTotalNativeFee);
125
+
126
+ if !Self::fee_enabled(env) {
127
+ return 0;
128
+ }
129
+
130
+ let native_treasury_fee = Self::calculate_native_fee(env, total_native_fee);
131
+ if pay_in_zro {
132
+ let zro_fee =
133
+ Self::get_zro_fee_lib_client(env).get_fee(sender, &dst_eid, &total_native_fee, &native_treasury_fee);
134
+ assert_with_error!(env, zro_fee >= 0, TreasuryError::InvalidZROFee);
135
+ zro_fee
136
+ } else {
137
+ native_treasury_fee
138
+ }
139
+ }
140
+ }