@layerzerolabs/protocol-starknet-v2 0.0.34

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 (504) hide show
  1. package/.turbo/turbo-build.log +186 -0
  2. package/.turbo/turbo-lint.log +71 -0
  3. package/.turbo/turbo-test.log +937 -0
  4. package/README.md +41 -0
  5. package/Scarb.lock +211 -0
  6. package/Scarb.toml +2 -0
  7. package/dist/4XD3ZRZ4.cjs +301 -0
  8. package/dist/4XD3ZRZ4.cjs.map +1 -0
  9. package/dist/4Z5IPBC3.js +299 -0
  10. package/dist/4Z5IPBC3.js.map +1 -0
  11. package/dist/5NEZDLVQ.cjs +474 -0
  12. package/dist/5NEZDLVQ.cjs.map +1 -0
  13. package/dist/6JYCOKDE.js +472 -0
  14. package/dist/6JYCOKDE.js.map +1 -0
  15. package/dist/7C4PFMIZ.cjs +1288 -0
  16. package/dist/7C4PFMIZ.cjs.map +1 -0
  17. package/dist/7ZSGGZUE.js +1229 -0
  18. package/dist/7ZSGGZUE.js.map +1 -0
  19. package/dist/ARHOGUYH.cjs +2136 -0
  20. package/dist/ARHOGUYH.cjs.map +1 -0
  21. package/dist/CRCRIUFX.js +1264 -0
  22. package/dist/CRCRIUFX.js.map +1 -0
  23. package/dist/DB7CQSED.cjs +430 -0
  24. package/dist/DB7CQSED.cjs.map +1 -0
  25. package/dist/DFXLWHYP.cjs +1266 -0
  26. package/dist/DFXLWHYP.cjs.map +1 -0
  27. package/dist/EOLZCMCK.js +988 -0
  28. package/dist/EOLZCMCK.js.map +1 -0
  29. package/dist/FFDPTOWG.cjs +331 -0
  30. package/dist/FFDPTOWG.cjs.map +1 -0
  31. package/dist/FOJGEAIO.js +2134 -0
  32. package/dist/FOJGEAIO.js.map +1 -0
  33. package/dist/IWIUMVGB.js +629 -0
  34. package/dist/IWIUMVGB.js.map +1 -0
  35. package/dist/MUEN6AWV.cjs +697 -0
  36. package/dist/MUEN6AWV.cjs.map +1 -0
  37. package/dist/ORE6VBZ4.cjs +990 -0
  38. package/dist/ORE6VBZ4.cjs.map +1 -0
  39. package/dist/OUFKWPZ7.js +732 -0
  40. package/dist/OUFKWPZ7.js.map +1 -0
  41. package/dist/T2QTYQXJ.js +1229 -0
  42. package/dist/T2QTYQXJ.js.map +1 -0
  43. package/dist/UPJTM7BR.cjs +631 -0
  44. package/dist/UPJTM7BR.cjs.map +1 -0
  45. package/dist/VNVNX2P3.cjs +1231 -0
  46. package/dist/VNVNX2P3.cjs.map +1 -0
  47. package/dist/VUOMXK5T.js +6 -0
  48. package/dist/VUOMXK5T.js.map +1 -0
  49. package/dist/WISWRTDG.js +1286 -0
  50. package/dist/WISWRTDG.js.map +1 -0
  51. package/dist/WU5L7YIQ.cjs +1231 -0
  52. package/dist/WU5L7YIQ.cjs.map +1 -0
  53. package/dist/X3B5JDMZ.js +695 -0
  54. package/dist/X3B5JDMZ.js.map +1 -0
  55. package/dist/XYNBDBBV.cjs +297 -0
  56. package/dist/XYNBDBBV.cjs.map +1 -0
  57. package/dist/Y5JFPCYJ.cjs +734 -0
  58. package/dist/Y5JFPCYJ.cjs.map +1 -0
  59. package/dist/YEHL7IYO.js +295 -0
  60. package/dist/YEHL7IYO.js.map +1 -0
  61. package/dist/YJF4D23A.cjs +8 -0
  62. package/dist/YJF4D23A.cjs.map +1 -0
  63. package/dist/YTS44OEA.js +428 -0
  64. package/dist/YTS44OEA.js.map +1 -0
  65. package/dist/Z2NIUZMW.js +329 -0
  66. package/dist/Z2NIUZMW.js.map +1 -0
  67. package/dist/abis/blocked-message-lib.cjs +13 -0
  68. package/dist/abis/blocked-message-lib.cjs.map +1 -0
  69. package/dist/abis/blocked-message-lib.d.ts +338 -0
  70. package/dist/abis/blocked-message-lib.d.ts.map +1 -0
  71. package/dist/abis/blocked-message-lib.js +4 -0
  72. package/dist/abis/blocked-message-lib.js.map +1 -0
  73. package/dist/abis/dvn-fee-lib.cjs +13 -0
  74. package/dist/abis/dvn-fee-lib.cjs.map +1 -0
  75. package/dist/abis/dvn-fee-lib.d.ts +214 -0
  76. package/dist/abis/dvn-fee-lib.d.ts.map +1 -0
  77. package/dist/abis/dvn-fee-lib.js +4 -0
  78. package/dist/abis/dvn-fee-lib.js.map +1 -0
  79. package/dist/abis/dvn.cjs +13 -0
  80. package/dist/abis/dvn.cjs.map +1 -0
  81. package/dist/abis/dvn.d.ts +952 -0
  82. package/dist/abis/dvn.d.ts.map +1 -0
  83. package/dist/abis/dvn.js +4 -0
  84. package/dist/abis/dvn.js.map +1 -0
  85. package/dist/abis/endpoint-v2.cjs +13 -0
  86. package/dist/abis/endpoint-v2.cjs.map +1 -0
  87. package/dist/abis/endpoint-v2.d.ts +1580 -0
  88. package/dist/abis/endpoint-v2.d.ts.map +1 -0
  89. package/dist/abis/endpoint-v2.js +4 -0
  90. package/dist/abis/endpoint-v2.js.map +1 -0
  91. package/dist/abis/executor-fee-lib.cjs +13 -0
  92. package/dist/abis/executor-fee-lib.cjs.map +1 -0
  93. package/dist/abis/executor-fee-lib.d.ts +217 -0
  94. package/dist/abis/executor-fee-lib.d.ts.map +1 -0
  95. package/dist/abis/executor-fee-lib.js +4 -0
  96. package/dist/abis/executor-fee-lib.js.map +1 -0
  97. package/dist/abis/executor.cjs +13 -0
  98. package/dist/abis/executor.cjs.map +1 -0
  99. package/dist/abis/executor.d.ts +914 -0
  100. package/dist/abis/executor.d.ts.map +1 -0
  101. package/dist/abis/executor.js +4 -0
  102. package/dist/abis/executor.js.map +1 -0
  103. package/dist/abis/o-app.cjs +13 -0
  104. package/dist/abis/o-app.cjs.map +1 -0
  105. package/dist/abis/o-app.d.ts +311 -0
  106. package/dist/abis/o-app.d.ts.map +1 -0
  107. package/dist/abis/o-app.js +4 -0
  108. package/dist/abis/o-app.js.map +1 -0
  109. package/dist/abis/oft-adapter.cjs +13 -0
  110. package/dist/abis/oft-adapter.cjs.map +1 -0
  111. package/dist/abis/oft-adapter.d.ts +722 -0
  112. package/dist/abis/oft-adapter.d.ts.map +1 -0
  113. package/dist/abis/oft-adapter.js +4 -0
  114. package/dist/abis/oft-adapter.js.map +1 -0
  115. package/dist/abis/oft.cjs +13 -0
  116. package/dist/abis/oft.cjs.map +1 -0
  117. package/dist/abis/oft.d.ts +922 -0
  118. package/dist/abis/oft.d.ts.map +1 -0
  119. package/dist/abis/oft.js +4 -0
  120. package/dist/abis/oft.js.map +1 -0
  121. package/dist/abis/omni-counter.cjs +13 -0
  122. package/dist/abis/omni-counter.cjs.map +1 -0
  123. package/dist/abis/omni-counter.d.ts +459 -0
  124. package/dist/abis/omni-counter.d.ts.map +1 -0
  125. package/dist/abis/omni-counter.js +4 -0
  126. package/dist/abis/omni-counter.js.map +1 -0
  127. package/dist/abis/price-feed.cjs +13 -0
  128. package/dist/abis/price-feed.cjs.map +1 -0
  129. package/dist/abis/price-feed.d.ts +505 -0
  130. package/dist/abis/price-feed.d.ts.map +1 -0
  131. package/dist/abis/price-feed.js +4 -0
  132. package/dist/abis/price-feed.js.map +1 -0
  133. package/dist/abis/simple-message-lib.cjs +13 -0
  134. package/dist/abis/simple-message-lib.cjs.map +1 -0
  135. package/dist/abis/simple-message-lib.d.ts +535 -0
  136. package/dist/abis/simple-message-lib.d.ts.map +1 -0
  137. package/dist/abis/simple-message-lib.js +4 -0
  138. package/dist/abis/simple-message-lib.js.map +1 -0
  139. package/dist/abis/treasury.cjs +13 -0
  140. package/dist/abis/treasury.cjs.map +1 -0
  141. package/dist/abis/treasury.d.ts +240 -0
  142. package/dist/abis/treasury.d.ts.map +1 -0
  143. package/dist/abis/treasury.js +4 -0
  144. package/dist/abis/treasury.js.map +1 -0
  145. package/dist/abis/ultra-light-node.cjs +13 -0
  146. package/dist/abis/ultra-light-node.cjs.map +1 -0
  147. package/dist/abis/ultra-light-node.d.ts +900 -0
  148. package/dist/abis/ultra-light-node.d.ts.map +1 -0
  149. package/dist/abis/ultra-light-node.js +4 -0
  150. package/dist/abis/ultra-light-node.js.map +1 -0
  151. package/dist/index.cjs +78 -0
  152. package/dist/index.cjs.map +1 -0
  153. package/dist/index.d.ts +15 -0
  154. package/dist/index.d.ts.map +1 -0
  155. package/dist/index.js +17 -0
  156. package/dist/index.js.map +1 -0
  157. package/dist/scripts/build-abi.cjs +28 -0
  158. package/dist/scripts/build-abi.cjs.map +1 -0
  159. package/dist/scripts/build-abi.d.ts +2 -0
  160. package/dist/scripts/build-abi.d.ts.map +1 -0
  161. package/dist/scripts/build-abi.js +26 -0
  162. package/dist/scripts/build-abi.js.map +1 -0
  163. package/layerzero/README.md +244 -0
  164. package/layerzero/Scarb.lock +203 -0
  165. package/layerzero/Scarb.toml +30 -0
  166. package/layerzero/snfoundry.toml +11 -0
  167. package/layerzero/src/common/constants.cairo +26 -0
  168. package/layerzero/src/common/conversions.cairo +16 -0
  169. package/layerzero/src/common/guid.cairo +20 -0
  170. package/layerzero/src/common/packet_v1_codec.cairo +307 -0
  171. package/layerzero/src/common/structs/messaging.cairo +40 -0
  172. package/layerzero/src/common/structs/packet.cairo +31 -0
  173. package/layerzero/src/endpoint/constants.cairo +14 -0
  174. package/layerzero/src/endpoint/endpoint.cairo +688 -0
  175. package/layerzero/src/endpoint/errors.cairo +108 -0
  176. package/layerzero/src/endpoint/events.cairo +124 -0
  177. package/layerzero/src/endpoint/interfaces/endpoint.cairo +286 -0
  178. package/layerzero/src/endpoint/interfaces/layerzero_composer.cairo +62 -0
  179. package/layerzero/src/endpoint/interfaces/layerzero_receiver.cairo +63 -0
  180. package/layerzero/src/endpoint/message_lib_manager/errors.cairo +95 -0
  181. package/layerzero/src/endpoint/message_lib_manager/events.cairo +90 -0
  182. package/layerzero/src/endpoint/message_lib_manager/interface.cairo +449 -0
  183. package/layerzero/src/endpoint/message_lib_manager/message_lib_manager.cairo +720 -0
  184. package/layerzero/src/endpoint/message_lib_manager/structs.cairo +33 -0
  185. package/layerzero/src/endpoint/messaging_channel/errors.cairo +37 -0
  186. package/layerzero/src/endpoint/messaging_channel/events.cairo +58 -0
  187. package/layerzero/src/endpoint/messaging_channel/interface.cairo +171 -0
  188. package/layerzero/src/endpoint/messaging_channel/messaging_channel.cairo +453 -0
  189. package/layerzero/src/endpoint/messaging_composer/errors.cairo +46 -0
  190. package/layerzero/src/endpoint/messaging_composer/events.cairo +67 -0
  191. package/layerzero/src/endpoint/messaging_composer/interface.cairo +132 -0
  192. package/layerzero/src/endpoint/messaging_composer/messaging_composer.cairo +223 -0
  193. package/layerzero/src/lib.cairo +189 -0
  194. package/layerzero/src/message_lib/blocked_message_lib.cairo +114 -0
  195. package/layerzero/src/message_lib/interface.cairo +63 -0
  196. package/layerzero/src/message_lib/sml/errors.cairo +23 -0
  197. package/layerzero/src/message_lib/sml/events.cairo +32 -0
  198. package/layerzero/src/message_lib/sml/simple_message_lib.cairo +312 -0
  199. package/layerzero/src/message_lib/structs.cairo +22 -0
  200. package/layerzero/src/message_lib/uln/errors.cairo +128 -0
  201. package/layerzero/src/message_lib/uln/events.cairo +97 -0
  202. package/layerzero/src/message_lib/uln/interface.cairo +83 -0
  203. package/layerzero/src/message_lib/uln/options.cairo +64 -0
  204. package/layerzero/src/message_lib/uln/structs/executor_config.cairo +35 -0
  205. package/layerzero/src/message_lib/uln/structs/payment_info.cairo +7 -0
  206. package/layerzero/src/message_lib/uln/structs/uln_config.cairo +155 -0
  207. package/layerzero/src/message_lib/uln/structs/uln_config_storage_node.cairo +91 -0
  208. package/layerzero/src/message_lib/uln/structs/verification.cairo +7 -0
  209. package/layerzero/src/message_lib/uln/ultra_light_node.cairo +965 -0
  210. package/layerzero/src/oapps/common/oapp_options_type_3/errors.cairo +22 -0
  211. package/layerzero/src/oapps/common/oapp_options_type_3/events.cairo +6 -0
  212. package/layerzero/src/oapps/common/oapp_options_type_3/interface.cairo +34 -0
  213. package/layerzero/src/oapps/common/oapp_options_type_3/oapp_options_type_3.cairo +120 -0
  214. package/layerzero/src/oapps/common/oapp_options_type_3/structs.cairo +6 -0
  215. package/layerzero/src/oapps/counter/constants.cairo +3 -0
  216. package/layerzero/src/oapps/counter/counter.cairo +170 -0
  217. package/layerzero/src/oapps/counter/interface.cairo +27 -0
  218. package/layerzero/src/oapps/counter/structs.cairo +20 -0
  219. package/layerzero/src/oapps/message_inspector/interface.cairo +21 -0
  220. package/layerzero/src/oapps/oapp/errors.cairo +72 -0
  221. package/layerzero/src/oapps/oapp/events.cairo +9 -0
  222. package/layerzero/src/oapps/oapp/interface.cairo +67 -0
  223. package/layerzero/src/oapps/oapp/oapp.cairo +70 -0
  224. package/layerzero/src/oapps/oapp/oapp_core.cairo +448 -0
  225. package/layerzero/src/oapps/oft/errors.cairo +42 -0
  226. package/layerzero/src/oapps/oft/events.cairo +33 -0
  227. package/layerzero/src/oapps/oft/interface.cairo +87 -0
  228. package/layerzero/src/oapps/oft/oft.cairo +188 -0
  229. package/layerzero/src/oapps/oft/oft_adapter.cairo +175 -0
  230. package/layerzero/src/oapps/oft/oft_compose_msg_codec.cairo +128 -0
  231. package/layerzero/src/oapps/oft/oft_core.cairo +542 -0
  232. package/layerzero/src/oapps/oft/oft_msg_codec.cairo +131 -0
  233. package/layerzero/src/oapps/oft/structs.cairo +72 -0
  234. package/layerzero/src/treasury/errors.cairo +22 -0
  235. package/layerzero/src/treasury/events.cairo +5 -0
  236. package/layerzero/src/treasury/interfaces/layerzero_treasury.cairo +54 -0
  237. package/layerzero/src/treasury/interfaces/lz_token_fee_lib.cairo +45 -0
  238. package/layerzero/src/treasury/interfaces/treasury_admin.cairo +39 -0
  239. package/layerzero/src/treasury/treasury.cairo +140 -0
  240. package/layerzero/src/workers/access_control.cairo +11 -0
  241. package/layerzero/src/workers/base/base.cairo +238 -0
  242. package/layerzero/src/workers/base/errors.cairo +24 -0
  243. package/layerzero/src/workers/base/events.cairo +43 -0
  244. package/layerzero/src/workers/base/interface.cairo +93 -0
  245. package/layerzero/src/workers/base/structs.cairo +10 -0
  246. package/layerzero/src/workers/common.cairo +59 -0
  247. package/layerzero/src/workers/dvn/constants.cairo +11 -0
  248. package/layerzero/src/workers/dvn/dvn.cairo +338 -0
  249. package/layerzero/src/workers/dvn/errors.cairo +80 -0
  250. package/layerzero/src/workers/dvn/events.cairo +30 -0
  251. package/layerzero/src/workers/dvn/fee_lib/dvn_fee_lib.cairo +152 -0
  252. package/layerzero/src/workers/dvn/fee_lib/interface.cairo +45 -0
  253. package/layerzero/src/workers/dvn/interface.cairo +131 -0
  254. package/layerzero/src/workers/dvn/options.cairo +125 -0
  255. package/layerzero/src/workers/dvn/structs.cairo +51 -0
  256. package/layerzero/src/workers/executor/errors.cairo +159 -0
  257. package/layerzero/src/workers/executor/events.cairo +32 -0
  258. package/layerzero/src/workers/executor/executor.cairo +392 -0
  259. package/layerzero/src/workers/executor/fee_lib/executor_fee_lib.cairo +160 -0
  260. package/layerzero/src/workers/executor/fee_lib/interface.cairo +87 -0
  261. package/layerzero/src/workers/executor/interface.cairo +131 -0
  262. package/layerzero/src/workers/executor/options.cairo +244 -0
  263. package/layerzero/src/workers/executor/structs.cairo +119 -0
  264. package/layerzero/src/workers/interface.cairo +32 -0
  265. package/layerzero/src/workers/price_feed/constants.cairo +7 -0
  266. package/layerzero/src/workers/price_feed/errors.cairo +28 -0
  267. package/layerzero/src/workers/price_feed/events.cairo +13 -0
  268. package/layerzero/src/workers/price_feed/interface.cairo +264 -0
  269. package/layerzero/src/workers/price_feed/price_feed.cairo +392 -0
  270. package/layerzero/src/workers/price_feed/structs.cairo +74 -0
  271. package/layerzero/tests/common/test_constants.cairo +21 -0
  272. package/layerzero/tests/common/test_guid.cairo +232 -0
  273. package/layerzero/tests/common/test_packet_v1_codec.cairo +372 -0
  274. package/layerzero/tests/common/utils.cairo +23 -0
  275. package/layerzero/tests/e2e/oft_utils.cairo +121 -0
  276. package/layerzero/tests/e2e/test_counter_with_sml.cairo +194 -0
  277. package/layerzero/tests/e2e/test_counter_with_uln.cairo +352 -0
  278. package/layerzero/tests/e2e/test_dvn.cairo +406 -0
  279. package/layerzero/tests/e2e/test_lz_token.cairo +354 -0
  280. package/layerzero/tests/e2e/test_oft_compose_with_uln.cairo +364 -0
  281. package/layerzero/tests/e2e/test_oft_with_sml.cairo +240 -0
  282. package/layerzero/tests/e2e/test_oft_with_uln.cairo +299 -0
  283. package/layerzero/tests/e2e/utils.cairo +490 -0
  284. package/layerzero/tests/endpoint/message_lib_manager/test_message_lib_manager.cairo +2051 -0
  285. package/layerzero/tests/endpoint/message_lib_manager/utils.cairo +45 -0
  286. package/layerzero/tests/endpoint/messaging_channel/test_messaging_channel.cairo +621 -0
  287. package/layerzero/tests/endpoint/messaging_channel/utils.cairo +96 -0
  288. package/layerzero/tests/endpoint/messaging_composer/test_messaging_composer.cairo +456 -0
  289. package/layerzero/tests/endpoint/messaging_composer/utils.cairo +75 -0
  290. package/layerzero/tests/endpoint/test_endpoint_commit.cairo +763 -0
  291. package/layerzero/tests/endpoint/test_endpoint_lzreceive.cairo +1253 -0
  292. package/layerzero/tests/endpoint/test_endpoint_quote.cairo +71 -0
  293. package/layerzero/tests/endpoint/test_endpoint_send.cairo +1327 -0
  294. package/layerzero/tests/endpoint/utils.cairo +129 -0
  295. package/layerzero/tests/fuzzable/blockchain_config.cairo +89 -0
  296. package/layerzero/tests/fuzzable/bytes32.cairo +16 -0
  297. package/layerzero/tests/fuzzable/contract_address.cairo +67 -0
  298. package/layerzero/tests/fuzzable/dst_config.cairo +37 -0
  299. package/layerzero/tests/fuzzable/eid.cairo +23 -0
  300. package/layerzero/tests/fuzzable/eth_address.cairo +17 -0
  301. package/layerzero/tests/fuzzable/expiry.cairo +27 -0
  302. package/layerzero/tests/fuzzable/felt_array.cairo +38 -0
  303. package/layerzero/tests/fuzzable/inbound_params.cairo +21 -0
  304. package/layerzero/tests/fuzzable/keys.cairo +16 -0
  305. package/layerzero/tests/fuzzable/model_type.cairo +27 -0
  306. package/layerzero/tests/fuzzable/origin.cairo +21 -0
  307. package/layerzero/tests/fuzzable/price.cairo +32 -0
  308. package/layerzero/tests/fuzzable/role_admin.cairo +29 -0
  309. package/layerzero/tests/fuzzable/small_byte_array.cairo +61 -0
  310. package/layerzero/tests/lib.cairo +177 -0
  311. package/layerzero/tests/message_lib/sml/test_simple_message_lib.cairo +224 -0
  312. package/layerzero/tests/message_lib/uln/test_uln_admin.cairo +2150 -0
  313. package/layerzero/tests/message_lib/uln/test_uln_config.cairo +527 -0
  314. package/layerzero/tests/message_lib/uln/test_uln_config_storage_node.cairo +69 -0
  315. package/layerzero/tests/message_lib/uln/test_uln_executor_config.cairo +173 -0
  316. package/layerzero/tests/message_lib/uln/test_uln_options.cairo +329 -0
  317. package/layerzero/tests/message_lib/uln/test_uln_quote.cairo +1038 -0
  318. package/layerzero/tests/message_lib/uln/test_uln_receive.cairo +715 -0
  319. package/layerzero/tests/message_lib/uln/test_uln_send.cairo +1155 -0
  320. package/layerzero/tests/message_lib/uln/utils.cairo +59 -0
  321. package/layerzero/tests/mocks/composer_target.cairo +76 -0
  322. package/layerzero/tests/mocks/endpoint.cairo +199 -0
  323. package/layerzero/tests/mocks/erc20/erc20.cairo +50 -0
  324. package/layerzero/tests/mocks/erc20/interface.cairo +8 -0
  325. package/layerzero/tests/mocks/message_inspector/message_inspector.cairo +17 -0
  326. package/layerzero/tests/mocks/message_lib_manager.cairo +98 -0
  327. package/layerzero/tests/mocks/messaging_channel/interface.cairo +23 -0
  328. package/layerzero/tests/mocks/messaging_channel/messaging_channel.cairo +138 -0
  329. package/layerzero/tests/mocks/messaging_composer.cairo +171 -0
  330. package/layerzero/tests/mocks/oapp_core/interface.cairo +53 -0
  331. package/layerzero/tests/mocks/oapp_core/oapp_core.cairo +142 -0
  332. package/layerzero/tests/mocks/oapp_options_type3.cairo +42 -0
  333. package/layerzero/tests/mocks/oft_core/interface.cairo +28 -0
  334. package/layerzero/tests/mocks/oft_core/oft_core.cairo +242 -0
  335. package/layerzero/tests/mocks/receiver.cairo +54 -0
  336. package/layerzero/tests/mocks/treasury/lz_token_fee_lib.cairo +57 -0
  337. package/layerzero/tests/mocks/treasury/treasury.cairo +74 -0
  338. package/layerzero/tests/mocks/uln_config/interface.cairo +12 -0
  339. package/layerzero/tests/mocks/uln_config/uln_config.cairo +35 -0
  340. package/layerzero/tests/mocks/workers/base.cairo +80 -0
  341. package/layerzero/tests/mocks/workers/dvn.cairo +115 -0
  342. package/layerzero/tests/mocks/workers/executor/decode/decode.cairo +97 -0
  343. package/layerzero/tests/mocks/workers/executor/decode/interface.cairo +59 -0
  344. package/layerzero/tests/mocks/workers/executor/executor.cairo +176 -0
  345. package/layerzero/tests/oapps/common/test_oapp_options_type_3.cairo +279 -0
  346. package/layerzero/tests/oapps/oft/test_oft_adapter.cairo +441 -0
  347. package/layerzero/tests/oapps/oft/test_oft_compose_msg_codec.cairo +139 -0
  348. package/layerzero/tests/oapps/oft/test_oft_core.cairo +751 -0
  349. package/layerzero/tests/oapps/oft/test_oft_msg_codec.cairo +268 -0
  350. package/layerzero/tests/oapps/test_counter.cairo +470 -0
  351. package/layerzero/tests/oapps/test_oapp_core.cairo +750 -0
  352. package/layerzero/tests/treasury/test_lz_token_fee_lib.cairo +63 -0
  353. package/layerzero/tests/treasury/test_treasury.cairo +458 -0
  354. package/layerzero/tests/treasury/utils.cairo +8 -0
  355. package/layerzero/tests/utils.cairo +48 -0
  356. package/layerzero/tests/workers/base/test_worker_base.cairo +1097 -0
  357. package/layerzero/tests/workers/base/utils.cairo +76 -0
  358. package/layerzero/tests/workers/dvn/fee_lib/test_dvn_fee_lib.cairo +361 -0
  359. package/layerzero/tests/workers/dvn/test_dvn.cairo +1101 -0
  360. package/layerzero/tests/workers/dvn/test_dvn_options.cairo +312 -0
  361. package/layerzero/tests/workers/dvn/utils.cairo +236 -0
  362. package/layerzero/tests/workers/executor/fee_lib/test_executor_fee_lib.cairo +223 -0
  363. package/layerzero/tests/workers/executor/test_decode.cairo +612 -0
  364. package/layerzero/tests/workers/executor/test_executor.cairo +1472 -0
  365. package/layerzero/tests/workers/executor/utils.cairo +296 -0
  366. package/layerzero/tests/workers/price_feed/test_price_feed.cairo +879 -0
  367. package/layerzero/tests/workers/price_feed/utils.cairo +37 -0
  368. package/libs/enumerable_set/Scarb.lock +24 -0
  369. package/libs/enumerable_set/Scarb.toml +17 -0
  370. package/libs/enumerable_set/src/enumerable_set.cairo +118 -0
  371. package/libs/enumerable_set/src/lib.cairo +4 -0
  372. package/libs/enumerable_set/tests/lib.cairo +5 -0
  373. package/libs/enumerable_set/tests/mocks/mock_enumerable_set.cairo +61 -0
  374. package/libs/enumerable_set/tests/test_enumerable_set.cairo +379 -0
  375. package/libs/lz_utils/Scarb.lock +24 -0
  376. package/libs/lz_utils/Scarb.toml +17 -0
  377. package/libs/lz_utils/src/bytes.cairo +33 -0
  378. package/libs/lz_utils/src/error.cairo +12 -0
  379. package/libs/lz_utils/src/keccak.cairo +28 -0
  380. package/libs/lz_utils/src/lib.cairo +3 -0
  381. package/libs/multisig/Scarb.lock +172 -0
  382. package/libs/multisig/Scarb.toml +23 -0
  383. package/libs/multisig/src/errors.cairo +84 -0
  384. package/libs/multisig/src/events.cairo +13 -0
  385. package/libs/multisig/src/interface.cairo +73 -0
  386. package/libs/multisig/src/lib.cairo +7 -0
  387. package/libs/multisig/src/multisig.cairo +241 -0
  388. package/libs/multisig/tests/lib.cairo +4 -0
  389. package/libs/multisig/tests/mocks/mock_multisig.cairo +57 -0
  390. package/libs/multisig/tests/test_multisig.cairo +452 -0
  391. package/package.json +41 -0
  392. package/src/scripts/build-abi.ts +51 -0
  393. package/target/CACHEDIR.TAG +3 -0
  394. package/target/dev/.fingerprint/alexandria_bytes-5ea6u5t70d7qi/alexandria_bytes +1 -0
  395. package/target/dev/.fingerprint/alexandria_data_structures-0aue3g6q80gs0/alexandria_data_structures +1 -0
  396. package/target/dev/.fingerprint/alexandria_math-h2fi7jdq4isuu/alexandria_math +1 -0
  397. package/target/dev/.fingerprint/core-lq3u730l5p1ag/core +1 -0
  398. package/target/dev/.fingerprint/core-vf7fc6rvic5vi/core +1 -0
  399. package/target/dev/.fingerprint/enumerable_set-eaerkg8njl85o/enumerable_set +1 -0
  400. package/target/dev/.fingerprint/enumerable_set-r54oje7t06ku8/enumerable_set +1 -0
  401. package/target/dev/.fingerprint/layerzero-oqgdqsaddpi2k/layerzero +1 -0
  402. package/target/dev/.fingerprint/lz_utils-kfkkeueiqg0pa/lz_utils +1 -0
  403. package/target/dev/.fingerprint/lz_utils-u4v1os6e7gkng/lz_utils +1 -0
  404. package/target/dev/.fingerprint/multisig-0fjetugejecge/multisig +1 -0
  405. package/target/dev/.fingerprint/multisig-6j5kqs436hm54/multisig +1 -0
  406. package/target/dev/.fingerprint/openzeppelin-ei1id1hu088lo/openzeppelin +1 -0
  407. package/target/dev/.fingerprint/openzeppelin-j9d5nd1qhfnu6/openzeppelin +1 -0
  408. package/target/dev/.fingerprint/openzeppelin_access-3oa41aikpaek0/openzeppelin_access +1 -0
  409. package/target/dev/.fingerprint/openzeppelin_access-p5h849v8so76q/openzeppelin_access +1 -0
  410. package/target/dev/.fingerprint/openzeppelin_account-4qhv5fks84g9u/openzeppelin_account +1 -0
  411. package/target/dev/.fingerprint/openzeppelin_account-hgbm8ln9ah7rm/openzeppelin_account +1 -0
  412. package/target/dev/.fingerprint/openzeppelin_finance-n70q9al0cps8i/openzeppelin_finance +1 -0
  413. package/target/dev/.fingerprint/openzeppelin_finance-nnd4f8703t3ak/openzeppelin_finance +1 -0
  414. package/target/dev/.fingerprint/openzeppelin_governance-3gnk21ubp5lis/openzeppelin_governance +1 -0
  415. package/target/dev/.fingerprint/openzeppelin_governance-rj1bfont4fij4/openzeppelin_governance +1 -0
  416. package/target/dev/.fingerprint/openzeppelin_introspection-3fja9hd1gvbcq/openzeppelin_introspection +1 -0
  417. package/target/dev/.fingerprint/openzeppelin_introspection-jc3nf5525eet6/openzeppelin_introspection +1 -0
  418. package/target/dev/.fingerprint/openzeppelin_merkle_tree-4en77ogr2r2l2/openzeppelin_merkle_tree +1 -0
  419. package/target/dev/.fingerprint/openzeppelin_merkle_tree-4t190frqs4db8/openzeppelin_merkle_tree +1 -0
  420. package/target/dev/.fingerprint/openzeppelin_presets-aqb0f6p9c0bp6/openzeppelin_presets +1 -0
  421. package/target/dev/.fingerprint/openzeppelin_presets-nseg8korhin8e/openzeppelin_presets +1 -0
  422. package/target/dev/.fingerprint/openzeppelin_security-g7p73ji1ih1qg/openzeppelin_security +1 -0
  423. package/target/dev/.fingerprint/openzeppelin_security-qp5328v80452u/openzeppelin_security +1 -0
  424. package/target/dev/.fingerprint/openzeppelin_token-jjf7tl9rphc6k/openzeppelin_token +1 -0
  425. package/target/dev/.fingerprint/openzeppelin_token-r6s43vlpj6rqk/openzeppelin_token +1 -0
  426. package/target/dev/.fingerprint/openzeppelin_upgrades-0dpbnre7engca/openzeppelin_upgrades +1 -0
  427. package/target/dev/.fingerprint/openzeppelin_upgrades-2sqgvbuv9s800/openzeppelin_upgrades +1 -0
  428. package/target/dev/.fingerprint/openzeppelin_utils-mj395ivff1ffo/openzeppelin_utils +1 -0
  429. package/target/dev/.fingerprint/openzeppelin_utils-oh1hse8sjumgm/openzeppelin_utils +1 -0
  430. package/target/dev/.fingerprint/starkware_utils-1qnnjnq0pf9u0/starkware_utils +1 -0
  431. package/target/dev/.fingerprint/starkware_utils-mh8e3te65lju4/starkware_utils +1 -0
  432. package/target/dev/enumerable_set.sierra.json +1 -0
  433. package/target/dev/incremental/alexandria_bytes-5ea6u5t70d7qi.bin +0 -0
  434. package/target/dev/incremental/alexandria_data_structures-0aue3g6q80gs0.bin +0 -0
  435. package/target/dev/incremental/alexandria_math-h2fi7jdq4isuu.bin +0 -0
  436. package/target/dev/incremental/core-lq3u730l5p1ag.bin +0 -0
  437. package/target/dev/incremental/core-vf7fc6rvic5vi.bin +0 -0
  438. package/target/dev/incremental/enumerable_set-eaerkg8njl85o.bin +0 -0
  439. package/target/dev/incremental/enumerable_set-r54oje7t06ku8.bin +0 -0
  440. package/target/dev/incremental/layerzero-oqgdqsaddpi2k.bin +0 -0
  441. package/target/dev/incremental/lz_utils-kfkkeueiqg0pa.bin +0 -0
  442. package/target/dev/incremental/lz_utils-u4v1os6e7gkng.bin +0 -0
  443. package/target/dev/incremental/multisig-0fjetugejecge.bin +0 -0
  444. package/target/dev/incremental/multisig-6j5kqs436hm54.bin +0 -0
  445. package/target/dev/incremental/openzeppelin-ei1id1hu088lo.bin +0 -0
  446. package/target/dev/incremental/openzeppelin-j9d5nd1qhfnu6.bin +0 -0
  447. package/target/dev/incremental/openzeppelin_access-3oa41aikpaek0.bin +0 -0
  448. package/target/dev/incremental/openzeppelin_access-p5h849v8so76q.bin +0 -0
  449. package/target/dev/incremental/openzeppelin_account-4qhv5fks84g9u.bin +0 -0
  450. package/target/dev/incremental/openzeppelin_account-hgbm8ln9ah7rm.bin +0 -0
  451. package/target/dev/incremental/openzeppelin_finance-n70q9al0cps8i.bin +0 -0
  452. package/target/dev/incremental/openzeppelin_finance-nnd4f8703t3ak.bin +0 -0
  453. package/target/dev/incremental/openzeppelin_governance-3gnk21ubp5lis.bin +0 -0
  454. package/target/dev/incremental/openzeppelin_governance-rj1bfont4fij4.bin +0 -0
  455. package/target/dev/incremental/openzeppelin_introspection-3fja9hd1gvbcq.bin +0 -0
  456. package/target/dev/incremental/openzeppelin_introspection-jc3nf5525eet6.bin +0 -0
  457. package/target/dev/incremental/openzeppelin_merkle_tree-4en77ogr2r2l2.bin +0 -0
  458. package/target/dev/incremental/openzeppelin_merkle_tree-4t190frqs4db8.bin +0 -0
  459. package/target/dev/incremental/openzeppelin_presets-aqb0f6p9c0bp6.bin +0 -0
  460. package/target/dev/incremental/openzeppelin_presets-nseg8korhin8e.bin +0 -0
  461. package/target/dev/incremental/openzeppelin_security-g7p73ji1ih1qg.bin +0 -0
  462. package/target/dev/incremental/openzeppelin_security-qp5328v80452u.bin +0 -0
  463. package/target/dev/incremental/openzeppelin_token-jjf7tl9rphc6k.bin +0 -0
  464. package/target/dev/incremental/openzeppelin_token-r6s43vlpj6rqk.bin +0 -0
  465. package/target/dev/incremental/openzeppelin_upgrades-0dpbnre7engca.bin +0 -0
  466. package/target/dev/incremental/openzeppelin_upgrades-2sqgvbuv9s800.bin +0 -0
  467. package/target/dev/incremental/openzeppelin_utils-mj395ivff1ffo.bin +0 -0
  468. package/target/dev/incremental/openzeppelin_utils-oh1hse8sjumgm.bin +0 -0
  469. package/target/dev/incremental/starkware_utils-1qnnjnq0pf9u0.bin +0 -0
  470. package/target/dev/incremental/starkware_utils-mh8e3te65lju4.bin +0 -0
  471. package/target/dev/layerzero.starknet_artifacts.json +1 -0
  472. package/target/dev/layerzero_BlockedMessageLib.compiled_contract_class.json +1 -0
  473. package/target/dev/layerzero_BlockedMessageLib.contract_class.json +1 -0
  474. package/target/dev/layerzero_Dvn.compiled_contract_class.json +1 -0
  475. package/target/dev/layerzero_Dvn.contract_class.json +1 -0
  476. package/target/dev/layerzero_DvnFeeLib.compiled_contract_class.json +1 -0
  477. package/target/dev/layerzero_DvnFeeLib.contract_class.json +1 -0
  478. package/target/dev/layerzero_Endpoint.compiled_contract_class.json +1 -0
  479. package/target/dev/layerzero_Endpoint.contract_class.json +1 -0
  480. package/target/dev/layerzero_Executor.compiled_contract_class.json +1 -0
  481. package/target/dev/layerzero_Executor.contract_class.json +1 -0
  482. package/target/dev/layerzero_ExecutorFeeLib.compiled_contract_class.json +1 -0
  483. package/target/dev/layerzero_ExecutorFeeLib.contract_class.json +1 -0
  484. package/target/dev/layerzero_OApp.compiled_contract_class.json +1 -0
  485. package/target/dev/layerzero_OApp.contract_class.json +1 -0
  486. package/target/dev/layerzero_OFT.compiled_contract_class.json +1 -0
  487. package/target/dev/layerzero_OFT.contract_class.json +1 -0
  488. package/target/dev/layerzero_OFTAdapter.compiled_contract_class.json +1 -0
  489. package/target/dev/layerzero_OFTAdapter.contract_class.json +1 -0
  490. package/target/dev/layerzero_OmniCounter.compiled_contract_class.json +1 -0
  491. package/target/dev/layerzero_OmniCounter.contract_class.json +1 -0
  492. package/target/dev/layerzero_PriceFeed.compiled_contract_class.json +1 -0
  493. package/target/dev/layerzero_PriceFeed.contract_class.json +1 -0
  494. package/target/dev/layerzero_SimpleMessageLib.compiled_contract_class.json +1 -0
  495. package/target/dev/layerzero_SimpleMessageLib.contract_class.json +1 -0
  496. package/target/dev/layerzero_Treasury.compiled_contract_class.json +1 -0
  497. package/target/dev/layerzero_Treasury.contract_class.json +1 -0
  498. package/target/dev/layerzero_UltraLightNode.compiled_contract_class.json +1 -0
  499. package/target/dev/layerzero_UltraLightNode.contract_class.json +1 -0
  500. package/target/dev/lz_utils.sierra.json +1 -0
  501. package/target/dev/multisig.sierra.json +1 -0
  502. package/tools/update_contracts.sh +19 -0
  503. package/tsconfig.json +20 -0
  504. package/tsup.config.ts +7 -0
@@ -0,0 +1,2150 @@
1
+ //! ULN admin tests
2
+
3
+ use layerzero::message_lib::interface::{IMessageLibSafeDispatcher, IMessageLibSafeDispatcherTrait};
4
+ use layerzero::message_lib::uln::errors::{
5
+ err_invalid_confirmations, err_invalid_optional_dvn_threshold, err_must_have_at_least_one_dvn,
6
+ err_too_many_dvns, err_unsorted_dvns, err_unsupported_send_eid,
7
+ };
8
+ use layerzero::message_lib::uln::events::{
9
+ DefaultExecutorConfigSet, DefaultUlnReceiveConfigSet, DefaultUlnSendConfigSet,
10
+ OAppExecutorConfigSet, OAppUlnReceiveConfigSet, OAppUlnSendConfigSet,
11
+ };
12
+ use layerzero::message_lib::uln::interface::{
13
+ IUltraLightNodeAdminDispatcher, IUltraLightNodeAdminDispatcherTrait,
14
+ IUltraLightNodeAdminSafeDispatcher, IUltraLightNodeAdminSafeDispatcherTrait,
15
+ };
16
+ use layerzero::message_lib::uln::structs::executor_config::ExecutorConfig;
17
+ use layerzero::message_lib::uln::structs::uln_config::{SetDefaultUlnConfigParam, UlnConfig};
18
+ use layerzero::message_lib::uln::ultra_light_node::UltraLightNode;
19
+ use snforge_std::{
20
+ ContractClassTrait, DeclareResultTrait, EventSpyAssertionsTrait, declare, spy_events,
21
+ start_cheat_caller_address, stop_cheat_caller_address,
22
+ };
23
+ use starknet::ContractAddress;
24
+ use starkware_utils_testing::test_utils::assert_panic_with_error;
25
+ use crate::message_lib::uln::utils::{
26
+ create_executor_send_config_param, set_oapp_executor_send_config_via_message_lib,
27
+ set_oapp_uln_receive_config_via_message_lib, set_oapp_uln_send_config_via_message_lib,
28
+ };
29
+ use super::utils::create_uln_send_config_param;
30
+
31
+
32
+ // Test constants
33
+ pub const ENDPOINT: ContractAddress = 'endpoint'.try_into().unwrap();
34
+ pub const OWNER: ContractAddress = 'owner'.try_into().unwrap();
35
+ pub const NON_OWNER: ContractAddress = 'non_owner'.try_into().unwrap();
36
+ pub const SENDER: ContractAddress = 'sender'.try_into().unwrap();
37
+ pub const SENDER_2: ContractAddress = 'sender_2'.try_into().unwrap();
38
+ pub const DVN_1: ContractAddress = 'dvn_1'.try_into().unwrap();
39
+ pub const DVN_2: ContractAddress = 'dvn_2'.try_into().unwrap();
40
+ pub const DVN_3: ContractAddress = 'dvn_3'.try_into().unwrap();
41
+ pub const EXECUTOR: ContractAddress = 'executor'.try_into().unwrap();
42
+ pub const EXECUTOR_2: ContractAddress = 'executor_2'.try_into().unwrap();
43
+ pub const DST_EID: u32 = 2;
44
+ pub const DST_EID_2: u32 = 3;
45
+ pub const MAX_MESSAGE_SIZE: u32 = 100;
46
+ pub const CONFIRMATIONS: u64 = 20;
47
+ pub const TREASURY_FEE: u256 = 300;
48
+ pub const TREASURY_NATIVE_FEE_CAP: u256 = 100;
49
+
50
+ // Helper functions
51
+ fn deploy_ultra_light_node() -> (IUltraLightNodeAdminDispatcher, ContractAddress) {
52
+ let contract = declare("UltraLightNode").unwrap().contract_class();
53
+ let treasury = deploy_mock_treasury(TREASURY_FEE);
54
+ let mut constructor_calldata = array![OWNER.into(), treasury.into(), ENDPOINT.into()];
55
+ TREASURY_NATIVE_FEE_CAP.serialize(ref constructor_calldata);
56
+ let (contract_address, _) = contract.deploy(@constructor_calldata).unwrap();
57
+ let admin = IUltraLightNodeAdminDispatcher { contract_address };
58
+ (admin, contract_address)
59
+ }
60
+
61
+ fn deploy_ultra_light_node_safe() -> (IUltraLightNodeAdminSafeDispatcher, ContractAddress) {
62
+ let contract = declare("UltraLightNode").unwrap().contract_class();
63
+ let treasury = deploy_mock_treasury(TREASURY_FEE);
64
+ let mut constructor_calldata = array![OWNER.into(), treasury.into(), ENDPOINT.into()];
65
+ TREASURY_NATIVE_FEE_CAP.serialize(ref constructor_calldata);
66
+ let (contract_address, _) = contract.deploy(@constructor_calldata).unwrap();
67
+ let admin = IUltraLightNodeAdminSafeDispatcher { contract_address };
68
+ (admin, contract_address)
69
+ }
70
+
71
+ fn deploy_mock_treasury(treasury_fee: u256) -> ContractAddress {
72
+ let contract = declare("MockTreasury").unwrap().contract_class();
73
+ let constructor_calldata = array![treasury_fee.low.into(), treasury_fee.high.into()];
74
+ let (address, _) = contract.deploy(@constructor_calldata).unwrap();
75
+ address
76
+ }
77
+
78
+ fn create_required_dvns() -> Array<ContractAddress> {
79
+ array![DVN_1, DVN_2]
80
+ }
81
+
82
+ fn create_optional_dvns() -> Array<ContractAddress> {
83
+ array![]
84
+ }
85
+
86
+ fn create_test_uln_config() -> UlnConfig {
87
+ UlnConfig {
88
+ confirmations: CONFIRMATIONS,
89
+ has_confirmations: true,
90
+ required_dvns: create_required_dvns(),
91
+ has_required_dvns: true,
92
+ optional_dvns: create_optional_dvns(),
93
+ optional_dvn_threshold: 0,
94
+ has_optional_dvns: true,
95
+ }
96
+ }
97
+
98
+ fn create_test_executor_config() -> ExecutorConfig {
99
+ ExecutorConfig { max_message_size: MAX_MESSAGE_SIZE, executor: EXECUTOR }
100
+ }
101
+
102
+ // Helper function to set up default config for an EID (makes EID supported)
103
+ fn setup_default_config(
104
+ admin: IUltraLightNodeAdminDispatcher, contract_address: ContractAddress, dst_eid: u32,
105
+ ) {
106
+ start_cheat_caller_address(contract_address, OWNER);
107
+ let default_config = create_test_uln_config();
108
+ let config_params = array![SetDefaultUlnConfigParam { eid: dst_eid, config: default_config }];
109
+ admin.set_default_uln_send_config(config_params);
110
+ stop_cheat_caller_address(contract_address);
111
+ }
112
+
113
+ // Helper function to set up default config for safe dispatcher tests
114
+ fn setup_default_config_for_safe_test(contract_address: ContractAddress, dst_eid: u32) {
115
+ let admin_regular = IUltraLightNodeAdminDispatcher { contract_address };
116
+ setup_default_config(admin_regular, contract_address, dst_eid);
117
+ }
118
+
119
+ // Test cases for admin functions
120
+ #[test]
121
+ fn test_owner_can_set_default_uln_send_config() {
122
+ let (admin, contract_address) = deploy_ultra_light_node();
123
+ let uln_config = create_test_uln_config();
124
+
125
+ // Test that owner can set default configs
126
+ start_cheat_caller_address(contract_address, OWNER);
127
+
128
+ // Create array of configs for the new API
129
+ let config_params = array![
130
+ SetDefaultUlnConfigParam { eid: DST_EID, config: uln_config.clone() },
131
+ ];
132
+
133
+ // Set up event spy
134
+ let mut spy = spy_events();
135
+
136
+ admin.set_default_uln_send_config(config_params);
137
+
138
+ // Verify config was set
139
+ let retrieved_uln_config = admin.get_default_uln_send_config(DST_EID);
140
+
141
+ assert(retrieved_uln_config.confirmations == CONFIRMATIONS, 'ULN confirmations incorrect');
142
+ assert(
143
+ retrieved_uln_config.required_dvns.len() == create_required_dvns().len(),
144
+ 'ULN DVNs count incorrect',
145
+ );
146
+
147
+ // Verify event was emitted
148
+ spy
149
+ .assert_emitted(
150
+ @array![
151
+ (
152
+ contract_address,
153
+ UltraLightNode::Event::DefaultUlnSendConfigSet(
154
+ DefaultUlnSendConfigSet { dst_eid: DST_EID, config: uln_config },
155
+ ),
156
+ ),
157
+ ],
158
+ );
159
+
160
+ stop_cheat_caller_address(contract_address);
161
+ }
162
+
163
+ #[test]
164
+ fn test_owner_can_set_default_executor_config() {
165
+ let (admin, contract_address) = deploy_ultra_light_node();
166
+ let executor_config = create_test_executor_config();
167
+
168
+ // Test that owner can set default executor config
169
+ start_cheat_caller_address(contract_address, OWNER);
170
+
171
+ // Set up event spy
172
+ let mut spy = spy_events();
173
+
174
+ admin.set_default_executor_config(DST_EID, executor_config.clone());
175
+
176
+ // Verify config was set
177
+ let retrieved_executor_config = admin.get_default_executor_config(DST_EID);
178
+
179
+ assert(
180
+ retrieved_executor_config.max_message_size == MAX_MESSAGE_SIZE, 'Executor size incorrect',
181
+ );
182
+ assert(retrieved_executor_config.executor == EXECUTOR, 'Executor address incorrect');
183
+
184
+ // Verify event was emitted
185
+ spy
186
+ .assert_emitted(
187
+ @array![
188
+ (
189
+ contract_address,
190
+ UltraLightNode::Event::DefaultExecutorConfigSet(
191
+ DefaultExecutorConfigSet { dst_eid: DST_EID, config: executor_config },
192
+ ),
193
+ ),
194
+ ],
195
+ );
196
+
197
+ stop_cheat_caller_address(contract_address);
198
+ }
199
+
200
+ #[test]
201
+ #[should_panic(expected: ('Caller is not the owner',))]
202
+ fn test_non_owner_cannot_set_default_uln_send_config() {
203
+ let (admin, contract_address) = deploy_ultra_light_node();
204
+ let uln_config = create_test_uln_config();
205
+
206
+ start_cheat_caller_address(contract_address, NON_OWNER);
207
+
208
+ let config_params = array![SetDefaultUlnConfigParam { eid: DST_EID, config: uln_config }];
209
+
210
+ admin.set_default_uln_send_config(config_params); // This should panic
211
+ }
212
+
213
+ #[test]
214
+ #[should_panic(expected: ('Caller is not the owner',))]
215
+ fn test_non_owner_cannot_set_default_executor_config() {
216
+ let (admin, contract_address) = deploy_ultra_light_node();
217
+ let executor_config = create_test_executor_config();
218
+
219
+ start_cheat_caller_address(contract_address, NON_OWNER);
220
+
221
+ admin.set_default_executor_config(DST_EID, executor_config); // This should panic
222
+ }
223
+
224
+ #[test]
225
+ fn test_set_and_get_default_uln_send_config_multiple_destinations() {
226
+ let (admin, contract_address) = deploy_ultra_light_node();
227
+
228
+ start_cheat_caller_address(contract_address, OWNER);
229
+
230
+ // Set configs for different destinations
231
+ let config_dst2 = UlnConfig {
232
+ confirmations: 5,
233
+ has_confirmations: true,
234
+ required_dvns: array![DVN_1],
235
+ has_required_dvns: true,
236
+ optional_dvns: array![],
237
+ optional_dvn_threshold: 0,
238
+ has_optional_dvns: true,
239
+ };
240
+
241
+ let config_dst3 = UlnConfig {
242
+ confirmations: 15,
243
+ has_confirmations: true,
244
+ required_dvns: array![DVN_1, DVN_2],
245
+ has_required_dvns: true,
246
+ optional_dvns: array![],
247
+ optional_dvn_threshold: 0,
248
+ has_optional_dvns: true,
249
+ };
250
+
251
+ // Use the new batch API to set multiple configs at once
252
+ let config_params = array![
253
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_dst2.clone() },
254
+ SetDefaultUlnConfigParam { eid: DST_EID_2, config: config_dst3.clone() },
255
+ ];
256
+
257
+ // Set up event spy
258
+ let mut spy = spy_events();
259
+
260
+ admin.set_default_uln_send_config(config_params);
261
+
262
+ // Verify different configs for different destinations
263
+ let retrieved_config_dst2 = admin.get_default_uln_send_config(DST_EID);
264
+ let retrieved_config_dst3 = admin.get_default_uln_send_config(DST_EID_2);
265
+
266
+ assert(
267
+ retrieved_config_dst2.confirmations == config_dst2.confirmations,
268
+ 'DST2 confirmations incorrect',
269
+ );
270
+ assert(
271
+ retrieved_config_dst2.required_dvns.len() == config_dst2.required_dvns.len(),
272
+ 'DST2 DVNs count incorrect',
273
+ );
274
+ assert(
275
+ retrieved_config_dst3.confirmations == config_dst3.confirmations,
276
+ 'DST3 confirmations incorrect',
277
+ );
278
+ assert(
279
+ retrieved_config_dst3.required_dvns.len() == config_dst3.required_dvns.len(),
280
+ 'DST3 DVNs count incorrect',
281
+ );
282
+
283
+ // Verify events were emitted for both configs
284
+ spy
285
+ .assert_emitted(
286
+ @array![
287
+ (
288
+ contract_address,
289
+ UltraLightNode::Event::DefaultUlnSendConfigSet(
290
+ DefaultUlnSendConfigSet { dst_eid: DST_EID, config: config_dst2 },
291
+ ),
292
+ ),
293
+ (
294
+ contract_address,
295
+ UltraLightNode::Event::DefaultUlnSendConfigSet(
296
+ DefaultUlnSendConfigSet { dst_eid: DST_EID_2, config: config_dst3 },
297
+ ),
298
+ ),
299
+ ],
300
+ );
301
+
302
+ stop_cheat_caller_address(contract_address);
303
+ }
304
+
305
+ #[test]
306
+ fn test_set_and_get_default_executor_config_multiple_destinations() {
307
+ let (admin, contract_address) = deploy_ultra_light_node();
308
+
309
+ start_cheat_caller_address(contract_address, OWNER);
310
+
311
+ // Set configs for different destinations
312
+ let config_dst2 = ExecutorConfig { max_message_size: 500, executor: EXECUTOR };
313
+ let config_dst3 = ExecutorConfig { max_message_size: 2000, executor: EXECUTOR_2 };
314
+
315
+ admin.set_default_executor_config(DST_EID, config_dst2.clone());
316
+ admin.set_default_executor_config(DST_EID_2, config_dst3.clone());
317
+
318
+ // Verify different configs for different destinations
319
+ let retrieved_config_dst2 = admin.get_default_executor_config(DST_EID);
320
+ let retrieved_config_dst3 = admin.get_default_executor_config(DST_EID_2);
321
+
322
+ assert(
323
+ retrieved_config_dst2.max_message_size == config_dst2.max_message_size,
324
+ 'DST2 size incorrect',
325
+ );
326
+ assert(retrieved_config_dst2.executor == EXECUTOR, 'DST2 executor incorrect');
327
+ assert(
328
+ retrieved_config_dst3.max_message_size == config_dst3.max_message_size,
329
+ 'DST3 size incorrect',
330
+ );
331
+ assert(retrieved_config_dst3.executor == EXECUTOR_2, 'DST3 executor incorrect');
332
+
333
+ stop_cheat_caller_address(contract_address);
334
+ }
335
+
336
+ #[test]
337
+ fn test_set_and_get_raw_oapp_uln_send_config_multiple_senders() {
338
+ let (admin, contract_address) = deploy_ultra_light_node();
339
+
340
+ // First set default config as owner (required for EID to be supported)
341
+ setup_default_config(admin, contract_address, DST_EID);
342
+
343
+ // Set configs for different senders (no ownership required)
344
+ let config_sender1 = UlnConfig {
345
+ confirmations: 8,
346
+ has_confirmations: true,
347
+ required_dvns: array![DVN_1],
348
+ has_required_dvns: true,
349
+ optional_dvns: array![],
350
+ optional_dvn_threshold: 0,
351
+ has_optional_dvns: true,
352
+ };
353
+
354
+ let config_sender2 = UlnConfig {
355
+ confirmations: 12,
356
+ has_confirmations: true,
357
+ required_dvns: array![DVN_2],
358
+ has_required_dvns: true,
359
+ optional_dvns: array![],
360
+ optional_dvn_threshold: 0,
361
+ has_optional_dvns: true,
362
+ };
363
+
364
+ // Set up event spy
365
+ let mut spy = spy_events();
366
+
367
+ // Set config for SENDER
368
+ start_cheat_caller_address(contract_address, ENDPOINT);
369
+ set_oapp_uln_send_config_via_message_lib(
370
+ contract_address, SENDER, DST_EID, config_sender1.clone(),
371
+ );
372
+
373
+ // Set config for SENDER_2
374
+ set_oapp_uln_send_config_via_message_lib(
375
+ contract_address, SENDER_2, DST_EID, config_sender2.clone(),
376
+ );
377
+ stop_cheat_caller_address(contract_address);
378
+
379
+ // Verify different configs for different senders
380
+ let retrieved_config_sender1 = admin.get_raw_oapp_uln_send_config(SENDER, DST_EID);
381
+ let retrieved_config_sender2 = admin.get_raw_oapp_uln_send_config(SENDER_2, DST_EID);
382
+
383
+ assert(
384
+ retrieved_config_sender1.confirmations == config_sender1.confirmations,
385
+ 'Sender1 confirmations incorrect',
386
+ );
387
+ assert(
388
+ retrieved_config_sender2.confirmations == config_sender2.confirmations,
389
+ 'Sender2 confirmations incorrect',
390
+ );
391
+
392
+ // Verify events were emitted
393
+ spy
394
+ .assert_emitted(
395
+ @array![
396
+ (
397
+ contract_address,
398
+ UltraLightNode::Event::OAppUlnSendConfigSet(
399
+ OAppUlnSendConfigSet {
400
+ oapp: SENDER, dst_eid: DST_EID, config: config_sender1,
401
+ },
402
+ ),
403
+ ),
404
+ (
405
+ contract_address,
406
+ UltraLightNode::Event::OAppUlnSendConfigSet(
407
+ OAppUlnSendConfigSet {
408
+ oapp: SENDER_2, dst_eid: DST_EID, config: config_sender2,
409
+ },
410
+ ),
411
+ ),
412
+ ],
413
+ );
414
+ }
415
+
416
+ #[test]
417
+ fn test_set_and_get_raw_oapp_executor_config_multiple_senders() {
418
+ let (admin, contract_address) = deploy_ultra_light_node();
419
+
420
+ // First set default config as owner (required for EID to be supported)
421
+ setup_default_config(admin, contract_address, DST_EID);
422
+
423
+ // Set configs for different senders
424
+ let config_sender1 = ExecutorConfig { max_message_size: 800, executor: EXECUTOR };
425
+ let config_sender2 = ExecutorConfig { max_message_size: 1200, executor: EXECUTOR_2 };
426
+
427
+ // Set up event spy
428
+ let mut spy = spy_events();
429
+
430
+ // Set config for SENDER
431
+ start_cheat_caller_address(contract_address, ENDPOINT);
432
+ set_oapp_executor_send_config_via_message_lib(
433
+ contract_address, SENDER, DST_EID, config_sender1.clone(),
434
+ );
435
+
436
+ set_oapp_executor_send_config_via_message_lib(
437
+ contract_address, SENDER_2, DST_EID, config_sender2.clone(),
438
+ );
439
+ stop_cheat_caller_address(contract_address);
440
+
441
+ // Verify different configs for different senders
442
+ let retrieved_config_sender1 = admin.get_raw_oapp_executor_config(SENDER, DST_EID);
443
+ let retrieved_config_sender2 = admin.get_raw_oapp_executor_config(SENDER_2, DST_EID);
444
+
445
+ assert(
446
+ retrieved_config_sender1.max_message_size == config_sender1.max_message_size,
447
+ 'Sender1 size incorrect',
448
+ );
449
+ assert(retrieved_config_sender1.executor == EXECUTOR, 'Sender1 executor incorrect');
450
+ assert(
451
+ retrieved_config_sender2.max_message_size == config_sender2.max_message_size,
452
+ 'Sender2 size incorrect',
453
+ );
454
+ assert(retrieved_config_sender2.executor == EXECUTOR_2, 'Sender2 executor incorrect');
455
+
456
+ // Verify events were emitted
457
+ spy
458
+ .assert_emitted(
459
+ @array![
460
+ (
461
+ contract_address,
462
+ UltraLightNode::Event::OAppExecutorConfigSet(
463
+ OAppExecutorConfigSet {
464
+ oapp: SENDER, dst_eid: DST_EID, config: config_sender1,
465
+ },
466
+ ),
467
+ ),
468
+ (
469
+ contract_address,
470
+ UltraLightNode::Event::OAppExecutorConfigSet(
471
+ OAppExecutorConfigSet {
472
+ oapp: SENDER_2, dst_eid: DST_EID, config: config_sender2,
473
+ },
474
+ ),
475
+ ),
476
+ ],
477
+ );
478
+ }
479
+
480
+ #[test]
481
+ fn test_oapp_config_overrides_default() {
482
+ let (admin, contract_address) = deploy_ultra_light_node();
483
+
484
+ start_cheat_caller_address(contract_address, OWNER);
485
+
486
+ // Set default config
487
+ let default_config = UlnConfig {
488
+ confirmations: 10,
489
+ has_confirmations: true,
490
+ required_dvns: array![DVN_1],
491
+ has_required_dvns: true,
492
+ optional_dvns: array![DVN_3],
493
+ optional_dvn_threshold: 1,
494
+ has_optional_dvns: true,
495
+ };
496
+ let config_params = array![
497
+ SetDefaultUlnConfigParam { eid: DST_EID, config: default_config.clone() },
498
+ ];
499
+ admin.set_default_uln_send_config(config_params);
500
+
501
+ stop_cheat_caller_address(contract_address);
502
+
503
+ // Set OApp-specific config that should override default
504
+ let oapp_config = UlnConfig {
505
+ confirmations: 20,
506
+ has_confirmations: true,
507
+ required_dvns: array![DVN_2],
508
+ has_required_dvns: true,
509
+ optional_dvns: array![],
510
+ optional_dvn_threshold: 0,
511
+ has_optional_dvns: true,
512
+ };
513
+
514
+ // Set up event spy for OApp config
515
+ let mut oapp_spy = spy_events();
516
+
517
+ // Set config as SENDER
518
+ start_cheat_caller_address(contract_address, ENDPOINT);
519
+ set_oapp_uln_send_config_via_message_lib(
520
+ contract_address, SENDER, DST_EID, oapp_config.clone(),
521
+ );
522
+ stop_cheat_caller_address(contract_address);
523
+
524
+ // Verify that default and OApp effective configs are different
525
+ let oapp_effective_config = admin.get_oapp_uln_send_config(SENDER, DST_EID);
526
+
527
+ assert(
528
+ oapp_effective_config.confirmations == oapp_config.confirmations,
529
+ 'OApp confirmations incorrect',
530
+ );
531
+ assert(
532
+ oapp_effective_config.required_dvns.len() == oapp_config.required_dvns.len(),
533
+ 'OApp DVNs count incorrect',
534
+ );
535
+ assert(
536
+ *oapp_effective_config.required_dvns.at(0) == *oapp_config.required_dvns.at(0),
537
+ 'OApp DVN incorrect',
538
+ );
539
+
540
+ // Check that a different sender would get the default config (not overridden)
541
+ let other_sender_effective_config = admin.get_oapp_uln_send_config(SENDER_2, DST_EID);
542
+ assert(
543
+ other_sender_effective_config.confirmations == default_config.confirmations,
544
+ 'Other sender should get default',
545
+ );
546
+ assert(
547
+ *other_sender_effective_config.required_dvns.at(0) == *default_config.required_dvns.at(0),
548
+ 'Sender2 should get default DVN',
549
+ );
550
+
551
+ // Verify OApp config event was emitted
552
+ oapp_spy
553
+ .assert_emitted(
554
+ @array![
555
+ (
556
+ contract_address,
557
+ UltraLightNode::Event::OAppUlnSendConfigSet(
558
+ OAppUlnSendConfigSet {
559
+ oapp: SENDER, dst_eid: DST_EID, config: oapp_config,
560
+ },
561
+ ),
562
+ ),
563
+ ],
564
+ );
565
+ }
566
+
567
+ #[test]
568
+ fn test_oapp_config_partial_override() {
569
+ let (admin, contract_address) = deploy_ultra_light_node();
570
+
571
+ start_cheat_caller_address(contract_address, OWNER);
572
+
573
+ // Set default config with all fields populated
574
+ let default_config = UlnConfig {
575
+ confirmations: 15,
576
+ has_confirmations: true,
577
+ required_dvns: array![DVN_1, DVN_2],
578
+ has_required_dvns: true,
579
+ optional_dvns: array![DVN_3],
580
+ optional_dvn_threshold: 1,
581
+ has_optional_dvns: true,
582
+ };
583
+ let config_params = array![
584
+ SetDefaultUlnConfigParam { eid: DST_EID, config: default_config.clone() },
585
+ ];
586
+ admin.set_default_uln_send_config(config_params);
587
+
588
+ stop_cheat_caller_address(contract_address);
589
+
590
+ // Set OApp-specific config that only overrides some fields
591
+ let partial_oapp_config = UlnConfig {
592
+ confirmations: 25, // Override confirmations
593
+ has_confirmations: true,
594
+ required_dvns: array![], // Don't override required DVNs (use default)
595
+ has_required_dvns: false, // This means use default
596
+ optional_dvns: array![DVN_1, DVN_2], // Override optional DVNs
597
+ optional_dvn_threshold: 2, // Override optional threshold
598
+ has_optional_dvns: true,
599
+ };
600
+
601
+ // Set up event spy for OApp config
602
+ let mut oapp_spy = spy_events();
603
+
604
+ // Set config as SENDER
605
+ start_cheat_caller_address(contract_address, ENDPOINT);
606
+ set_oapp_uln_send_config_via_message_lib(
607
+ contract_address, SENDER, DST_EID, partial_oapp_config.clone(),
608
+ );
609
+ stop_cheat_caller_address(contract_address);
610
+
611
+ // Get the effective config (resolved)
612
+ let effective_config = admin.get_oapp_uln_send_config(SENDER, DST_EID);
613
+
614
+ // Verify partial override behavior:
615
+ // - confirmations should be overridden (25, not 15)
616
+ // - required_dvns should use default (DVN_1, DVN_2 from default, not empty from oapp)
617
+ // - optional_dvns should be overridden (DVN_1, DVN_2 from oapp, not DVN_3 from default)
618
+ // - optional_dvn_threshold should be overridden (2, not 1)
619
+
620
+ assert(
621
+ effective_config.confirmations == partial_oapp_config.confirmations,
622
+ 'Confirmations not overridden',
623
+ );
624
+ assert(
625
+ effective_config.required_dvns.len() == default_config.required_dvns.len(),
626
+ 'Required DVNs not default',
627
+ );
628
+ assert(
629
+ *effective_config.required_dvns.at(0) == *default_config.required_dvns.at(0),
630
+ 'Required DVN[0] not default',
631
+ );
632
+ assert(
633
+ *effective_config.required_dvns.at(1) == *default_config.required_dvns.at(1),
634
+ 'Required DVN[1] not default',
635
+ );
636
+ assert(
637
+ effective_config.optional_dvns.len() == partial_oapp_config.optional_dvns.len(),
638
+ 'Optional DVNs not overridden',
639
+ );
640
+ assert(
641
+ *effective_config.optional_dvns.at(0) == *partial_oapp_config.optional_dvns.at(0),
642
+ 'Optional DVN[0] not overridden',
643
+ );
644
+ assert(
645
+ *effective_config.optional_dvns.at(1) == *partial_oapp_config.optional_dvns.at(1),
646
+ 'Optional DVN[1] not overridden',
647
+ );
648
+ assert(
649
+ effective_config.optional_dvn_threshold == partial_oapp_config.optional_dvn_threshold,
650
+ 'Optional thresh not overridden',
651
+ );
652
+
653
+ // Verify that another sender gets the full default config
654
+ let other_sender_effective_config = admin.get_oapp_uln_send_config(SENDER_2, DST_EID);
655
+ assert(
656
+ other_sender_effective_config.confirmations == default_config.confirmations,
657
+ 'Sender2 confms != default',
658
+ );
659
+ assert(
660
+ other_sender_effective_config.required_dvns.len() == default_config.required_dvns.len(),
661
+ 'Sender2 reqDVNs != default',
662
+ );
663
+ assert(
664
+ other_sender_effective_config.optional_dvns.len() == default_config.optional_dvns.len(),
665
+ 'Sender2 optDVNs != default',
666
+ );
667
+ assert(
668
+ *other_sender_effective_config.optional_dvns.at(0) == *default_config.optional_dvns.at(0),
669
+ 'Sender2 optDVN != default',
670
+ );
671
+ assert(
672
+ other_sender_effective_config
673
+ .optional_dvn_threshold == default_config
674
+ .optional_dvn_threshold,
675
+ 'Sender2 thresh != default',
676
+ );
677
+
678
+ // Verify OApp config event was emitted
679
+ oapp_spy
680
+ .assert_emitted(
681
+ @array![
682
+ (
683
+ contract_address,
684
+ UltraLightNode::Event::OAppUlnSendConfigSet(
685
+ OAppUlnSendConfigSet {
686
+ oapp: SENDER, dst_eid: DST_EID, config: partial_oapp_config,
687
+ },
688
+ ),
689
+ ),
690
+ ],
691
+ );
692
+ }
693
+
694
+ #[test]
695
+ fn test_oapp_config_partial_override_with_false_has_flags() {
696
+ let (admin, contract_address) = deploy_ultra_light_node();
697
+
698
+ start_cheat_caller_address(contract_address, OWNER);
699
+
700
+ // Set default config with all fields populated
701
+ let default_config = UlnConfig {
702
+ confirmations: 15,
703
+ has_confirmations: true,
704
+ required_dvns: array![DVN_1, DVN_2],
705
+ has_required_dvns: true,
706
+ optional_dvns: array![DVN_3],
707
+ optional_dvn_threshold: 1,
708
+ has_optional_dvns: true,
709
+ };
710
+ let config_params = array![
711
+ SetDefaultUlnConfigParam { eid: DST_EID, config: default_config.clone() },
712
+ ];
713
+ admin.set_default_uln_send_config(config_params);
714
+
715
+ stop_cheat_caller_address(contract_address);
716
+
717
+ // Set OApp-specific config with has_required_dvns = false
718
+ // Even if we provide values in required_dvns, they should be ignored
719
+ let partial_oapp_config = UlnConfig {
720
+ confirmations: 25, // Override confirmations
721
+ has_confirmations: true,
722
+ required_dvns: array![DVN_3], // This should be ignored since has_required_dvns = false
723
+ has_required_dvns: false, // This means use default required DVNs
724
+ optional_dvns: array![], // Don't override optional DVNs (use default)
725
+ optional_dvn_threshold: 0, // Don't override optional threshold (use default)
726
+ has_optional_dvns: false // This means use default optional DVNs
727
+ };
728
+
729
+ // Set up event spy for OApp config
730
+ let mut oapp_spy = spy_events();
731
+
732
+ // Set config as SENDER
733
+ start_cheat_caller_address(contract_address, ENDPOINT);
734
+ set_oapp_uln_send_config_via_message_lib(
735
+ contract_address, SENDER, DST_EID, partial_oapp_config.clone(),
736
+ );
737
+ stop_cheat_caller_address(contract_address);
738
+
739
+ // Get the effective config (resolved)
740
+ let effective_config = admin.get_oapp_uln_send_config(SENDER, DST_EID);
741
+
742
+ // Verify that when has_required_dvns = false, the default required DVNs are used
743
+ // NOT the values provided in the OApp config's required_dvns array
744
+ assert(
745
+ effective_config.confirmations == partial_oapp_config.confirmations,
746
+ 'Confirmations not overridden',
747
+ );
748
+ assert(
749
+ effective_config.required_dvns.len() == default_config.required_dvns.len(),
750
+ 'RequiredDVNs dont default',
751
+ );
752
+ assert(
753
+ *effective_config.required_dvns.at(0) == *default_config.required_dvns.at(0),
754
+ 'Required DVN[0] not default',
755
+ );
756
+ assert(
757
+ *effective_config.required_dvns.at(1) == *default_config.required_dvns.at(1),
758
+ 'Required DVN[1] not default',
759
+ );
760
+ // Verify that the OApp config's required_dvns values were ignored
761
+ assert(
762
+ *effective_config.required_dvns.at(0) != *partial_oapp_config.required_dvns.at(0),
763
+ 'OApp required DVNs not ignored',
764
+ );
765
+
766
+ // Verify that optional DVNs also use default when has_optional_dvns = false
767
+ assert(
768
+ effective_config.optional_dvns.len() == default_config.optional_dvns.len(),
769
+ 'Optional DVNs not default',
770
+ );
771
+ assert(
772
+ *effective_config.optional_dvns.at(0) == *default_config.optional_dvns.at(0),
773
+ 'Optional DVN not default',
774
+ );
775
+ assert(
776
+ effective_config.optional_dvn_threshold == default_config.optional_dvn_threshold,
777
+ 'Optional threshold not default',
778
+ );
779
+
780
+ // Verify that another sender gets the same default config
781
+ let other_sender_effective_config = admin.get_oapp_uln_send_config(SENDER_2, DST_EID);
782
+ assert(
783
+ other_sender_effective_config.confirmations == default_config.confirmations,
784
+ 'Sender2 confms != default',
785
+ );
786
+ assert(
787
+ other_sender_effective_config.required_dvns.len() == default_config.required_dvns.len(),
788
+ 'Sender2 reqDVNs != default',
789
+ );
790
+
791
+ // Verify OApp config event was emitted with the original config (including ignored values)
792
+ oapp_spy
793
+ .assert_emitted(
794
+ @array![
795
+ (
796
+ contract_address,
797
+ UltraLightNode::Event::OAppUlnSendConfigSet(
798
+ OAppUlnSendConfigSet {
799
+ oapp: SENDER, dst_eid: DST_EID, config: partial_oapp_config,
800
+ },
801
+ ),
802
+ ),
803
+ ],
804
+ );
805
+ }
806
+
807
+ #[test]
808
+ fn test_treasury_getter() {
809
+ let (admin, _) = deploy_ultra_light_node();
810
+
811
+ let treasury = admin.get_treasury();
812
+ assert(treasury != 0.try_into().unwrap(), 'Treasury should be set');
813
+ }
814
+
815
+ #[test]
816
+ fn test_empty_configs_return_defaults() {
817
+ let (admin, _) = deploy_ultra_light_node();
818
+
819
+ // Getting configs that were never set should return empty/default values
820
+ let empty_uln_config = admin.get_default_uln_send_config(DST_EID);
821
+ let empty_executor_config = admin.get_default_executor_config(DST_EID);
822
+ let empty_oapp_uln_config = admin.get_raw_oapp_uln_send_config(SENDER, DST_EID);
823
+ let empty_oapp_executor_config = admin.get_raw_oapp_executor_config(SENDER, DST_EID);
824
+
825
+ // These should be empty/default values
826
+ assert(empty_uln_config.confirmations == 0, 'Default ULN should be empty');
827
+ assert(empty_uln_config.required_dvns.len() == 0, 'Default ULN dvns != empty');
828
+ assert(empty_executor_config.max_message_size == 0, 'Default executor != empty');
829
+ assert(empty_oapp_uln_config.confirmations == 0, 'OApp ULN should be empty');
830
+ assert(empty_oapp_executor_config.max_message_size == 0, 'OApp executor should be empty');
831
+ }
832
+
833
+ #[test]
834
+ #[feature("safe_dispatcher")]
835
+ fn test_cannot_set_oapp_uln_send_config_without_default_config() {
836
+ let (_, contract_address) = deploy_ultra_light_node_safe();
837
+ let uln_config = create_test_uln_config();
838
+
839
+ // Try to set OApp config without setting default config first
840
+ start_cheat_caller_address(contract_address, ENDPOINT);
841
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
842
+ let param = create_uln_send_config_param(DST_EID, SENDER, uln_config);
843
+ let result = message_lib.set_send_config(SENDER, array![param]);
844
+ assert_panic_with_error(result, err_unsupported_send_eid(DST_EID));
845
+ stop_cheat_caller_address(contract_address);
846
+ }
847
+
848
+ #[test]
849
+ #[feature("safe_dispatcher")]
850
+ fn test_cannot_set_oapp_executor_config_without_default_config() {
851
+ let (_, contract_address) = deploy_ultra_light_node_safe();
852
+ let executor_config = create_test_executor_config();
853
+
854
+ // Try to set OApp executor config without setting default config first
855
+ start_cheat_caller_address(contract_address, ENDPOINT);
856
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
857
+ let param = create_executor_send_config_param(DST_EID, SENDER, executor_config);
858
+ let result = message_lib.set_send_config(SENDER, array![param]);
859
+ assert_panic_with_error(result, err_unsupported_send_eid(DST_EID));
860
+ stop_cheat_caller_address(contract_address);
861
+ }
862
+
863
+ #[test]
864
+ fn test_eid_with_optional_dvn_threshold_is_supported() {
865
+ let (admin, contract_address) = deploy_ultra_light_node();
866
+ let uln_config = create_test_uln_config();
867
+
868
+ // Set default config with only optional DVN threshold (no required DVNs)
869
+ start_cheat_caller_address(contract_address, OWNER);
870
+ let default_config_with_optional = UlnConfig {
871
+ confirmations: 10,
872
+ has_confirmations: true,
873
+ required_dvns: array![], // No required DVNs
874
+ has_required_dvns: true,
875
+ optional_dvns: array![DVN_1, DVN_2], // Has optional DVNs
876
+ optional_dvn_threshold: 1, // Has optional threshold > 0
877
+ has_optional_dvns: true,
878
+ };
879
+ let config_params = array![
880
+ SetDefaultUlnConfigParam { eid: DST_EID, config: default_config_with_optional },
881
+ ];
882
+ admin.set_default_uln_send_config(config_params);
883
+ stop_cheat_caller_address(contract_address);
884
+
885
+ // Should be able to set OApp config because EID is supported (has optional threshold > 0)
886
+ start_cheat_caller_address(contract_address, ENDPOINT);
887
+ set_oapp_uln_send_config_via_message_lib(contract_address, SENDER, DST_EID, uln_config.clone());
888
+
889
+ // Verify config was set
890
+ let retrieved_config = admin.get_raw_oapp_uln_send_config(SENDER, DST_EID);
891
+ assert(
892
+ retrieved_config.confirmations == uln_config.confirmations, 'OApp config not set correctly',
893
+ );
894
+
895
+ stop_cheat_caller_address(contract_address);
896
+ }
897
+
898
+ #[test]
899
+ #[feature("safe_dispatcher")]
900
+ fn test_set_default_uln_send_config_fails_with_duplicate_required_dvns() {
901
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
902
+
903
+ // Create config with duplicate required DVNs
904
+ let config_with_duplicate_required = UlnConfig {
905
+ confirmations: 10,
906
+ has_confirmations: true,
907
+ required_dvns: array![DVN_1, DVN_1], // Duplicate DVN_1
908
+ has_required_dvns: true,
909
+ optional_dvns: array![DVN_2],
910
+ optional_dvn_threshold: 1,
911
+ has_optional_dvns: true,
912
+ };
913
+
914
+ let config_params = array![
915
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_duplicate_required },
916
+ ];
917
+
918
+ // Try to set default config with duplicate required DVNs - should fail
919
+ start_cheat_caller_address(contract_address, OWNER);
920
+ let result = admin_safe.set_default_uln_send_config(config_params);
921
+ assert_panic_with_error(result, err_unsorted_dvns());
922
+ stop_cheat_caller_address(contract_address);
923
+ }
924
+
925
+ #[test]
926
+ #[feature("safe_dispatcher")]
927
+ fn test_set_default_uln_send_config_fails_with_duplicate_optional_dvns() {
928
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
929
+
930
+ // Create config with duplicate optional DVNs
931
+ let config_with_duplicate_optional = UlnConfig {
932
+ confirmations: 10,
933
+ has_confirmations: true,
934
+ required_dvns: array![DVN_1],
935
+ has_required_dvns: true,
936
+ optional_dvns: array![DVN_2, DVN_2], // Duplicate DVN_2
937
+ optional_dvn_threshold: 1,
938
+ has_optional_dvns: true,
939
+ };
940
+
941
+ let config_params = array![
942
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_duplicate_optional },
943
+ ];
944
+
945
+ // Try to set default config with duplicate optional DVNs - should fail
946
+ start_cheat_caller_address(contract_address, OWNER);
947
+ let result = admin_safe.set_default_uln_send_config(config_params);
948
+ assert_panic_with_error(result, err_unsorted_dvns());
949
+ stop_cheat_caller_address(contract_address);
950
+ }
951
+
952
+ #[test]
953
+ #[feature("safe_dispatcher")]
954
+ fn test_set_default_uln_send_config_fails_with_unsorted_required_dvns() {
955
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
956
+
957
+ // Create config with unsorted required DVNs (DVN_2 < DVN_1)
958
+ let config_with_unsorted_required = UlnConfig {
959
+ confirmations: 10,
960
+ has_confirmations: true,
961
+ required_dvns: array![DVN_2, DVN_1], // Unsorted: DVN_2 should come after DVN_1
962
+ has_required_dvns: true,
963
+ optional_dvns: array![],
964
+ optional_dvn_threshold: 0,
965
+ has_optional_dvns: true,
966
+ };
967
+
968
+ let config_params = array![
969
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_unsorted_required },
970
+ ];
971
+
972
+ // Try to set default config with unsorted required DVNs - should fail
973
+ start_cheat_caller_address(contract_address, OWNER);
974
+ let result = admin_safe.set_default_uln_send_config(config_params);
975
+ assert_panic_with_error(result, err_unsorted_dvns());
976
+ stop_cheat_caller_address(contract_address);
977
+ }
978
+
979
+ #[test]
980
+ #[feature("safe_dispatcher")]
981
+ fn test_set_default_uln_send_config_fails_with_unsorted_optional_dvns() {
982
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
983
+
984
+ // Create config with unsorted optional DVNs (DVN_2 < DVN_1)
985
+ let config_with_unsorted_optional = UlnConfig {
986
+ confirmations: 10,
987
+ has_confirmations: true,
988
+ required_dvns: array![],
989
+ has_required_dvns: true,
990
+ optional_dvns: array![DVN_2, DVN_1], // Unsorted: DVN_2 should come after DVN_1
991
+ optional_dvn_threshold: 1,
992
+ has_optional_dvns: true,
993
+ };
994
+
995
+ let config_params = array![
996
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_unsorted_optional },
997
+ ];
998
+
999
+ // Try to set default config with unsorted optional DVNs - should fail
1000
+ start_cheat_caller_address(contract_address, OWNER);
1001
+ let result = admin_safe.set_default_uln_send_config(config_params);
1002
+ assert_panic_with_error(result, err_unsorted_dvns());
1003
+ stop_cheat_caller_address(contract_address);
1004
+ }
1005
+
1006
+ #[test]
1007
+ #[feature("safe_dispatcher")]
1008
+ fn test_set_default_uln_send_config_fails_with_invalid_optional_threshold() {
1009
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
1010
+
1011
+ // Create config with invalid optional threshold (threshold > optional DVN count)
1012
+ let config_with_invalid_threshold = UlnConfig {
1013
+ confirmations: 10,
1014
+ has_confirmations: true,
1015
+ required_dvns: array![],
1016
+ has_required_dvns: true,
1017
+ optional_dvns: array![DVN_1], // Only 1 optional DVN
1018
+ optional_dvn_threshold: 2, // But threshold is 2
1019
+ has_optional_dvns: true,
1020
+ };
1021
+
1022
+ let config_params = array![
1023
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_invalid_threshold },
1024
+ ];
1025
+
1026
+ // Try to set default config with invalid optional threshold - should fail
1027
+ start_cheat_caller_address(contract_address, OWNER);
1028
+ let result = admin_safe.set_default_uln_send_config(config_params);
1029
+ assert_panic_with_error(result, err_invalid_optional_dvn_threshold(1, 2));
1030
+ stop_cheat_caller_address(contract_address);
1031
+ }
1032
+
1033
+ #[test]
1034
+ #[feature("safe_dispatcher")]
1035
+ fn test_set_default_uln_send_config_fails_with_zero_threshold_but_optional_dvns() {
1036
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
1037
+
1038
+ // Create config with optional DVNs but zero threshold
1039
+ let config_with_zero_threshold = UlnConfig {
1040
+ confirmations: 10,
1041
+ has_confirmations: true,
1042
+ required_dvns: array![DVN_3],
1043
+ has_required_dvns: true,
1044
+ optional_dvns: array![DVN_1, DVN_2], // Has optional DVNs
1045
+ optional_dvn_threshold: 0, // But threshold is 0
1046
+ has_optional_dvns: true,
1047
+ };
1048
+
1049
+ let config_params = array![
1050
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_zero_threshold },
1051
+ ];
1052
+
1053
+ // Try to set default config with zero threshold but optional DVNs - should fail
1054
+ start_cheat_caller_address(contract_address, OWNER);
1055
+ let result = admin_safe.set_default_uln_send_config(config_params);
1056
+ assert_panic_with_error(result, err_invalid_optional_dvn_threshold(2, 0));
1057
+ stop_cheat_caller_address(contract_address);
1058
+ }
1059
+
1060
+ #[test]
1061
+ #[feature("safe_dispatcher")]
1062
+ fn test_set_default_uln_send_config_fails_with_too_many_dvns() {
1063
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
1064
+
1065
+ // Create config with too many DVNs (exceeding MAX_DVN_COUNT = 255)
1066
+ let mut too_many_required_dvns = array![];
1067
+ let mut too_many_optional_dvns = array![];
1068
+
1069
+ // Add 200 required DVNs
1070
+ let mut i = 1;
1071
+ while i != 201 {
1072
+ too_many_required_dvns.append(i.try_into().unwrap());
1073
+ i += 1;
1074
+ }
1075
+
1076
+ // Add 100 optional DVNs (total = 300 > 255)
1077
+ let mut j = 202;
1078
+ while j != 302 {
1079
+ too_many_optional_dvns.append(j.try_into().unwrap());
1080
+ j += 1;
1081
+ }
1082
+
1083
+ let config_with_too_many_dvns = UlnConfig {
1084
+ confirmations: 10,
1085
+ has_confirmations: true,
1086
+ required_dvns: too_many_required_dvns,
1087
+ has_required_dvns: true,
1088
+ optional_dvns: too_many_optional_dvns,
1089
+ optional_dvn_threshold: 50,
1090
+ has_optional_dvns: true,
1091
+ };
1092
+
1093
+ let config_params = array![
1094
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_too_many_dvns },
1095
+ ];
1096
+
1097
+ // Try to set default config with too many DVNs - should fail
1098
+ start_cheat_caller_address(contract_address, OWNER);
1099
+ let result = admin_safe.set_default_uln_send_config(config_params);
1100
+ assert_panic_with_error(result, err_too_many_dvns(200, 100));
1101
+ stop_cheat_caller_address(contract_address);
1102
+ }
1103
+
1104
+ #[test]
1105
+ #[feature("safe_dispatcher")]
1106
+ fn test_set_default_uln_send_config_fails_with_zero_confirmations() {
1107
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
1108
+
1109
+ // Create config with zero confirmations
1110
+ let config_with_zero_confirmations = UlnConfig {
1111
+ confirmations: 0, // Invalid: confirmations must be > 0
1112
+ has_confirmations: true,
1113
+ required_dvns: array![DVN_1],
1114
+ has_required_dvns: true,
1115
+ optional_dvns: array![],
1116
+ optional_dvn_threshold: 0,
1117
+ has_optional_dvns: true,
1118
+ };
1119
+
1120
+ let config_params = array![
1121
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_zero_confirmations },
1122
+ ];
1123
+
1124
+ // Try to set default config with zero confirmations - should fail
1125
+ start_cheat_caller_address(contract_address, OWNER);
1126
+ let result = admin_safe.set_default_uln_send_config(config_params);
1127
+ assert_panic_with_error(result, err_invalid_confirmations());
1128
+ stop_cheat_caller_address(contract_address);
1129
+ }
1130
+
1131
+ #[test]
1132
+ #[feature("safe_dispatcher")]
1133
+ fn test_set_default_uln_send_config_fails_with_no_dvns() {
1134
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
1135
+
1136
+ // Create config with no DVNs and no optional threshold
1137
+ let config_with_no_dvns = UlnConfig {
1138
+ confirmations: 10,
1139
+ has_confirmations: true,
1140
+ required_dvns: array![], // No required DVNs
1141
+ has_required_dvns: true,
1142
+ optional_dvns: array![], // No optional DVNs
1143
+ optional_dvn_threshold: 0, // No optional threshold
1144
+ has_optional_dvns: true,
1145
+ };
1146
+
1147
+ let config_params = array![
1148
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_no_dvns },
1149
+ ];
1150
+
1151
+ // Try to set default config with no DVNs - should fail
1152
+ start_cheat_caller_address(contract_address, OWNER);
1153
+ let result = admin_safe.set_default_uln_send_config(config_params);
1154
+ assert_panic_with_error(result, err_must_have_at_least_one_dvn());
1155
+ stop_cheat_caller_address(contract_address);
1156
+ }
1157
+
1158
+ #[test]
1159
+ #[feature("safe_dispatcher")]
1160
+ fn test_set_oapp_uln_send_config_fails_with_duplicate_required_dvns() {
1161
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1162
+
1163
+ // First set default config as owner (required for EID to be supported)
1164
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1165
+
1166
+ // Create config with duplicate required DVNs
1167
+ let config_with_duplicate_required = UlnConfig {
1168
+ confirmations: 10,
1169
+ has_confirmations: true,
1170
+ required_dvns: array![DVN_1, DVN_1], // Duplicate DVN_1
1171
+ has_required_dvns: true,
1172
+ optional_dvns: array![DVN_2],
1173
+ optional_dvn_threshold: 1,
1174
+ has_optional_dvns: true,
1175
+ };
1176
+
1177
+ // Try to set OApp config with duplicate required DVNs - should fail
1178
+ start_cheat_caller_address(contract_address, ENDPOINT);
1179
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1180
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_duplicate_required);
1181
+ let result = message_lib.set_send_config(SENDER, array![param]);
1182
+ assert_panic_with_error(result, err_unsorted_dvns());
1183
+ stop_cheat_caller_address(contract_address);
1184
+ }
1185
+
1186
+ #[test]
1187
+ #[feature("safe_dispatcher")]
1188
+ fn test_set_oapp_uln_send_config_fails_with_duplicate_optional_dvns() {
1189
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1190
+
1191
+ // First set default config as owner (required for EID to be supported)
1192
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1193
+
1194
+ // Create config with duplicate optional DVNs
1195
+ let config_with_duplicate_optional = UlnConfig {
1196
+ confirmations: 10,
1197
+ has_confirmations: true,
1198
+ required_dvns: array![DVN_1],
1199
+ has_required_dvns: true,
1200
+ optional_dvns: array![DVN_2, DVN_2], // Duplicate DVN_2
1201
+ optional_dvn_threshold: 1,
1202
+ has_optional_dvns: true,
1203
+ };
1204
+
1205
+ // Try to set OApp config with duplicate optional DVNs - should fail
1206
+ start_cheat_caller_address(contract_address, ENDPOINT);
1207
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1208
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_duplicate_optional);
1209
+ let result = message_lib.set_send_config(SENDER, array![param]);
1210
+ assert_panic_with_error(result, err_unsorted_dvns());
1211
+ stop_cheat_caller_address(contract_address);
1212
+ }
1213
+
1214
+ #[test]
1215
+ #[feature("safe_dispatcher")]
1216
+ fn test_set_oapp_uln_send_config_fails_with_unsorted_required_dvns() {
1217
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1218
+
1219
+ // First set default config as owner (required for EID to be supported)
1220
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1221
+
1222
+ // Create config with unsorted required DVNs (DVN_2 < DVN_1)
1223
+ let config_with_unsorted_required = UlnConfig {
1224
+ confirmations: 10,
1225
+ has_confirmations: true,
1226
+ required_dvns: array![DVN_2, DVN_1], // Unsorted: DVN_2 should come after DVN_1
1227
+ has_required_dvns: true,
1228
+ optional_dvns: array![],
1229
+ optional_dvn_threshold: 0,
1230
+ has_optional_dvns: true,
1231
+ };
1232
+
1233
+ // Try to set OApp config with unsorted required DVNs - should fail
1234
+ start_cheat_caller_address(contract_address, ENDPOINT);
1235
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1236
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_unsorted_required);
1237
+ let result = message_lib.set_send_config(SENDER, array![param]);
1238
+ assert_panic_with_error(result, err_unsorted_dvns());
1239
+ stop_cheat_caller_address(contract_address);
1240
+ }
1241
+
1242
+ #[test]
1243
+ #[feature("safe_dispatcher")]
1244
+ fn test_set_oapp_uln_send_config_fails_with_unsorted_optional_dvns() {
1245
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1246
+
1247
+ // First set default config as owner (required for EID to be supported)
1248
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1249
+
1250
+ // Create config with unsorted optional DVNs (DVN_2 < DVN_1)
1251
+ let config_with_unsorted_optional = UlnConfig {
1252
+ confirmations: 10,
1253
+ has_confirmations: true,
1254
+ required_dvns: array![],
1255
+ has_required_dvns: true,
1256
+ optional_dvns: array![DVN_2, DVN_1], // Unsorted: DVN_2 should come after DVN_1
1257
+ optional_dvn_threshold: 1,
1258
+ has_optional_dvns: true,
1259
+ };
1260
+
1261
+ // Try to set OApp config with unsorted optional DVNs - should fail
1262
+ start_cheat_caller_address(contract_address, ENDPOINT);
1263
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1264
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_unsorted_optional);
1265
+ let result = message_lib.set_send_config(SENDER, array![param]);
1266
+ assert_panic_with_error(result, err_unsorted_dvns());
1267
+ stop_cheat_caller_address(contract_address);
1268
+ }
1269
+
1270
+ #[test]
1271
+ #[feature("safe_dispatcher")]
1272
+ fn test_set_oapp_uln_send_config_fails_when_resolved_config_has_no_dvns_and_default_has_required() {
1273
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1274
+
1275
+ // Set default config with no DVNs and no threshold
1276
+ let admin_regular = IUltraLightNodeAdminDispatcher { contract_address };
1277
+ start_cheat_caller_address(contract_address, OWNER);
1278
+ let invalid_default_config = UlnConfig {
1279
+ confirmations: 10,
1280
+ has_confirmations: true,
1281
+ required_dvns: array![DVN_1], // Default DVNs set, will get overwritten
1282
+ has_required_dvns: true,
1283
+ optional_dvns: array![DVN_3], // Optional DVNs set, will get overwritten
1284
+ optional_dvn_threshold: 1,
1285
+ has_optional_dvns: true,
1286
+ };
1287
+ let config_params = array![
1288
+ SetDefaultUlnConfigParam { eid: DST_EID, config: invalid_default_config },
1289
+ ];
1290
+ admin_regular.set_default_uln_send_config(config_params);
1291
+ stop_cheat_caller_address(contract_address);
1292
+
1293
+ // Try to set OApp config that also has no DVNs - should fail during resolution
1294
+ let oapp_config_no_dvns = UlnConfig {
1295
+ confirmations: 20,
1296
+ has_confirmations: true,
1297
+ required_dvns: array![], // No required DVNs
1298
+ has_required_dvns: true,
1299
+ optional_dvns: array![], // No optional DVNs
1300
+ optional_dvn_threshold: 0, // No optional threshold
1301
+ has_optional_dvns: true,
1302
+ };
1303
+
1304
+ start_cheat_caller_address(contract_address, ENDPOINT);
1305
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1306
+ let param = create_uln_send_config_param(DST_EID, SENDER, oapp_config_no_dvns);
1307
+ let result = message_lib.set_send_config(SENDER, array![param]);
1308
+ assert_panic_with_error(result, err_must_have_at_least_one_dvn());
1309
+ stop_cheat_caller_address(contract_address);
1310
+ }
1311
+
1312
+ #[test]
1313
+ #[feature("safe_dispatcher")]
1314
+ fn test_set_oapp_uln_send_config_fails_when_resolved_config_has_no_dvns_and_default_has_optional() {
1315
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1316
+
1317
+ // Set default config with no DVNs and no threshold
1318
+ let admin_regular = IUltraLightNodeAdminDispatcher { contract_address };
1319
+ start_cheat_caller_address(contract_address, OWNER);
1320
+ let invalid_default_config = UlnConfig {
1321
+ confirmations: 10,
1322
+ has_confirmations: true,
1323
+ required_dvns: array![], // Default DVNs set, will get overwritten
1324
+ has_required_dvns: true,
1325
+ optional_dvns: array![DVN_3], // Optional DVNs set, will get overwritten
1326
+ optional_dvn_threshold: 1,
1327
+ has_optional_dvns: true,
1328
+ };
1329
+ let config_params = array![
1330
+ SetDefaultUlnConfigParam { eid: DST_EID, config: invalid_default_config },
1331
+ ];
1332
+ admin_regular.set_default_uln_send_config(config_params);
1333
+ stop_cheat_caller_address(contract_address);
1334
+
1335
+ // Try to set OApp config that also has no DVNs - should fail during resolution
1336
+ let oapp_config_no_dvns = UlnConfig {
1337
+ confirmations: 20,
1338
+ has_confirmations: true,
1339
+ required_dvns: array![], // No required DVNs
1340
+ has_required_dvns: true,
1341
+ optional_dvns: array![], // No optional DVNs
1342
+ optional_dvn_threshold: 0, // No optional threshold
1343
+ has_optional_dvns: true,
1344
+ };
1345
+
1346
+ start_cheat_caller_address(contract_address, ENDPOINT);
1347
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1348
+ let param = create_uln_send_config_param(DST_EID, SENDER, oapp_config_no_dvns);
1349
+ let result = message_lib.set_send_config(SENDER, array![param]);
1350
+ assert_panic_with_error(result, err_must_have_at_least_one_dvn());
1351
+ stop_cheat_caller_address(contract_address);
1352
+ }
1353
+
1354
+ #[test]
1355
+ #[feature("safe_dispatcher")]
1356
+ fn test_set_oapp_uln_send_config_fails_with_invalid_optional_threshold() {
1357
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1358
+
1359
+ // First set default config as owner (required for EID to be supported)
1360
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1361
+
1362
+ // Create config with invalid optional threshold (threshold > optional DVN count)
1363
+ let config_with_invalid_threshold = UlnConfig {
1364
+ confirmations: 10,
1365
+ has_confirmations: true,
1366
+ required_dvns: array![],
1367
+ has_required_dvns: true,
1368
+ optional_dvns: array![DVN_1], // Only 1 optional DVN
1369
+ optional_dvn_threshold: 2, // But threshold is 2
1370
+ has_optional_dvns: true,
1371
+ };
1372
+
1373
+ // Try to set OApp config with invalid optional threshold - should fail
1374
+ start_cheat_caller_address(contract_address, ENDPOINT);
1375
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1376
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_invalid_threshold);
1377
+ let result = message_lib.set_send_config(SENDER, array![param]);
1378
+ assert_panic_with_error(result, err_invalid_optional_dvn_threshold(1, 2));
1379
+ stop_cheat_caller_address(contract_address);
1380
+ }
1381
+
1382
+ #[test]
1383
+ #[feature("safe_dispatcher")]
1384
+ fn test_set_oapp_uln_send_config_fails_with_zero_threshold_but_optional_dvns() {
1385
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1386
+
1387
+ // First set default config as owner (required for EID to be supported)
1388
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1389
+
1390
+ // Create config with optional DVNs but zero threshold
1391
+ let config_with_zero_threshold = UlnConfig {
1392
+ confirmations: 10,
1393
+ has_confirmations: true,
1394
+ required_dvns: array![DVN_3],
1395
+ has_required_dvns: true,
1396
+ optional_dvns: array![DVN_1, DVN_2], // Has optional DVNs
1397
+ optional_dvn_threshold: 0, // But threshold is 0
1398
+ has_optional_dvns: true,
1399
+ };
1400
+
1401
+ // Try to set OApp config with zero threshold but optional DVNs - should fail
1402
+ start_cheat_caller_address(contract_address, ENDPOINT);
1403
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1404
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_zero_threshold);
1405
+ let result = message_lib.set_send_config(SENDER, array![param]);
1406
+ assert_panic_with_error(result, err_invalid_optional_dvn_threshold(2, 0));
1407
+ stop_cheat_caller_address(contract_address);
1408
+ }
1409
+
1410
+ #[test]
1411
+ #[feature("safe_dispatcher")]
1412
+ fn test_set_oapp_uln_send_config_fails_with_too_many_dvns() {
1413
+ let (_, contract_address) = deploy_ultra_light_node_safe();
1414
+
1415
+ // First set default config as owner (required for EID to be supported)
1416
+ setup_default_config_for_safe_test(contract_address, DST_EID);
1417
+
1418
+ // Create config with too many DVNs (exceeding MAX_DVN_COUNT = 255)
1419
+ let mut too_many_required_dvns = array![];
1420
+ let mut too_many_optional_dvns = array![];
1421
+ // Add 200 required DVNs
1422
+ let mut i = 1;
1423
+ while i != 201 {
1424
+ too_many_required_dvns.append(i.try_into().unwrap());
1425
+ i += 1;
1426
+ }
1427
+
1428
+ // Add 100 optional DVNs (total = 300 > 255)
1429
+ let mut j = 202;
1430
+ while j != 302 {
1431
+ too_many_optional_dvns.append(j.try_into().unwrap());
1432
+ j += 1;
1433
+ }
1434
+
1435
+ let config_with_too_many_dvns = UlnConfig {
1436
+ confirmations: 10,
1437
+ has_confirmations: true,
1438
+ required_dvns: too_many_required_dvns,
1439
+ has_required_dvns: true,
1440
+ optional_dvns: too_many_optional_dvns,
1441
+ optional_dvn_threshold: 50,
1442
+ has_optional_dvns: true,
1443
+ };
1444
+
1445
+ // Try to set OApp config with too many DVNs - should fail
1446
+ start_cheat_caller_address(contract_address, ENDPOINT);
1447
+ let message_lib = IMessageLibSafeDispatcher { contract_address };
1448
+ let param = create_uln_send_config_param(DST_EID, SENDER, config_with_too_many_dvns);
1449
+ let result = message_lib.set_send_config(SENDER, array![param]);
1450
+ assert_panic_with_error(result, err_too_many_dvns(200, 100));
1451
+ stop_cheat_caller_address(contract_address);
1452
+ }
1453
+
1454
+ #[test]
1455
+ fn test_set_oapp_uln_send_config_success_with_valid_config() {
1456
+ let (admin, contract_address) = deploy_ultra_light_node();
1457
+
1458
+ // First set default config as owner (required for EID to be supported)
1459
+ setup_default_config(admin, contract_address, DST_EID);
1460
+
1461
+ // Create a valid config
1462
+ let valid_config = UlnConfig {
1463
+ confirmations: 15,
1464
+ has_confirmations: true,
1465
+ required_dvns: array![DVN_1],
1466
+ has_required_dvns: true,
1467
+ optional_dvns: array![DVN_2],
1468
+ optional_dvn_threshold: 1,
1469
+ has_optional_dvns: true,
1470
+ };
1471
+
1472
+ // Set up event spy
1473
+ let mut spy = spy_events();
1474
+
1475
+ // Set OApp config - should succeed
1476
+ start_cheat_caller_address(contract_address, ENDPOINT);
1477
+ set_oapp_uln_send_config_via_message_lib(
1478
+ contract_address, SENDER, DST_EID, valid_config.clone(),
1479
+ );
1480
+ stop_cheat_caller_address(contract_address);
1481
+
1482
+ // Verify config was set correctly
1483
+ let retrieved_config = admin.get_raw_oapp_uln_send_config(SENDER, DST_EID);
1484
+ assert(
1485
+ retrieved_config.confirmations == valid_config.confirmations,
1486
+ 'Confirmations not set correctly',
1487
+ );
1488
+ assert(
1489
+ retrieved_config.required_dvns.len() == valid_config.required_dvns.len(),
1490
+ 'Required DVNs not set correctly',
1491
+ );
1492
+ assert(
1493
+ retrieved_config.optional_dvns.len() == valid_config.optional_dvns.len(),
1494
+ 'Optional DVNs not set correctly',
1495
+ );
1496
+ assert(
1497
+ retrieved_config.optional_dvn_threshold == valid_config.optional_dvn_threshold,
1498
+ 'Optional threshold incorrect',
1499
+ );
1500
+
1501
+ // Verify event was emitted
1502
+ spy
1503
+ .assert_emitted(
1504
+ @array![
1505
+ (
1506
+ contract_address,
1507
+ UltraLightNode::Event::OAppUlnSendConfigSet(
1508
+ OAppUlnSendConfigSet {
1509
+ oapp: SENDER, dst_eid: DST_EID, config: valid_config,
1510
+ },
1511
+ ),
1512
+ ),
1513
+ ],
1514
+ );
1515
+ }
1516
+
1517
+ #[test]
1518
+ fn test_set_oapp_executor_config_success_with_valid_config() {
1519
+ let (admin, contract_address) = deploy_ultra_light_node();
1520
+
1521
+ // First set default config as owner (required for EID to be supported)
1522
+ setup_default_config(admin, contract_address, DST_EID);
1523
+
1524
+ // Create a valid executor config
1525
+ let valid_executor_config = ExecutorConfig { max_message_size: 2000, executor: EXECUTOR };
1526
+
1527
+ // Set up event spy
1528
+ let mut spy = spy_events();
1529
+
1530
+ // Set OApp executor config - should succeed
1531
+ start_cheat_caller_address(contract_address, ENDPOINT);
1532
+ set_oapp_executor_send_config_via_message_lib(
1533
+ contract_address, SENDER, DST_EID, valid_executor_config.clone(),
1534
+ );
1535
+ stop_cheat_caller_address(contract_address);
1536
+
1537
+ // Verify config was set correctly
1538
+ let retrieved_config = admin.get_raw_oapp_executor_config(SENDER, DST_EID);
1539
+ assert(
1540
+ retrieved_config.max_message_size == valid_executor_config.max_message_size,
1541
+ 'MaxMsgSize not set correctly',
1542
+ );
1543
+ assert(
1544
+ retrieved_config.executor == valid_executor_config.executor, 'Executor not set correctly',
1545
+ );
1546
+
1547
+ // Verify event was emitted
1548
+ spy
1549
+ .assert_emitted(
1550
+ @array![
1551
+ (
1552
+ contract_address,
1553
+ UltraLightNode::Event::OAppExecutorConfigSet(
1554
+ OAppExecutorConfigSet {
1555
+ oapp: SENDER, dst_eid: DST_EID, config: valid_executor_config,
1556
+ },
1557
+ ),
1558
+ ),
1559
+ ],
1560
+ );
1561
+ }
1562
+
1563
+ #[test]
1564
+ fn test_set_oapp_configs_emits_correct_events() {
1565
+ let (admin, contract_address) = deploy_ultra_light_node();
1566
+
1567
+ // First set default config as owner (required for EID to be supported)
1568
+ setup_default_config(admin, contract_address, DST_EID);
1569
+
1570
+ let uln_config = UlnConfig {
1571
+ confirmations: 25,
1572
+ has_confirmations: true,
1573
+ required_dvns: array![DVN_1, DVN_2],
1574
+ has_required_dvns: true,
1575
+ optional_dvns: array![],
1576
+ optional_dvn_threshold: 0,
1577
+ has_optional_dvns: true,
1578
+ };
1579
+
1580
+ let executor_config = ExecutorConfig { max_message_size: 3000, executor: EXECUTOR };
1581
+
1582
+ // Set up event spy
1583
+ let mut spy = spy_events();
1584
+
1585
+ // Set both configs as SENDER
1586
+ start_cheat_caller_address(contract_address, ENDPOINT);
1587
+ set_oapp_uln_send_config_via_message_lib(contract_address, SENDER, DST_EID, uln_config.clone());
1588
+ set_oapp_executor_send_config_via_message_lib(
1589
+ contract_address, SENDER, DST_EID, executor_config.clone(),
1590
+ );
1591
+ stop_cheat_caller_address(contract_address);
1592
+
1593
+ // Verify both events were emitted with correct data
1594
+ spy
1595
+ .assert_emitted(
1596
+ @array![
1597
+ (
1598
+ contract_address,
1599
+ UltraLightNode::Event::OAppUlnSendConfigSet(
1600
+ OAppUlnSendConfigSet { oapp: SENDER, dst_eid: DST_EID, config: uln_config },
1601
+ ),
1602
+ ),
1603
+ (
1604
+ contract_address,
1605
+ UltraLightNode::Event::OAppExecutorConfigSet(
1606
+ OAppExecutorConfigSet {
1607
+ oapp: SENDER, dst_eid: DST_EID, config: executor_config,
1608
+ },
1609
+ ),
1610
+ ),
1611
+ ],
1612
+ );
1613
+ }
1614
+
1615
+ #[test]
1616
+ fn test_set_oapp_configs_multiple_callers_independence() {
1617
+ let (admin, contract_address) = deploy_ultra_light_node();
1618
+
1619
+ // First set default config as owner (required for EID to be supported)
1620
+ setup_default_config(admin, contract_address, DST_EID);
1621
+
1622
+ let sender1_uln_config = UlnConfig {
1623
+ confirmations: 30,
1624
+ has_confirmations: true,
1625
+ required_dvns: array![DVN_1],
1626
+ has_required_dvns: true,
1627
+ optional_dvns: array![],
1628
+ optional_dvn_threshold: 0,
1629
+ has_optional_dvns: true,
1630
+ };
1631
+
1632
+ let sender2_uln_config = UlnConfig {
1633
+ confirmations: 40,
1634
+ has_confirmations: true,
1635
+ required_dvns: array![DVN_2],
1636
+ has_required_dvns: true,
1637
+ optional_dvns: array![],
1638
+ optional_dvn_threshold: 0,
1639
+ has_optional_dvns: true,
1640
+ };
1641
+
1642
+ let sender1_executor_config = ExecutorConfig { max_message_size: 4000, executor: DVN_1 };
1643
+ let sender2_executor_config = ExecutorConfig { max_message_size: 5000, executor: DVN_2 };
1644
+
1645
+ // Set configs for SENDER
1646
+ start_cheat_caller_address(contract_address, ENDPOINT);
1647
+ set_oapp_uln_send_config_via_message_lib(
1648
+ contract_address, SENDER, DST_EID, sender1_uln_config.clone(),
1649
+ );
1650
+ set_oapp_executor_send_config_via_message_lib(
1651
+ contract_address, SENDER, DST_EID, sender1_executor_config.clone(),
1652
+ );
1653
+
1654
+ set_oapp_uln_send_config_via_message_lib(
1655
+ contract_address, SENDER_2, DST_EID, sender2_uln_config.clone(),
1656
+ );
1657
+ set_oapp_executor_send_config_via_message_lib(
1658
+ contract_address, SENDER_2, DST_EID, sender2_executor_config.clone(),
1659
+ );
1660
+ stop_cheat_caller_address(contract_address);
1661
+
1662
+ // Verify configs are independent
1663
+ let sender1_retrieved_uln = admin.get_raw_oapp_uln_send_config(SENDER, DST_EID);
1664
+ let sender2_retrieved_uln = admin.get_raw_oapp_uln_send_config(SENDER_2, DST_EID);
1665
+ let sender1_retrieved_executor = admin.get_raw_oapp_executor_config(SENDER, DST_EID);
1666
+ let sender2_retrieved_executor = admin.get_raw_oapp_executor_config(SENDER_2, DST_EID);
1667
+
1668
+ assert(sender1_retrieved_uln.confirmations == 30, 'Sender1 ULN confirmations wrong');
1669
+ assert(sender2_retrieved_uln.confirmations == 40, 'Sender2 ULN confirmations wrong');
1670
+ assert(sender1_retrieved_executor.max_message_size == 4000, 'Sender1 executor size wrong');
1671
+ assert(sender2_retrieved_executor.max_message_size == 5000, 'Sender2 executor size wrong');
1672
+ assert(sender1_retrieved_executor.executor == DVN_1, 'Sender1 executor address wrong');
1673
+ assert(sender2_retrieved_executor.executor == DVN_2, 'Sender2 executor address wrong');
1674
+ }
1675
+
1676
+ #[test]
1677
+ fn test_owner_can_set_default_uln_receive_config() {
1678
+ let (admin, contract_address) = deploy_ultra_light_node();
1679
+ let uln_config = create_test_uln_config();
1680
+
1681
+ // Test that owner can set default receive configs
1682
+ start_cheat_caller_address(contract_address, OWNER);
1683
+
1684
+ // Create array of configs for the new API
1685
+ let config_params = array![
1686
+ SetDefaultUlnConfigParam { eid: DST_EID, config: uln_config.clone() },
1687
+ ];
1688
+
1689
+ // Set up event spy
1690
+ let mut spy = spy_events();
1691
+
1692
+ admin.set_default_uln_receive_config(config_params);
1693
+
1694
+ // Verify config was set
1695
+ let retrieved_uln_config = admin.get_default_uln_receive_config(DST_EID);
1696
+
1697
+ assert(retrieved_uln_config.confirmations == CONFIRMATIONS, 'Receive confirmations incorrect');
1698
+ assert(
1699
+ retrieved_uln_config.required_dvns.len() == create_required_dvns().len(),
1700
+ 'Receive DVNs count incorrect',
1701
+ );
1702
+
1703
+ // Verify event was emitted
1704
+ spy
1705
+ .assert_emitted(
1706
+ @array![
1707
+ (
1708
+ contract_address,
1709
+ UltraLightNode::Event::DefaultUlnReceiveConfigSet(
1710
+ DefaultUlnReceiveConfigSet { src_eid: DST_EID, config: uln_config },
1711
+ ),
1712
+ ),
1713
+ ],
1714
+ );
1715
+
1716
+ stop_cheat_caller_address(contract_address);
1717
+ }
1718
+
1719
+ #[test]
1720
+ #[should_panic(expected: ('Caller is not the owner',))]
1721
+ fn test_non_owner_cannot_set_default_uln_receive_config() {
1722
+ let (admin, contract_address) = deploy_ultra_light_node();
1723
+ let uln_config = create_test_uln_config();
1724
+
1725
+ start_cheat_caller_address(contract_address, NON_OWNER);
1726
+
1727
+ let config_params = array![SetDefaultUlnConfigParam { eid: DST_EID, config: uln_config }];
1728
+
1729
+ admin.set_default_uln_receive_config(config_params); // This should panic
1730
+ }
1731
+
1732
+ #[test]
1733
+ fn test_set_and_get_default_uln_receive_config_multiple_sources() {
1734
+ let (admin, contract_address) = deploy_ultra_light_node();
1735
+
1736
+ start_cheat_caller_address(contract_address, OWNER);
1737
+
1738
+ // Set configs for different source endpoints
1739
+ let config_src2 = UlnConfig {
1740
+ confirmations: 8,
1741
+ has_confirmations: true,
1742
+ required_dvns: array![DVN_1],
1743
+ has_required_dvns: true,
1744
+ optional_dvns: array![],
1745
+ optional_dvn_threshold: 0,
1746
+ has_optional_dvns: true,
1747
+ };
1748
+
1749
+ let config_src3 = UlnConfig {
1750
+ confirmations: 18,
1751
+ has_confirmations: true,
1752
+ required_dvns: array![DVN_1, DVN_2],
1753
+ has_required_dvns: true,
1754
+ optional_dvns: array![],
1755
+ optional_dvn_threshold: 0,
1756
+ has_optional_dvns: true,
1757
+ };
1758
+
1759
+ // Use the batch API to set multiple configs at once
1760
+ let config_params = array![
1761
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_src2.clone() },
1762
+ SetDefaultUlnConfigParam { eid: DST_EID_2, config: config_src3.clone() },
1763
+ ];
1764
+
1765
+ // Set up event spy
1766
+ let mut spy = spy_events();
1767
+
1768
+ admin.set_default_uln_receive_config(config_params);
1769
+
1770
+ // Verify different configs for different source endpoints
1771
+ let retrieved_config_src2 = admin.get_default_uln_receive_config(DST_EID);
1772
+ let retrieved_config_src3 = admin.get_default_uln_receive_config(DST_EID_2);
1773
+
1774
+ assert(
1775
+ retrieved_config_src2.confirmations == config_src2.confirmations,
1776
+ 'SRC2 confirmations incorrect',
1777
+ );
1778
+ assert(
1779
+ retrieved_config_src2.required_dvns.len() == config_src2.required_dvns.len(),
1780
+ 'SRC2 DVNs count incorrect',
1781
+ );
1782
+ assert(
1783
+ retrieved_config_src3.confirmations == config_src3.confirmations,
1784
+ 'SRC3 confirmations incorrect',
1785
+ );
1786
+ assert(
1787
+ retrieved_config_src3.required_dvns.len() == config_src3.required_dvns.len(),
1788
+ 'SRC3 DVNs count incorrect',
1789
+ );
1790
+
1791
+ // Verify events were emitted for both configs
1792
+ spy
1793
+ .assert_emitted(
1794
+ @array![
1795
+ (
1796
+ contract_address,
1797
+ UltraLightNode::Event::DefaultUlnReceiveConfigSet(
1798
+ DefaultUlnReceiveConfigSet { src_eid: DST_EID, config: config_src2 },
1799
+ ),
1800
+ ),
1801
+ (
1802
+ contract_address,
1803
+ UltraLightNode::Event::DefaultUlnReceiveConfigSet(
1804
+ DefaultUlnReceiveConfigSet { src_eid: DST_EID_2, config: config_src3 },
1805
+ ),
1806
+ ),
1807
+ ],
1808
+ );
1809
+
1810
+ stop_cheat_caller_address(contract_address);
1811
+ }
1812
+
1813
+ #[test]
1814
+ fn test_set_and_get_raw_oapp_uln_receive_config_multiple_receivers() {
1815
+ let (admin, contract_address) = deploy_ultra_light_node();
1816
+
1817
+ // First set default receive config as owner
1818
+ start_cheat_caller_address(contract_address, OWNER);
1819
+ let default_config = create_test_uln_config();
1820
+ let config_params = array![SetDefaultUlnConfigParam { eid: DST_EID, config: default_config }];
1821
+ admin.set_default_uln_receive_config(config_params);
1822
+ stop_cheat_caller_address(contract_address);
1823
+
1824
+ // Set configs for different receivers (no ownership required)
1825
+ let config_receiver1 = UlnConfig {
1826
+ confirmations: 9,
1827
+ has_confirmations: true,
1828
+ required_dvns: array![DVN_1],
1829
+ has_required_dvns: true,
1830
+ optional_dvns: array![],
1831
+ optional_dvn_threshold: 0,
1832
+ has_optional_dvns: true,
1833
+ };
1834
+
1835
+ let config_receiver2 = UlnConfig {
1836
+ confirmations: 13,
1837
+ has_confirmations: true,
1838
+ required_dvns: array![DVN_2],
1839
+ has_required_dvns: true,
1840
+ optional_dvns: array![],
1841
+ optional_dvn_threshold: 0,
1842
+ has_optional_dvns: true,
1843
+ };
1844
+
1845
+ // Set up event spy
1846
+ let mut spy = spy_events();
1847
+
1848
+ // Set config for SENDER
1849
+ start_cheat_caller_address(contract_address, ENDPOINT);
1850
+ set_oapp_uln_receive_config_via_message_lib(
1851
+ contract_address, SENDER, DST_EID, config_receiver1.clone(),
1852
+ );
1853
+
1854
+ set_oapp_uln_receive_config_via_message_lib(
1855
+ contract_address, SENDER_2, DST_EID, config_receiver2.clone(),
1856
+ );
1857
+ stop_cheat_caller_address(contract_address);
1858
+
1859
+ // Verify different configs for different receivers
1860
+ let retrieved_config_receiver1 = admin.get_raw_oapp_uln_receive_config(SENDER, DST_EID);
1861
+ let retrieved_config_receiver2 = admin.get_raw_oapp_uln_receive_config(SENDER_2, DST_EID);
1862
+
1863
+ assert(
1864
+ retrieved_config_receiver1.confirmations == config_receiver1.confirmations,
1865
+ 'Recv conf not custom',
1866
+ );
1867
+ assert(
1868
+ retrieved_config_receiver2.confirmations == config_receiver2.confirmations,
1869
+ 'Recv conf not custom',
1870
+ );
1871
+
1872
+ // Verify events were emitted
1873
+ spy
1874
+ .assert_emitted(
1875
+ @array![
1876
+ (
1877
+ contract_address,
1878
+ UltraLightNode::Event::OAppUlnReceiveConfigSet(
1879
+ OAppUlnReceiveConfigSet {
1880
+ oapp: SENDER, src_eid: DST_EID, config: config_receiver1,
1881
+ },
1882
+ ),
1883
+ ),
1884
+ (
1885
+ contract_address,
1886
+ UltraLightNode::Event::OAppUlnReceiveConfigSet(
1887
+ OAppUlnReceiveConfigSet {
1888
+ oapp: SENDER_2, src_eid: DST_EID, config: config_receiver2,
1889
+ },
1890
+ ),
1891
+ ),
1892
+ ],
1893
+ );
1894
+ }
1895
+
1896
+ #[test]
1897
+ fn test_oapp_receive_config_overrides_default() {
1898
+ let (admin, contract_address) = deploy_ultra_light_node();
1899
+
1900
+ start_cheat_caller_address(contract_address, OWNER);
1901
+
1902
+ // Set default receive config
1903
+ let default_config = UlnConfig {
1904
+ confirmations: 12,
1905
+ has_confirmations: true,
1906
+ required_dvns: array![DVN_1],
1907
+ has_required_dvns: true,
1908
+ optional_dvns: array![],
1909
+ optional_dvn_threshold: 0,
1910
+ has_optional_dvns: true,
1911
+ };
1912
+ let config_params = array![
1913
+ SetDefaultUlnConfigParam { eid: DST_EID, config: default_config.clone() },
1914
+ ];
1915
+ admin.set_default_uln_receive_config(config_params);
1916
+
1917
+ stop_cheat_caller_address(contract_address);
1918
+
1919
+ // Set OApp-specific receive config that should override default
1920
+ let oapp_config = UlnConfig {
1921
+ confirmations: 22,
1922
+ has_confirmations: true,
1923
+ required_dvns: array![DVN_2],
1924
+ has_required_dvns: true,
1925
+ optional_dvns: array![],
1926
+ optional_dvn_threshold: 0,
1927
+ has_optional_dvns: true,
1928
+ };
1929
+
1930
+ // Set up event spy for OApp config
1931
+ let mut oapp_spy = spy_events();
1932
+
1933
+ // Set config for SENDER
1934
+ start_cheat_caller_address(contract_address, ENDPOINT);
1935
+ set_oapp_uln_receive_config_via_message_lib(
1936
+ contract_address, SENDER, DST_EID, oapp_config.clone(),
1937
+ );
1938
+ stop_cheat_caller_address(contract_address);
1939
+
1940
+ // Verify that default and OApp effective configs are different
1941
+ let oapp_effective_config = admin.get_oapp_uln_receive_config(SENDER, DST_EID);
1942
+
1943
+ assert(
1944
+ oapp_effective_config.confirmations == oapp_config.confirmations,
1945
+ 'OApp receive conf incorrect',
1946
+ );
1947
+ assert(
1948
+ oapp_effective_config.required_dvns.len() == oapp_config.required_dvns.len(),
1949
+ 'OApp receive DVNs count inc',
1950
+ );
1951
+ assert(
1952
+ *oapp_effective_config.required_dvns.at(0) == *oapp_config.required_dvns.at(0),
1953
+ 'OApp receive DVN incorrect',
1954
+ );
1955
+
1956
+ // Check that a different receiver would get the default config (not overridden)
1957
+ let other_receiver_effective_config = admin.get_oapp_uln_receive_config(SENDER_2, DST_EID);
1958
+ assert(
1959
+ other_receiver_effective_config.confirmations == default_config.confirmations,
1960
+ 'Other recv should get default',
1961
+ );
1962
+ assert(
1963
+ *other_receiver_effective_config.required_dvns.at(0) == *default_config.required_dvns.at(0),
1964
+ 'recv2 should get default',
1965
+ );
1966
+
1967
+ // Verify OApp receive config event was emitted
1968
+ oapp_spy
1969
+ .assert_emitted(
1970
+ @array![
1971
+ (
1972
+ contract_address,
1973
+ UltraLightNode::Event::OAppUlnReceiveConfigSet(
1974
+ OAppUlnReceiveConfigSet {
1975
+ oapp: SENDER, src_eid: DST_EID, config: oapp_config,
1976
+ },
1977
+ ),
1978
+ ),
1979
+ ],
1980
+ );
1981
+ }
1982
+
1983
+ #[test]
1984
+ fn test_oapp_receive_config_partial_override() {
1985
+ let (admin, contract_address) = deploy_ultra_light_node();
1986
+
1987
+ start_cheat_caller_address(contract_address, OWNER);
1988
+
1989
+ // Set default receive config with all fields populated
1990
+ let default_config = UlnConfig {
1991
+ confirmations: 16,
1992
+ has_confirmations: true,
1993
+ required_dvns: array![DVN_1, DVN_2],
1994
+ has_required_dvns: true,
1995
+ optional_dvns: array![DVN_3],
1996
+ optional_dvn_threshold: 1,
1997
+ has_optional_dvns: true,
1998
+ };
1999
+ let config_params = array![
2000
+ SetDefaultUlnConfigParam { eid: DST_EID, config: default_config.clone() },
2001
+ ];
2002
+ admin.set_default_uln_receive_config(config_params);
2003
+
2004
+ stop_cheat_caller_address(contract_address);
2005
+
2006
+ // Set OApp-specific receive config that only overrides some fields
2007
+ let partial_oapp_config = UlnConfig {
2008
+ confirmations: 26, // Override confirmations
2009
+ has_confirmations: true,
2010
+ required_dvns: array![], // Don't override required DVNs (use default)
2011
+ has_required_dvns: false, // This means use default
2012
+ optional_dvns: array![DVN_1, DVN_2], // Override optional DVNs
2013
+ optional_dvn_threshold: 2, // Override optional threshold
2014
+ has_optional_dvns: true,
2015
+ };
2016
+
2017
+ // Set up event spy for OApp config
2018
+ let mut oapp_spy = spy_events();
2019
+
2020
+ // Set config as SENDER
2021
+ start_cheat_caller_address(contract_address, ENDPOINT);
2022
+ set_oapp_uln_receive_config_via_message_lib(
2023
+ contract_address, SENDER, DST_EID, partial_oapp_config.clone(),
2024
+ );
2025
+ stop_cheat_caller_address(contract_address);
2026
+
2027
+ // Get the effective config (resolved)
2028
+ let effective_config = admin.get_oapp_uln_receive_config(SENDER, DST_EID);
2029
+
2030
+ // Verify partial override behavior:
2031
+ // - confirmations should be overridden (26, not 16)
2032
+ // - required_dvns should use default (DVN_1, DVN_2 from default, not empty from oapp)
2033
+ // - optional_dvns should be overridden (DVN_1, DVN_2 from oapp, not DVN_3 from default)
2034
+ // - optional_dvn_threshold should be overridden (2, not 1)
2035
+
2036
+ assert(
2037
+ effective_config.confirmations == partial_oapp_config.confirmations, 'Recv conf not custom',
2038
+ );
2039
+ assert(
2040
+ effective_config.required_dvns.len() == default_config.required_dvns.len(),
2041
+ 'Recv req DVNs not default',
2042
+ );
2043
+ assert(
2044
+ *effective_config.required_dvns.at(0) == *default_config.required_dvns.at(0),
2045
+ 'Recv req DVN.0 not default',
2046
+ );
2047
+ assert(
2048
+ *effective_config.required_dvns.at(1) == *default_config.required_dvns.at(1),
2049
+ 'Recv req DVN.1 not default',
2050
+ );
2051
+ assert(
2052
+ effective_config.optional_dvns.len() == partial_oapp_config.optional_dvns.len(),
2053
+ 'Recv opt DVNs not custom',
2054
+ );
2055
+ assert(
2056
+ *effective_config.optional_dvns.at(0) == *partial_oapp_config.optional_dvns.at(0),
2057
+ 'Recv opt DVN.0 not custom',
2058
+ );
2059
+ assert(
2060
+ *effective_config.optional_dvns.at(1) == *partial_oapp_config.optional_dvns.at(1),
2061
+ 'Recv opt DVN.1 not custom',
2062
+ );
2063
+ assert(
2064
+ effective_config.optional_dvn_threshold == partial_oapp_config.optional_dvn_threshold,
2065
+ 'Recv opt thresh not custom',
2066
+ );
2067
+
2068
+ // Verify OApp receive config event was emitted
2069
+ oapp_spy
2070
+ .assert_emitted(
2071
+ @array![
2072
+ (
2073
+ contract_address,
2074
+ UltraLightNode::Event::OAppUlnReceiveConfigSet(
2075
+ OAppUlnReceiveConfigSet {
2076
+ oapp: SENDER, src_eid: DST_EID, config: partial_oapp_config,
2077
+ },
2078
+ ),
2079
+ ),
2080
+ ],
2081
+ );
2082
+ }
2083
+
2084
+ #[test]
2085
+ fn test_empty_receive_configs_return_defaults() {
2086
+ let (admin, _) = deploy_ultra_light_node();
2087
+
2088
+ // Getting receive configs that were never set should return empty/default values
2089
+ let empty_default_receive_config = admin.get_default_uln_receive_config(DST_EID);
2090
+ let empty_oapp_receive_config = admin.get_raw_oapp_uln_receive_config(SENDER, DST_EID);
2091
+
2092
+ // These should be empty/default values
2093
+ assert(empty_default_receive_config.confirmations == 0, 'Default receive should be empty');
2094
+ assert(empty_default_receive_config.required_dvns.len() == 0, 'Default receive dvns != empty');
2095
+ assert(empty_oapp_receive_config.confirmations == 0, 'OApp receive should be empty');
2096
+ }
2097
+
2098
+ #[test]
2099
+ #[feature("safe_dispatcher")]
2100
+ fn test_set_default_uln_receive_config_fails_with_duplicate_required_dvns() {
2101
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
2102
+
2103
+ // Create config with duplicate required DVNs
2104
+ let config_with_duplicate_required = UlnConfig {
2105
+ confirmations: 11,
2106
+ has_confirmations: true,
2107
+ required_dvns: array![DVN_1, DVN_1], // Duplicate DVN_1
2108
+ has_required_dvns: true,
2109
+ optional_dvns: array![DVN_2],
2110
+ optional_dvn_threshold: 1,
2111
+ has_optional_dvns: true,
2112
+ };
2113
+
2114
+ let config_params = array![
2115
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_duplicate_required },
2116
+ ];
2117
+
2118
+ // Try to set default receive config with duplicate required DVNs - should fail
2119
+ start_cheat_caller_address(contract_address, OWNER);
2120
+ let result = admin_safe.set_default_uln_receive_config(config_params);
2121
+ assert_panic_with_error(result, err_unsorted_dvns());
2122
+ stop_cheat_caller_address(contract_address);
2123
+ }
2124
+
2125
+ #[test]
2126
+ #[feature("safe_dispatcher")]
2127
+ fn test_set_default_uln_receive_config_fails_with_zero_confirmations() {
2128
+ let (admin_safe, contract_address) = deploy_ultra_light_node_safe();
2129
+
2130
+ // Create config with zero confirmations
2131
+ let config_with_zero_confirmations = UlnConfig {
2132
+ confirmations: 0, // Invalid: confirmations must be > 0
2133
+ has_confirmations: true,
2134
+ required_dvns: array![DVN_1],
2135
+ has_required_dvns: true,
2136
+ optional_dvns: array![],
2137
+ optional_dvn_threshold: 0,
2138
+ has_optional_dvns: true,
2139
+ };
2140
+
2141
+ let config_params = array![
2142
+ SetDefaultUlnConfigParam { eid: DST_EID, config: config_with_zero_confirmations },
2143
+ ];
2144
+
2145
+ // Try to set default receive config with zero confirmations - should fail
2146
+ start_cheat_caller_address(contract_address, OWNER);
2147
+ let result = admin_safe.set_default_uln_receive_config(config_params);
2148
+ assert_panic_with_error(result, err_invalid_confirmations());
2149
+ stop_cheat_caller_address(contract_address);
2150
+ }