@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.
- package/.turbo/turbo-build.log +186 -0
- package/.turbo/turbo-lint.log +71 -0
- package/.turbo/turbo-test.log +937 -0
- package/README.md +41 -0
- package/Scarb.lock +211 -0
- package/Scarb.toml +2 -0
- package/dist/4XD3ZRZ4.cjs +301 -0
- package/dist/4XD3ZRZ4.cjs.map +1 -0
- package/dist/4Z5IPBC3.js +299 -0
- package/dist/4Z5IPBC3.js.map +1 -0
- package/dist/5NEZDLVQ.cjs +474 -0
- package/dist/5NEZDLVQ.cjs.map +1 -0
- package/dist/6JYCOKDE.js +472 -0
- package/dist/6JYCOKDE.js.map +1 -0
- package/dist/7C4PFMIZ.cjs +1288 -0
- package/dist/7C4PFMIZ.cjs.map +1 -0
- package/dist/7ZSGGZUE.js +1229 -0
- package/dist/7ZSGGZUE.js.map +1 -0
- package/dist/ARHOGUYH.cjs +2136 -0
- package/dist/ARHOGUYH.cjs.map +1 -0
- package/dist/CRCRIUFX.js +1264 -0
- package/dist/CRCRIUFX.js.map +1 -0
- package/dist/DB7CQSED.cjs +430 -0
- package/dist/DB7CQSED.cjs.map +1 -0
- package/dist/DFXLWHYP.cjs +1266 -0
- package/dist/DFXLWHYP.cjs.map +1 -0
- package/dist/EOLZCMCK.js +988 -0
- package/dist/EOLZCMCK.js.map +1 -0
- package/dist/FFDPTOWG.cjs +331 -0
- package/dist/FFDPTOWG.cjs.map +1 -0
- package/dist/FOJGEAIO.js +2134 -0
- package/dist/FOJGEAIO.js.map +1 -0
- package/dist/IWIUMVGB.js +629 -0
- package/dist/IWIUMVGB.js.map +1 -0
- package/dist/MUEN6AWV.cjs +697 -0
- package/dist/MUEN6AWV.cjs.map +1 -0
- package/dist/ORE6VBZ4.cjs +990 -0
- package/dist/ORE6VBZ4.cjs.map +1 -0
- package/dist/OUFKWPZ7.js +732 -0
- package/dist/OUFKWPZ7.js.map +1 -0
- package/dist/T2QTYQXJ.js +1229 -0
- package/dist/T2QTYQXJ.js.map +1 -0
- package/dist/UPJTM7BR.cjs +631 -0
- package/dist/UPJTM7BR.cjs.map +1 -0
- package/dist/VNVNX2P3.cjs +1231 -0
- package/dist/VNVNX2P3.cjs.map +1 -0
- package/dist/VUOMXK5T.js +6 -0
- package/dist/VUOMXK5T.js.map +1 -0
- package/dist/WISWRTDG.js +1286 -0
- package/dist/WISWRTDG.js.map +1 -0
- package/dist/WU5L7YIQ.cjs +1231 -0
- package/dist/WU5L7YIQ.cjs.map +1 -0
- package/dist/X3B5JDMZ.js +695 -0
- package/dist/X3B5JDMZ.js.map +1 -0
- package/dist/XYNBDBBV.cjs +297 -0
- package/dist/XYNBDBBV.cjs.map +1 -0
- package/dist/Y5JFPCYJ.cjs +734 -0
- package/dist/Y5JFPCYJ.cjs.map +1 -0
- package/dist/YEHL7IYO.js +295 -0
- package/dist/YEHL7IYO.js.map +1 -0
- package/dist/YJF4D23A.cjs +8 -0
- package/dist/YJF4D23A.cjs.map +1 -0
- package/dist/YTS44OEA.js +428 -0
- package/dist/YTS44OEA.js.map +1 -0
- package/dist/Z2NIUZMW.js +329 -0
- package/dist/Z2NIUZMW.js.map +1 -0
- package/dist/abis/blocked-message-lib.cjs +13 -0
- package/dist/abis/blocked-message-lib.cjs.map +1 -0
- package/dist/abis/blocked-message-lib.d.ts +338 -0
- package/dist/abis/blocked-message-lib.d.ts.map +1 -0
- package/dist/abis/blocked-message-lib.js +4 -0
- package/dist/abis/blocked-message-lib.js.map +1 -0
- package/dist/abis/dvn-fee-lib.cjs +13 -0
- package/dist/abis/dvn-fee-lib.cjs.map +1 -0
- package/dist/abis/dvn-fee-lib.d.ts +214 -0
- package/dist/abis/dvn-fee-lib.d.ts.map +1 -0
- package/dist/abis/dvn-fee-lib.js +4 -0
- package/dist/abis/dvn-fee-lib.js.map +1 -0
- package/dist/abis/dvn.cjs +13 -0
- package/dist/abis/dvn.cjs.map +1 -0
- package/dist/abis/dvn.d.ts +952 -0
- package/dist/abis/dvn.d.ts.map +1 -0
- package/dist/abis/dvn.js +4 -0
- package/dist/abis/dvn.js.map +1 -0
- package/dist/abis/endpoint-v2.cjs +13 -0
- package/dist/abis/endpoint-v2.cjs.map +1 -0
- package/dist/abis/endpoint-v2.d.ts +1580 -0
- package/dist/abis/endpoint-v2.d.ts.map +1 -0
- package/dist/abis/endpoint-v2.js +4 -0
- package/dist/abis/endpoint-v2.js.map +1 -0
- package/dist/abis/executor-fee-lib.cjs +13 -0
- package/dist/abis/executor-fee-lib.cjs.map +1 -0
- package/dist/abis/executor-fee-lib.d.ts +217 -0
- package/dist/abis/executor-fee-lib.d.ts.map +1 -0
- package/dist/abis/executor-fee-lib.js +4 -0
- package/dist/abis/executor-fee-lib.js.map +1 -0
- package/dist/abis/executor.cjs +13 -0
- package/dist/abis/executor.cjs.map +1 -0
- package/dist/abis/executor.d.ts +914 -0
- package/dist/abis/executor.d.ts.map +1 -0
- package/dist/abis/executor.js +4 -0
- package/dist/abis/executor.js.map +1 -0
- package/dist/abis/o-app.cjs +13 -0
- package/dist/abis/o-app.cjs.map +1 -0
- package/dist/abis/o-app.d.ts +311 -0
- package/dist/abis/o-app.d.ts.map +1 -0
- package/dist/abis/o-app.js +4 -0
- package/dist/abis/o-app.js.map +1 -0
- package/dist/abis/oft-adapter.cjs +13 -0
- package/dist/abis/oft-adapter.cjs.map +1 -0
- package/dist/abis/oft-adapter.d.ts +722 -0
- package/dist/abis/oft-adapter.d.ts.map +1 -0
- package/dist/abis/oft-adapter.js +4 -0
- package/dist/abis/oft-adapter.js.map +1 -0
- package/dist/abis/oft.cjs +13 -0
- package/dist/abis/oft.cjs.map +1 -0
- package/dist/abis/oft.d.ts +922 -0
- package/dist/abis/oft.d.ts.map +1 -0
- package/dist/abis/oft.js +4 -0
- package/dist/abis/oft.js.map +1 -0
- package/dist/abis/omni-counter.cjs +13 -0
- package/dist/abis/omni-counter.cjs.map +1 -0
- package/dist/abis/omni-counter.d.ts +459 -0
- package/dist/abis/omni-counter.d.ts.map +1 -0
- package/dist/abis/omni-counter.js +4 -0
- package/dist/abis/omni-counter.js.map +1 -0
- package/dist/abis/price-feed.cjs +13 -0
- package/dist/abis/price-feed.cjs.map +1 -0
- package/dist/abis/price-feed.d.ts +505 -0
- package/dist/abis/price-feed.d.ts.map +1 -0
- package/dist/abis/price-feed.js +4 -0
- package/dist/abis/price-feed.js.map +1 -0
- package/dist/abis/simple-message-lib.cjs +13 -0
- package/dist/abis/simple-message-lib.cjs.map +1 -0
- package/dist/abis/simple-message-lib.d.ts +535 -0
- package/dist/abis/simple-message-lib.d.ts.map +1 -0
- package/dist/abis/simple-message-lib.js +4 -0
- package/dist/abis/simple-message-lib.js.map +1 -0
- package/dist/abis/treasury.cjs +13 -0
- package/dist/abis/treasury.cjs.map +1 -0
- package/dist/abis/treasury.d.ts +240 -0
- package/dist/abis/treasury.d.ts.map +1 -0
- package/dist/abis/treasury.js +4 -0
- package/dist/abis/treasury.js.map +1 -0
- package/dist/abis/ultra-light-node.cjs +13 -0
- package/dist/abis/ultra-light-node.cjs.map +1 -0
- package/dist/abis/ultra-light-node.d.ts +900 -0
- package/dist/abis/ultra-light-node.d.ts.map +1 -0
- package/dist/abis/ultra-light-node.js +4 -0
- package/dist/abis/ultra-light-node.js.map +1 -0
- package/dist/index.cjs +78 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/build-abi.cjs +28 -0
- package/dist/scripts/build-abi.cjs.map +1 -0
- package/dist/scripts/build-abi.d.ts +2 -0
- package/dist/scripts/build-abi.d.ts.map +1 -0
- package/dist/scripts/build-abi.js +26 -0
- package/dist/scripts/build-abi.js.map +1 -0
- package/layerzero/README.md +244 -0
- package/layerzero/Scarb.lock +203 -0
- package/layerzero/Scarb.toml +30 -0
- package/layerzero/snfoundry.toml +11 -0
- package/layerzero/src/common/constants.cairo +26 -0
- package/layerzero/src/common/conversions.cairo +16 -0
- package/layerzero/src/common/guid.cairo +20 -0
- package/layerzero/src/common/packet_v1_codec.cairo +307 -0
- package/layerzero/src/common/structs/messaging.cairo +40 -0
- package/layerzero/src/common/structs/packet.cairo +31 -0
- package/layerzero/src/endpoint/constants.cairo +14 -0
- package/layerzero/src/endpoint/endpoint.cairo +688 -0
- package/layerzero/src/endpoint/errors.cairo +108 -0
- package/layerzero/src/endpoint/events.cairo +124 -0
- package/layerzero/src/endpoint/interfaces/endpoint.cairo +286 -0
- package/layerzero/src/endpoint/interfaces/layerzero_composer.cairo +62 -0
- package/layerzero/src/endpoint/interfaces/layerzero_receiver.cairo +63 -0
- package/layerzero/src/endpoint/message_lib_manager/errors.cairo +95 -0
- package/layerzero/src/endpoint/message_lib_manager/events.cairo +90 -0
- package/layerzero/src/endpoint/message_lib_manager/interface.cairo +449 -0
- package/layerzero/src/endpoint/message_lib_manager/message_lib_manager.cairo +720 -0
- package/layerzero/src/endpoint/message_lib_manager/structs.cairo +33 -0
- package/layerzero/src/endpoint/messaging_channel/errors.cairo +37 -0
- package/layerzero/src/endpoint/messaging_channel/events.cairo +58 -0
- package/layerzero/src/endpoint/messaging_channel/interface.cairo +171 -0
- package/layerzero/src/endpoint/messaging_channel/messaging_channel.cairo +453 -0
- package/layerzero/src/endpoint/messaging_composer/errors.cairo +46 -0
- package/layerzero/src/endpoint/messaging_composer/events.cairo +67 -0
- package/layerzero/src/endpoint/messaging_composer/interface.cairo +132 -0
- package/layerzero/src/endpoint/messaging_composer/messaging_composer.cairo +223 -0
- package/layerzero/src/lib.cairo +189 -0
- package/layerzero/src/message_lib/blocked_message_lib.cairo +114 -0
- package/layerzero/src/message_lib/interface.cairo +63 -0
- package/layerzero/src/message_lib/sml/errors.cairo +23 -0
- package/layerzero/src/message_lib/sml/events.cairo +32 -0
- package/layerzero/src/message_lib/sml/simple_message_lib.cairo +312 -0
- package/layerzero/src/message_lib/structs.cairo +22 -0
- package/layerzero/src/message_lib/uln/errors.cairo +128 -0
- package/layerzero/src/message_lib/uln/events.cairo +97 -0
- package/layerzero/src/message_lib/uln/interface.cairo +83 -0
- package/layerzero/src/message_lib/uln/options.cairo +64 -0
- package/layerzero/src/message_lib/uln/structs/executor_config.cairo +35 -0
- package/layerzero/src/message_lib/uln/structs/payment_info.cairo +7 -0
- package/layerzero/src/message_lib/uln/structs/uln_config.cairo +155 -0
- package/layerzero/src/message_lib/uln/structs/uln_config_storage_node.cairo +91 -0
- package/layerzero/src/message_lib/uln/structs/verification.cairo +7 -0
- package/layerzero/src/message_lib/uln/ultra_light_node.cairo +965 -0
- package/layerzero/src/oapps/common/oapp_options_type_3/errors.cairo +22 -0
- package/layerzero/src/oapps/common/oapp_options_type_3/events.cairo +6 -0
- package/layerzero/src/oapps/common/oapp_options_type_3/interface.cairo +34 -0
- package/layerzero/src/oapps/common/oapp_options_type_3/oapp_options_type_3.cairo +120 -0
- package/layerzero/src/oapps/common/oapp_options_type_3/structs.cairo +6 -0
- package/layerzero/src/oapps/counter/constants.cairo +3 -0
- package/layerzero/src/oapps/counter/counter.cairo +170 -0
- package/layerzero/src/oapps/counter/interface.cairo +27 -0
- package/layerzero/src/oapps/counter/structs.cairo +20 -0
- package/layerzero/src/oapps/message_inspector/interface.cairo +21 -0
- package/layerzero/src/oapps/oapp/errors.cairo +72 -0
- package/layerzero/src/oapps/oapp/events.cairo +9 -0
- package/layerzero/src/oapps/oapp/interface.cairo +67 -0
- package/layerzero/src/oapps/oapp/oapp.cairo +70 -0
- package/layerzero/src/oapps/oapp/oapp_core.cairo +448 -0
- package/layerzero/src/oapps/oft/errors.cairo +42 -0
- package/layerzero/src/oapps/oft/events.cairo +33 -0
- package/layerzero/src/oapps/oft/interface.cairo +87 -0
- package/layerzero/src/oapps/oft/oft.cairo +188 -0
- package/layerzero/src/oapps/oft/oft_adapter.cairo +175 -0
- package/layerzero/src/oapps/oft/oft_compose_msg_codec.cairo +128 -0
- package/layerzero/src/oapps/oft/oft_core.cairo +542 -0
- package/layerzero/src/oapps/oft/oft_msg_codec.cairo +131 -0
- package/layerzero/src/oapps/oft/structs.cairo +72 -0
- package/layerzero/src/treasury/errors.cairo +22 -0
- package/layerzero/src/treasury/events.cairo +5 -0
- package/layerzero/src/treasury/interfaces/layerzero_treasury.cairo +54 -0
- package/layerzero/src/treasury/interfaces/lz_token_fee_lib.cairo +45 -0
- package/layerzero/src/treasury/interfaces/treasury_admin.cairo +39 -0
- package/layerzero/src/treasury/treasury.cairo +140 -0
- package/layerzero/src/workers/access_control.cairo +11 -0
- package/layerzero/src/workers/base/base.cairo +238 -0
- package/layerzero/src/workers/base/errors.cairo +24 -0
- package/layerzero/src/workers/base/events.cairo +43 -0
- package/layerzero/src/workers/base/interface.cairo +93 -0
- package/layerzero/src/workers/base/structs.cairo +10 -0
- package/layerzero/src/workers/common.cairo +59 -0
- package/layerzero/src/workers/dvn/constants.cairo +11 -0
- package/layerzero/src/workers/dvn/dvn.cairo +338 -0
- package/layerzero/src/workers/dvn/errors.cairo +80 -0
- package/layerzero/src/workers/dvn/events.cairo +30 -0
- package/layerzero/src/workers/dvn/fee_lib/dvn_fee_lib.cairo +152 -0
- package/layerzero/src/workers/dvn/fee_lib/interface.cairo +45 -0
- package/layerzero/src/workers/dvn/interface.cairo +131 -0
- package/layerzero/src/workers/dvn/options.cairo +125 -0
- package/layerzero/src/workers/dvn/structs.cairo +51 -0
- package/layerzero/src/workers/executor/errors.cairo +159 -0
- package/layerzero/src/workers/executor/events.cairo +32 -0
- package/layerzero/src/workers/executor/executor.cairo +392 -0
- package/layerzero/src/workers/executor/fee_lib/executor_fee_lib.cairo +160 -0
- package/layerzero/src/workers/executor/fee_lib/interface.cairo +87 -0
- package/layerzero/src/workers/executor/interface.cairo +131 -0
- package/layerzero/src/workers/executor/options.cairo +244 -0
- package/layerzero/src/workers/executor/structs.cairo +119 -0
- package/layerzero/src/workers/interface.cairo +32 -0
- package/layerzero/src/workers/price_feed/constants.cairo +7 -0
- package/layerzero/src/workers/price_feed/errors.cairo +28 -0
- package/layerzero/src/workers/price_feed/events.cairo +13 -0
- package/layerzero/src/workers/price_feed/interface.cairo +264 -0
- package/layerzero/src/workers/price_feed/price_feed.cairo +392 -0
- package/layerzero/src/workers/price_feed/structs.cairo +74 -0
- package/layerzero/tests/common/test_constants.cairo +21 -0
- package/layerzero/tests/common/test_guid.cairo +232 -0
- package/layerzero/tests/common/test_packet_v1_codec.cairo +372 -0
- package/layerzero/tests/common/utils.cairo +23 -0
- package/layerzero/tests/e2e/oft_utils.cairo +121 -0
- package/layerzero/tests/e2e/test_counter_with_sml.cairo +194 -0
- package/layerzero/tests/e2e/test_counter_with_uln.cairo +352 -0
- package/layerzero/tests/e2e/test_dvn.cairo +406 -0
- package/layerzero/tests/e2e/test_lz_token.cairo +354 -0
- package/layerzero/tests/e2e/test_oft_compose_with_uln.cairo +364 -0
- package/layerzero/tests/e2e/test_oft_with_sml.cairo +240 -0
- package/layerzero/tests/e2e/test_oft_with_uln.cairo +299 -0
- package/layerzero/tests/e2e/utils.cairo +490 -0
- package/layerzero/tests/endpoint/message_lib_manager/test_message_lib_manager.cairo +2051 -0
- package/layerzero/tests/endpoint/message_lib_manager/utils.cairo +45 -0
- package/layerzero/tests/endpoint/messaging_channel/test_messaging_channel.cairo +621 -0
- package/layerzero/tests/endpoint/messaging_channel/utils.cairo +96 -0
- package/layerzero/tests/endpoint/messaging_composer/test_messaging_composer.cairo +456 -0
- package/layerzero/tests/endpoint/messaging_composer/utils.cairo +75 -0
- package/layerzero/tests/endpoint/test_endpoint_commit.cairo +763 -0
- package/layerzero/tests/endpoint/test_endpoint_lzreceive.cairo +1253 -0
- package/layerzero/tests/endpoint/test_endpoint_quote.cairo +71 -0
- package/layerzero/tests/endpoint/test_endpoint_send.cairo +1327 -0
- package/layerzero/tests/endpoint/utils.cairo +129 -0
- package/layerzero/tests/fuzzable/blockchain_config.cairo +89 -0
- package/layerzero/tests/fuzzable/bytes32.cairo +16 -0
- package/layerzero/tests/fuzzable/contract_address.cairo +67 -0
- package/layerzero/tests/fuzzable/dst_config.cairo +37 -0
- package/layerzero/tests/fuzzable/eid.cairo +23 -0
- package/layerzero/tests/fuzzable/eth_address.cairo +17 -0
- package/layerzero/tests/fuzzable/expiry.cairo +27 -0
- package/layerzero/tests/fuzzable/felt_array.cairo +38 -0
- package/layerzero/tests/fuzzable/inbound_params.cairo +21 -0
- package/layerzero/tests/fuzzable/keys.cairo +16 -0
- package/layerzero/tests/fuzzable/model_type.cairo +27 -0
- package/layerzero/tests/fuzzable/origin.cairo +21 -0
- package/layerzero/tests/fuzzable/price.cairo +32 -0
- package/layerzero/tests/fuzzable/role_admin.cairo +29 -0
- package/layerzero/tests/fuzzable/small_byte_array.cairo +61 -0
- package/layerzero/tests/lib.cairo +177 -0
- package/layerzero/tests/message_lib/sml/test_simple_message_lib.cairo +224 -0
- package/layerzero/tests/message_lib/uln/test_uln_admin.cairo +2150 -0
- package/layerzero/tests/message_lib/uln/test_uln_config.cairo +527 -0
- package/layerzero/tests/message_lib/uln/test_uln_config_storage_node.cairo +69 -0
- package/layerzero/tests/message_lib/uln/test_uln_executor_config.cairo +173 -0
- package/layerzero/tests/message_lib/uln/test_uln_options.cairo +329 -0
- package/layerzero/tests/message_lib/uln/test_uln_quote.cairo +1038 -0
- package/layerzero/tests/message_lib/uln/test_uln_receive.cairo +715 -0
- package/layerzero/tests/message_lib/uln/test_uln_send.cairo +1155 -0
- package/layerzero/tests/message_lib/uln/utils.cairo +59 -0
- package/layerzero/tests/mocks/composer_target.cairo +76 -0
- package/layerzero/tests/mocks/endpoint.cairo +199 -0
- package/layerzero/tests/mocks/erc20/erc20.cairo +50 -0
- package/layerzero/tests/mocks/erc20/interface.cairo +8 -0
- package/layerzero/tests/mocks/message_inspector/message_inspector.cairo +17 -0
- package/layerzero/tests/mocks/message_lib_manager.cairo +98 -0
- package/layerzero/tests/mocks/messaging_channel/interface.cairo +23 -0
- package/layerzero/tests/mocks/messaging_channel/messaging_channel.cairo +138 -0
- package/layerzero/tests/mocks/messaging_composer.cairo +171 -0
- package/layerzero/tests/mocks/oapp_core/interface.cairo +53 -0
- package/layerzero/tests/mocks/oapp_core/oapp_core.cairo +142 -0
- package/layerzero/tests/mocks/oapp_options_type3.cairo +42 -0
- package/layerzero/tests/mocks/oft_core/interface.cairo +28 -0
- package/layerzero/tests/mocks/oft_core/oft_core.cairo +242 -0
- package/layerzero/tests/mocks/receiver.cairo +54 -0
- package/layerzero/tests/mocks/treasury/lz_token_fee_lib.cairo +57 -0
- package/layerzero/tests/mocks/treasury/treasury.cairo +74 -0
- package/layerzero/tests/mocks/uln_config/interface.cairo +12 -0
- package/layerzero/tests/mocks/uln_config/uln_config.cairo +35 -0
- package/layerzero/tests/mocks/workers/base.cairo +80 -0
- package/layerzero/tests/mocks/workers/dvn.cairo +115 -0
- package/layerzero/tests/mocks/workers/executor/decode/decode.cairo +97 -0
- package/layerzero/tests/mocks/workers/executor/decode/interface.cairo +59 -0
- package/layerzero/tests/mocks/workers/executor/executor.cairo +176 -0
- package/layerzero/tests/oapps/common/test_oapp_options_type_3.cairo +279 -0
- package/layerzero/tests/oapps/oft/test_oft_adapter.cairo +441 -0
- package/layerzero/tests/oapps/oft/test_oft_compose_msg_codec.cairo +139 -0
- package/layerzero/tests/oapps/oft/test_oft_core.cairo +751 -0
- package/layerzero/tests/oapps/oft/test_oft_msg_codec.cairo +268 -0
- package/layerzero/tests/oapps/test_counter.cairo +470 -0
- package/layerzero/tests/oapps/test_oapp_core.cairo +750 -0
- package/layerzero/tests/treasury/test_lz_token_fee_lib.cairo +63 -0
- package/layerzero/tests/treasury/test_treasury.cairo +458 -0
- package/layerzero/tests/treasury/utils.cairo +8 -0
- package/layerzero/tests/utils.cairo +48 -0
- package/layerzero/tests/workers/base/test_worker_base.cairo +1097 -0
- package/layerzero/tests/workers/base/utils.cairo +76 -0
- package/layerzero/tests/workers/dvn/fee_lib/test_dvn_fee_lib.cairo +361 -0
- package/layerzero/tests/workers/dvn/test_dvn.cairo +1101 -0
- package/layerzero/tests/workers/dvn/test_dvn_options.cairo +312 -0
- package/layerzero/tests/workers/dvn/utils.cairo +236 -0
- package/layerzero/tests/workers/executor/fee_lib/test_executor_fee_lib.cairo +223 -0
- package/layerzero/tests/workers/executor/test_decode.cairo +612 -0
- package/layerzero/tests/workers/executor/test_executor.cairo +1472 -0
- package/layerzero/tests/workers/executor/utils.cairo +296 -0
- package/layerzero/tests/workers/price_feed/test_price_feed.cairo +879 -0
- package/layerzero/tests/workers/price_feed/utils.cairo +37 -0
- package/libs/enumerable_set/Scarb.lock +24 -0
- package/libs/enumerable_set/Scarb.toml +17 -0
- package/libs/enumerable_set/src/enumerable_set.cairo +118 -0
- package/libs/enumerable_set/src/lib.cairo +4 -0
- package/libs/enumerable_set/tests/lib.cairo +5 -0
- package/libs/enumerable_set/tests/mocks/mock_enumerable_set.cairo +61 -0
- package/libs/enumerable_set/tests/test_enumerable_set.cairo +379 -0
- package/libs/lz_utils/Scarb.lock +24 -0
- package/libs/lz_utils/Scarb.toml +17 -0
- package/libs/lz_utils/src/bytes.cairo +33 -0
- package/libs/lz_utils/src/error.cairo +12 -0
- package/libs/lz_utils/src/keccak.cairo +28 -0
- package/libs/lz_utils/src/lib.cairo +3 -0
- package/libs/multisig/Scarb.lock +172 -0
- package/libs/multisig/Scarb.toml +23 -0
- package/libs/multisig/src/errors.cairo +84 -0
- package/libs/multisig/src/events.cairo +13 -0
- package/libs/multisig/src/interface.cairo +73 -0
- package/libs/multisig/src/lib.cairo +7 -0
- package/libs/multisig/src/multisig.cairo +241 -0
- package/libs/multisig/tests/lib.cairo +4 -0
- package/libs/multisig/tests/mocks/mock_multisig.cairo +57 -0
- package/libs/multisig/tests/test_multisig.cairo +452 -0
- package/package.json +41 -0
- package/src/scripts/build-abi.ts +51 -0
- package/target/CACHEDIR.TAG +3 -0
- package/target/dev/.fingerprint/alexandria_bytes-5ea6u5t70d7qi/alexandria_bytes +1 -0
- package/target/dev/.fingerprint/alexandria_data_structures-0aue3g6q80gs0/alexandria_data_structures +1 -0
- package/target/dev/.fingerprint/alexandria_math-h2fi7jdq4isuu/alexandria_math +1 -0
- package/target/dev/.fingerprint/core-lq3u730l5p1ag/core +1 -0
- package/target/dev/.fingerprint/core-vf7fc6rvic5vi/core +1 -0
- package/target/dev/.fingerprint/enumerable_set-eaerkg8njl85o/enumerable_set +1 -0
- package/target/dev/.fingerprint/enumerable_set-r54oje7t06ku8/enumerable_set +1 -0
- package/target/dev/.fingerprint/layerzero-oqgdqsaddpi2k/layerzero +1 -0
- package/target/dev/.fingerprint/lz_utils-kfkkeueiqg0pa/lz_utils +1 -0
- package/target/dev/.fingerprint/lz_utils-u4v1os6e7gkng/lz_utils +1 -0
- package/target/dev/.fingerprint/multisig-0fjetugejecge/multisig +1 -0
- package/target/dev/.fingerprint/multisig-6j5kqs436hm54/multisig +1 -0
- package/target/dev/.fingerprint/openzeppelin-ei1id1hu088lo/openzeppelin +1 -0
- package/target/dev/.fingerprint/openzeppelin-j9d5nd1qhfnu6/openzeppelin +1 -0
- package/target/dev/.fingerprint/openzeppelin_access-3oa41aikpaek0/openzeppelin_access +1 -0
- package/target/dev/.fingerprint/openzeppelin_access-p5h849v8so76q/openzeppelin_access +1 -0
- package/target/dev/.fingerprint/openzeppelin_account-4qhv5fks84g9u/openzeppelin_account +1 -0
- package/target/dev/.fingerprint/openzeppelin_account-hgbm8ln9ah7rm/openzeppelin_account +1 -0
- package/target/dev/.fingerprint/openzeppelin_finance-n70q9al0cps8i/openzeppelin_finance +1 -0
- package/target/dev/.fingerprint/openzeppelin_finance-nnd4f8703t3ak/openzeppelin_finance +1 -0
- package/target/dev/.fingerprint/openzeppelin_governance-3gnk21ubp5lis/openzeppelin_governance +1 -0
- package/target/dev/.fingerprint/openzeppelin_governance-rj1bfont4fij4/openzeppelin_governance +1 -0
- package/target/dev/.fingerprint/openzeppelin_introspection-3fja9hd1gvbcq/openzeppelin_introspection +1 -0
- package/target/dev/.fingerprint/openzeppelin_introspection-jc3nf5525eet6/openzeppelin_introspection +1 -0
- package/target/dev/.fingerprint/openzeppelin_merkle_tree-4en77ogr2r2l2/openzeppelin_merkle_tree +1 -0
- package/target/dev/.fingerprint/openzeppelin_merkle_tree-4t190frqs4db8/openzeppelin_merkle_tree +1 -0
- package/target/dev/.fingerprint/openzeppelin_presets-aqb0f6p9c0bp6/openzeppelin_presets +1 -0
- package/target/dev/.fingerprint/openzeppelin_presets-nseg8korhin8e/openzeppelin_presets +1 -0
- package/target/dev/.fingerprint/openzeppelin_security-g7p73ji1ih1qg/openzeppelin_security +1 -0
- package/target/dev/.fingerprint/openzeppelin_security-qp5328v80452u/openzeppelin_security +1 -0
- package/target/dev/.fingerprint/openzeppelin_token-jjf7tl9rphc6k/openzeppelin_token +1 -0
- package/target/dev/.fingerprint/openzeppelin_token-r6s43vlpj6rqk/openzeppelin_token +1 -0
- package/target/dev/.fingerprint/openzeppelin_upgrades-0dpbnre7engca/openzeppelin_upgrades +1 -0
- package/target/dev/.fingerprint/openzeppelin_upgrades-2sqgvbuv9s800/openzeppelin_upgrades +1 -0
- package/target/dev/.fingerprint/openzeppelin_utils-mj395ivff1ffo/openzeppelin_utils +1 -0
- package/target/dev/.fingerprint/openzeppelin_utils-oh1hse8sjumgm/openzeppelin_utils +1 -0
- package/target/dev/.fingerprint/starkware_utils-1qnnjnq0pf9u0/starkware_utils +1 -0
- package/target/dev/.fingerprint/starkware_utils-mh8e3te65lju4/starkware_utils +1 -0
- package/target/dev/enumerable_set.sierra.json +1 -0
- package/target/dev/incremental/alexandria_bytes-5ea6u5t70d7qi.bin +0 -0
- package/target/dev/incremental/alexandria_data_structures-0aue3g6q80gs0.bin +0 -0
- package/target/dev/incremental/alexandria_math-h2fi7jdq4isuu.bin +0 -0
- package/target/dev/incremental/core-lq3u730l5p1ag.bin +0 -0
- package/target/dev/incremental/core-vf7fc6rvic5vi.bin +0 -0
- package/target/dev/incremental/enumerable_set-eaerkg8njl85o.bin +0 -0
- package/target/dev/incremental/enumerable_set-r54oje7t06ku8.bin +0 -0
- package/target/dev/incremental/layerzero-oqgdqsaddpi2k.bin +0 -0
- package/target/dev/incremental/lz_utils-kfkkeueiqg0pa.bin +0 -0
- package/target/dev/incremental/lz_utils-u4v1os6e7gkng.bin +0 -0
- package/target/dev/incremental/multisig-0fjetugejecge.bin +0 -0
- package/target/dev/incremental/multisig-6j5kqs436hm54.bin +0 -0
- package/target/dev/incremental/openzeppelin-ei1id1hu088lo.bin +0 -0
- package/target/dev/incremental/openzeppelin-j9d5nd1qhfnu6.bin +0 -0
- package/target/dev/incremental/openzeppelin_access-3oa41aikpaek0.bin +0 -0
- package/target/dev/incremental/openzeppelin_access-p5h849v8so76q.bin +0 -0
- package/target/dev/incremental/openzeppelin_account-4qhv5fks84g9u.bin +0 -0
- package/target/dev/incremental/openzeppelin_account-hgbm8ln9ah7rm.bin +0 -0
- package/target/dev/incremental/openzeppelin_finance-n70q9al0cps8i.bin +0 -0
- package/target/dev/incremental/openzeppelin_finance-nnd4f8703t3ak.bin +0 -0
- package/target/dev/incremental/openzeppelin_governance-3gnk21ubp5lis.bin +0 -0
- package/target/dev/incremental/openzeppelin_governance-rj1bfont4fij4.bin +0 -0
- package/target/dev/incremental/openzeppelin_introspection-3fja9hd1gvbcq.bin +0 -0
- package/target/dev/incremental/openzeppelin_introspection-jc3nf5525eet6.bin +0 -0
- package/target/dev/incremental/openzeppelin_merkle_tree-4en77ogr2r2l2.bin +0 -0
- package/target/dev/incremental/openzeppelin_merkle_tree-4t190frqs4db8.bin +0 -0
- package/target/dev/incremental/openzeppelin_presets-aqb0f6p9c0bp6.bin +0 -0
- package/target/dev/incremental/openzeppelin_presets-nseg8korhin8e.bin +0 -0
- package/target/dev/incremental/openzeppelin_security-g7p73ji1ih1qg.bin +0 -0
- package/target/dev/incremental/openzeppelin_security-qp5328v80452u.bin +0 -0
- package/target/dev/incremental/openzeppelin_token-jjf7tl9rphc6k.bin +0 -0
- package/target/dev/incremental/openzeppelin_token-r6s43vlpj6rqk.bin +0 -0
- package/target/dev/incremental/openzeppelin_upgrades-0dpbnre7engca.bin +0 -0
- package/target/dev/incremental/openzeppelin_upgrades-2sqgvbuv9s800.bin +0 -0
- package/target/dev/incremental/openzeppelin_utils-mj395ivff1ffo.bin +0 -0
- package/target/dev/incremental/openzeppelin_utils-oh1hse8sjumgm.bin +0 -0
- package/target/dev/incremental/starkware_utils-1qnnjnq0pf9u0.bin +0 -0
- package/target/dev/incremental/starkware_utils-mh8e3te65lju4.bin +0 -0
- package/target/dev/layerzero.starknet_artifacts.json +1 -0
- package/target/dev/layerzero_BlockedMessageLib.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_BlockedMessageLib.contract_class.json +1 -0
- package/target/dev/layerzero_Dvn.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_Dvn.contract_class.json +1 -0
- package/target/dev/layerzero_DvnFeeLib.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_DvnFeeLib.contract_class.json +1 -0
- package/target/dev/layerzero_Endpoint.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_Endpoint.contract_class.json +1 -0
- package/target/dev/layerzero_Executor.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_Executor.contract_class.json +1 -0
- package/target/dev/layerzero_ExecutorFeeLib.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_ExecutorFeeLib.contract_class.json +1 -0
- package/target/dev/layerzero_OApp.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_OApp.contract_class.json +1 -0
- package/target/dev/layerzero_OFT.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_OFT.contract_class.json +1 -0
- package/target/dev/layerzero_OFTAdapter.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_OFTAdapter.contract_class.json +1 -0
- package/target/dev/layerzero_OmniCounter.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_OmniCounter.contract_class.json +1 -0
- package/target/dev/layerzero_PriceFeed.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_PriceFeed.contract_class.json +1 -0
- package/target/dev/layerzero_SimpleMessageLib.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_SimpleMessageLib.contract_class.json +1 -0
- package/target/dev/layerzero_Treasury.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_Treasury.contract_class.json +1 -0
- package/target/dev/layerzero_UltraLightNode.compiled_contract_class.json +1 -0
- package/target/dev/layerzero_UltraLightNode.contract_class.json +1 -0
- package/target/dev/lz_utils.sierra.json +1 -0
- package/target/dev/multisig.sierra.json +1 -0
- package/tools/update_contracts.sh +19 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +7 -0
|
@@ -0,0 +1,1097 @@
|
|
|
1
|
+
//! Base worker tests
|
|
2
|
+
|
|
3
|
+
use layerzero::common::constants::ZERO_ADDRESS;
|
|
4
|
+
use layerzero::workers::access_control::{ADMIN_ROLE, DEFAULT_ADMIN_ROLE, MESSAGE_LIB_ROLE};
|
|
5
|
+
use layerzero::workers::base::base::WorkerBaseComponent;
|
|
6
|
+
use layerzero::workers::base::errors;
|
|
7
|
+
use layerzero::workers::base::events::{
|
|
8
|
+
DefaultMultiplierBpsSet, FeeWithdrawn, SupportedOptionTypeSet, WorkerFeeLibSet,
|
|
9
|
+
};
|
|
10
|
+
use layerzero::workers::base::interface::{
|
|
11
|
+
IWorkerBaseDispatcherTrait, IWorkerBaseSafeDispatcherTrait,
|
|
12
|
+
};
|
|
13
|
+
use openzeppelin::access::accesscontrol::AccessControlComponent;
|
|
14
|
+
use openzeppelin::access::accesscontrol::interface::{
|
|
15
|
+
IAccessControlDispatcherTrait, IAccessControlSafeDispatcherTrait,
|
|
16
|
+
};
|
|
17
|
+
use openzeppelin::security::interface::{IPausableDispatcher, IPausableDispatcherTrait};
|
|
18
|
+
use openzeppelin::security::pausable::PausableComponent;
|
|
19
|
+
use openzeppelin::token::erc20::ERC20Component::{
|
|
20
|
+
Errors as ERC20Errors, Event as ERC20Event, Transfer,
|
|
21
|
+
};
|
|
22
|
+
use openzeppelin::token::erc20::interface::IERC20DispatcherTrait;
|
|
23
|
+
use snforge_std::fuzzable::{FuzzableU16, FuzzableU256};
|
|
24
|
+
use snforge_std::{
|
|
25
|
+
EventSpyAssertionsTrait, spy_events, start_cheat_caller_address, stop_cheat_caller_address,
|
|
26
|
+
};
|
|
27
|
+
use starknet::ContractAddress;
|
|
28
|
+
use starkware_utils_testing::test_utils::{assert_panic_with_error, assert_panic_with_felt_error};
|
|
29
|
+
use crate::fuzzable::contract_address::{
|
|
30
|
+
ContractAddressArrayList, FuzzableContractAddress, FuzzableContractAddresses,
|
|
31
|
+
};
|
|
32
|
+
use crate::fuzzable::eid::{Eid, FuzzableEid};
|
|
33
|
+
use crate::fuzzable::role_admin::{FuzzableRoleAdmin, RoleAdmin};
|
|
34
|
+
use crate::workers::base::utils::{
|
|
35
|
+
ERC20Mock, WorkerBaseMock, deploy_mock_erc20, deploy_worker_base,
|
|
36
|
+
deploy_worker_base_with_additional_roles,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
//////////////////////////
|
|
40
|
+
// Initialization tests //
|
|
41
|
+
//////////////////////////
|
|
42
|
+
|
|
43
|
+
#[test]
|
|
44
|
+
#[fuzzer(runs: 10)]
|
|
45
|
+
fn sets_initial_roles(
|
|
46
|
+
role_admin: RoleAdmin,
|
|
47
|
+
price_feed: ContractAddress,
|
|
48
|
+
message_libs: ContractAddressArrayList,
|
|
49
|
+
admins: ContractAddressArrayList,
|
|
50
|
+
) {
|
|
51
|
+
let role_admin = role_admin.address;
|
|
52
|
+
let WorkerBaseMock {
|
|
53
|
+
access_control, ..,
|
|
54
|
+
} =
|
|
55
|
+
deploy_worker_base_with_additional_roles(
|
|
56
|
+
message_libs.arr.span(), price_feed, role_admin, admins.arr.span(),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Check that role_admin is only the role admin
|
|
60
|
+
assert(access_control.has_role(DEFAULT_ADMIN_ROLE, role_admin), 'Role admin should be set');
|
|
61
|
+
assert(!access_control.has_role(ADMIN_ROLE, role_admin), 'Role admin should not be admin');
|
|
62
|
+
assert!(
|
|
63
|
+
!access_control.has_role(MESSAGE_LIB_ROLE, role_admin), "Role admin should not be msg lib",
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Check that message libs are only message libs
|
|
67
|
+
for message_lib in message_libs.arr {
|
|
68
|
+
assert(access_control.has_role(MESSAGE_LIB_ROLE, message_lib), 'Msg lib should be set');
|
|
69
|
+
assert(!access_control.has_role(ADMIN_ROLE, message_lib), 'Msg lib should not be admin');
|
|
70
|
+
assert!(
|
|
71
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, message_lib),
|
|
72
|
+
"Msg lib should not be role admin",
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check that admins are only admins
|
|
77
|
+
for admin in admins.arr {
|
|
78
|
+
assert(access_control.has_role(ADMIN_ROLE, admin), 'Admin should be set');
|
|
79
|
+
assert(!access_control.has_role(MESSAGE_LIB_ROLE, admin), 'Admin should not be msg lib');
|
|
80
|
+
assert(
|
|
81
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, admin), 'Admin should not be role admin',
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
#[test]
|
|
87
|
+
#[fuzzer(runs: 10)]
|
|
88
|
+
fn does_not_set_zero_admin(
|
|
89
|
+
price_feed: ContractAddress,
|
|
90
|
+
message_libs: ContractAddressArrayList,
|
|
91
|
+
admins: ContractAddressArrayList,
|
|
92
|
+
) {
|
|
93
|
+
let WorkerBaseMock {
|
|
94
|
+
access_control, ..,
|
|
95
|
+
} =
|
|
96
|
+
deploy_worker_base_with_additional_roles(
|
|
97
|
+
message_libs.arr.span(), price_feed, ZERO_ADDRESS, admins.arr.span(),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Check that zero address is not set as any role
|
|
101
|
+
assert!(
|
|
102
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, ZERO_ADDRESS),
|
|
103
|
+
"Zero address should not be role admin",
|
|
104
|
+
);
|
|
105
|
+
assert!(!access_control.has_role(ADMIN_ROLE, ZERO_ADDRESS), "Zero address should not be admin");
|
|
106
|
+
assert!(
|
|
107
|
+
!access_control.has_role(MESSAGE_LIB_ROLE, ZERO_ADDRESS),
|
|
108
|
+
"Zero address should not be msg lib",
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Check that message libs are only message libs
|
|
112
|
+
for message_lib in message_libs.arr {
|
|
113
|
+
assert(access_control.has_role(MESSAGE_LIB_ROLE, message_lib), 'Msg lib should be set');
|
|
114
|
+
assert(!access_control.has_role(ADMIN_ROLE, message_lib), 'Msg lib should not be admin');
|
|
115
|
+
assert!(
|
|
116
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, message_lib),
|
|
117
|
+
"Msg lib should not be role admin",
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Check that admins are only admins
|
|
122
|
+
for admin in admins.arr {
|
|
123
|
+
assert(access_control.has_role(ADMIN_ROLE, admin), 'Admin should be set');
|
|
124
|
+
assert(!access_control.has_role(MESSAGE_LIB_ROLE, admin), 'Admin should not be msg lib');
|
|
125
|
+
assert(
|
|
126
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, admin), 'Admin should not be role admin',
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#[test]
|
|
132
|
+
#[fuzzer(runs: 10)]
|
|
133
|
+
fn set_initial_price_feed_succeeds(role_admin: ContractAddress, price_feed: ContractAddress) {
|
|
134
|
+
let WorkerBaseMock { dispatcher, .. } = deploy_worker_base(price_feed, role_admin);
|
|
135
|
+
assert(dispatcher.get_price_feed() == price_feed, 'Price feed should be set');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//////////////////////
|
|
139
|
+
// Price feed tests //
|
|
140
|
+
//////////////////////
|
|
141
|
+
|
|
142
|
+
#[test]
|
|
143
|
+
#[fuzzer(runs: 10)]
|
|
144
|
+
fn set_price_feed_succeeds_when_admin(
|
|
145
|
+
role_admin: RoleAdmin,
|
|
146
|
+
admin: ContractAddress,
|
|
147
|
+
price_feed: ContractAddress,
|
|
148
|
+
new_price_feed: ContractAddress,
|
|
149
|
+
) {
|
|
150
|
+
let role_admin = role_admin.address;
|
|
151
|
+
let WorkerBaseMock {
|
|
152
|
+
worker, dispatcher, ..,
|
|
153
|
+
} =
|
|
154
|
+
deploy_worker_base_with_additional_roles(
|
|
155
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Set price feed
|
|
159
|
+
// Caller has admin role
|
|
160
|
+
start_cheat_caller_address(worker, admin);
|
|
161
|
+
dispatcher.set_price_feed(new_price_feed);
|
|
162
|
+
stop_cheat_caller_address(worker);
|
|
163
|
+
|
|
164
|
+
// Check that price feed is set
|
|
165
|
+
assert(dispatcher.get_price_feed() == new_price_feed, 'Price feed should be set');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#[test]
|
|
169
|
+
#[fuzzer(runs: 10)]
|
|
170
|
+
#[feature("safe_dispatcher")]
|
|
171
|
+
fn set_price_feed_fails_when_not_admin(
|
|
172
|
+
role_admin: RoleAdmin, not_admin: ContractAddress, price_feed: ContractAddress,
|
|
173
|
+
) {
|
|
174
|
+
let role_admin = role_admin.address;
|
|
175
|
+
let WorkerBaseMock {
|
|
176
|
+
worker, safe_dispatcher, access_control, ..,
|
|
177
|
+
} = deploy_worker_base(price_feed, role_admin);
|
|
178
|
+
|
|
179
|
+
// Check that not_admin does not have the admin role
|
|
180
|
+
assert(!access_control.has_role(ADMIN_ROLE, not_admin), 'Should not have admin role');
|
|
181
|
+
|
|
182
|
+
// Attempt to set price feed
|
|
183
|
+
// Caller does not have admin role
|
|
184
|
+
start_cheat_caller_address(worker, role_admin);
|
|
185
|
+
let res = safe_dispatcher.set_price_feed(price_feed);
|
|
186
|
+
stop_cheat_caller_address(worker);
|
|
187
|
+
|
|
188
|
+
// Should panic with missing role error because role_admin does not have admin role
|
|
189
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
190
|
+
|
|
191
|
+
// Attempt to set price feed
|
|
192
|
+
// Caller does not have admin role
|
|
193
|
+
start_cheat_caller_address(worker, not_admin);
|
|
194
|
+
let res = safe_dispatcher.set_price_feed(price_feed);
|
|
195
|
+
stop_cheat_caller_address(worker);
|
|
196
|
+
|
|
197
|
+
// Should panic with missing role error because not_admin does not have admin role
|
|
198
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#[test]
|
|
202
|
+
#[fuzzer(runs: 10)]
|
|
203
|
+
#[feature("safe_dispatcher")]
|
|
204
|
+
fn set_price_feed_fails_when_msg_lib(
|
|
205
|
+
role_admin: RoleAdmin, msg_lib: ContractAddress, price_feed: ContractAddress,
|
|
206
|
+
) {
|
|
207
|
+
let role_admin = role_admin.address;
|
|
208
|
+
let WorkerBaseMock {
|
|
209
|
+
worker, safe_dispatcher, ..,
|
|
210
|
+
} =
|
|
211
|
+
deploy_worker_base_with_additional_roles(
|
|
212
|
+
array![msg_lib].span(), price_feed, role_admin, array![].span(),
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
// Attempt to set price feed
|
|
216
|
+
// Caller has msg lib role
|
|
217
|
+
start_cheat_caller_address(worker, msg_lib);
|
|
218
|
+
let res = safe_dispatcher.set_price_feed(price_feed);
|
|
219
|
+
stop_cheat_caller_address(worker);
|
|
220
|
+
|
|
221
|
+
// Should panic with missing role error because msg_lib does not have admin role
|
|
222
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#[test]
|
|
226
|
+
#[fuzzer(runs: 10)]
|
|
227
|
+
fn set_multiple_price_feeds_succeeds(
|
|
228
|
+
role_admin: RoleAdmin,
|
|
229
|
+
admin: ContractAddress,
|
|
230
|
+
price_feed: ContractAddress,
|
|
231
|
+
first_new_price_feed: ContractAddress,
|
|
232
|
+
second_new_price_feed: ContractAddress,
|
|
233
|
+
) {
|
|
234
|
+
let role_admin = role_admin.address;
|
|
235
|
+
let WorkerBaseMock {
|
|
236
|
+
worker, dispatcher, ..,
|
|
237
|
+
} =
|
|
238
|
+
deploy_worker_base_with_additional_roles(
|
|
239
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Caller has admin role
|
|
243
|
+
start_cheat_caller_address(worker, admin);
|
|
244
|
+
|
|
245
|
+
// First price feed update
|
|
246
|
+
dispatcher.set_price_feed(first_new_price_feed);
|
|
247
|
+
let price_feed = dispatcher.get_price_feed();
|
|
248
|
+
assert(price_feed == first_new_price_feed, 'First update should succeed');
|
|
249
|
+
|
|
250
|
+
// Second price feed update
|
|
251
|
+
dispatcher.set_price_feed(second_new_price_feed);
|
|
252
|
+
let price_feed = dispatcher.get_price_feed();
|
|
253
|
+
assert(price_feed == second_new_price_feed, 'Second update should succeed');
|
|
254
|
+
|
|
255
|
+
stop_cheat_caller_address(worker);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/////////////////////////////////
|
|
259
|
+
// Supported option type tests //
|
|
260
|
+
/////////////////////////////////
|
|
261
|
+
|
|
262
|
+
/// An admin can set the supported option type for an EID - corresponding event is emitted
|
|
263
|
+
#[test]
|
|
264
|
+
#[fuzzer(runs: 10)]
|
|
265
|
+
fn set_supported_option_type_succeeds_when_admin(
|
|
266
|
+
role_admin: RoleAdmin,
|
|
267
|
+
price_feed: ContractAddress,
|
|
268
|
+
admin: ContractAddress,
|
|
269
|
+
eid: Eid,
|
|
270
|
+
option_type: ByteArray,
|
|
271
|
+
) {
|
|
272
|
+
let eid = eid.eid;
|
|
273
|
+
let role_admin = role_admin.address;
|
|
274
|
+
let WorkerBaseMock {
|
|
275
|
+
worker, dispatcher, ..,
|
|
276
|
+
} =
|
|
277
|
+
deploy_worker_base_with_additional_roles(
|
|
278
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
let mut spy = spy_events();
|
|
282
|
+
|
|
283
|
+
// Caller has admin role
|
|
284
|
+
start_cheat_caller_address(worker, admin);
|
|
285
|
+
dispatcher.set_supported_option_type(eid, option_type.clone());
|
|
286
|
+
stop_cheat_caller_address(worker);
|
|
287
|
+
|
|
288
|
+
// Check that supported option type is set
|
|
289
|
+
assert!(
|
|
290
|
+
dispatcher.get_supported_option_type(eid) == option_type,
|
|
291
|
+
"Supported option type should be set",
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
// Verify SupportedOptionTypeSet event was emitted
|
|
295
|
+
let expected_event = WorkerBaseComponent::Event::SupportedOptionTypeSet(
|
|
296
|
+
SupportedOptionTypeSet { eid, option_type },
|
|
297
|
+
);
|
|
298
|
+
spy.assert_emitted(@array![(worker, expected_event)]);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/// A non-admin cannot set the supported option type for an EID - no event is emitted
|
|
302
|
+
#[test]
|
|
303
|
+
#[fuzzer(runs: 10)]
|
|
304
|
+
#[feature("safe_dispatcher")]
|
|
305
|
+
fn set_supported_option_type_fails_when_not_admin(
|
|
306
|
+
role_admin: RoleAdmin,
|
|
307
|
+
price_feed: ContractAddress,
|
|
308
|
+
not_admin: ContractAddress,
|
|
309
|
+
eid: Eid,
|
|
310
|
+
option_type: ByteArray,
|
|
311
|
+
) {
|
|
312
|
+
let eid = eid.eid;
|
|
313
|
+
let role_admin = role_admin.address;
|
|
314
|
+
let WorkerBaseMock { worker, safe_dispatcher, .. } = deploy_worker_base(price_feed, role_admin);
|
|
315
|
+
|
|
316
|
+
let mut spy = spy_events();
|
|
317
|
+
|
|
318
|
+
// Caller does not have admin role
|
|
319
|
+
start_cheat_caller_address(worker, not_admin);
|
|
320
|
+
let res = safe_dispatcher.set_supported_option_type(eid, option_type.clone());
|
|
321
|
+
stop_cheat_caller_address(worker);
|
|
322
|
+
|
|
323
|
+
// Should panic with missing role error because not_admin does not have admin role
|
|
324
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
325
|
+
|
|
326
|
+
// Check that supported option type is not set
|
|
327
|
+
assert!(
|
|
328
|
+
safe_dispatcher.get_supported_option_type(eid).unwrap() == Default::default(),
|
|
329
|
+
"Supported option type should not be set",
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
// Verify SupportedOptionTypeSet event was not emitted
|
|
333
|
+
let event = WorkerBaseComponent::Event::SupportedOptionTypeSet(
|
|
334
|
+
SupportedOptionTypeSet { eid, option_type },
|
|
335
|
+
);
|
|
336
|
+
spy.assert_not_emitted(@array![(worker, event)]);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
//////////////////////////
|
|
340
|
+
// Access control tests //
|
|
341
|
+
//////////////////////////
|
|
342
|
+
|
|
343
|
+
/// The role admin can grant all roles
|
|
344
|
+
#[test]
|
|
345
|
+
#[fuzzer(runs: 10)]
|
|
346
|
+
fn access_control_grant_all_roles_succeed_when_role_admin(
|
|
347
|
+
role_admin: RoleAdmin,
|
|
348
|
+
new_role_admin: ContractAddress,
|
|
349
|
+
admin: ContractAddress,
|
|
350
|
+
msg_lib: ContractAddress,
|
|
351
|
+
price_feed: ContractAddress,
|
|
352
|
+
) {
|
|
353
|
+
let role_admin = role_admin.address;
|
|
354
|
+
let WorkerBaseMock { worker, access_control, .. } = deploy_worker_base(price_feed, role_admin);
|
|
355
|
+
|
|
356
|
+
// Role admin grants new role admin
|
|
357
|
+
// Caller is the role admin
|
|
358
|
+
start_cheat_caller_address(worker, role_admin);
|
|
359
|
+
access_control.grant_role(DEFAULT_ADMIN_ROLE, new_role_admin);
|
|
360
|
+
stop_cheat_caller_address(worker);
|
|
361
|
+
|
|
362
|
+
// Check that new role admin is a role admin
|
|
363
|
+
assert(
|
|
364
|
+
access_control.has_role(DEFAULT_ADMIN_ROLE, new_role_admin), 'New role admin should be set',
|
|
365
|
+
);
|
|
366
|
+
assert!(
|
|
367
|
+
!access_control.has_role(ADMIN_ROLE, new_role_admin), "New role admin should not be admin",
|
|
368
|
+
);
|
|
369
|
+
assert!(
|
|
370
|
+
!access_control.has_role(MESSAGE_LIB_ROLE, new_role_admin),
|
|
371
|
+
"New role admin should not be msg lib",
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
// Role admin grants admin role
|
|
375
|
+
// Caller is the new role admin
|
|
376
|
+
start_cheat_caller_address(worker, role_admin);
|
|
377
|
+
access_control.grant_role(ADMIN_ROLE, admin);
|
|
378
|
+
stop_cheat_caller_address(worker);
|
|
379
|
+
|
|
380
|
+
// Check that admin only has the admin role
|
|
381
|
+
assert(access_control.has_role(ADMIN_ROLE, admin), 'Admin role should be set');
|
|
382
|
+
assert(!access_control.has_role(DEFAULT_ADMIN_ROLE, admin), 'Admin should not be role admin');
|
|
383
|
+
assert(!access_control.has_role(MESSAGE_LIB_ROLE, admin), 'Admin should not be msg lib');
|
|
384
|
+
|
|
385
|
+
// Role admin grants msg lib role
|
|
386
|
+
// Caller is the role admin
|
|
387
|
+
start_cheat_caller_address(worker, new_role_admin);
|
|
388
|
+
access_control.grant_role(MESSAGE_LIB_ROLE, msg_lib);
|
|
389
|
+
stop_cheat_caller_address(worker);
|
|
390
|
+
|
|
391
|
+
// Check that msg_lib has only the message lib role
|
|
392
|
+
assert!(access_control.has_role(MESSAGE_LIB_ROLE, msg_lib), "Msg lib role should be set");
|
|
393
|
+
assert!(!access_control.has_role(ADMIN_ROLE, msg_lib), "Msg lib should not be admin");
|
|
394
|
+
assert!(
|
|
395
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, msg_lib), "Msg lib should not be role admin",
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/// Only the role admin can grant roles
|
|
400
|
+
#[test]
|
|
401
|
+
#[fuzzer(runs: 10)]
|
|
402
|
+
#[feature("safe_dispatcher")]
|
|
403
|
+
fn access_control_grant_roles_fail_when_not_role_admin(
|
|
404
|
+
role_admin: ContractAddress,
|
|
405
|
+
not_role_admin: ContractAddress,
|
|
406
|
+
price_feed: ContractAddress,
|
|
407
|
+
grantee: ContractAddress,
|
|
408
|
+
message_libs: ContractAddressArrayList,
|
|
409
|
+
admins: ContractAddressArrayList,
|
|
410
|
+
) {
|
|
411
|
+
// Ensure role_admin and not_role_admin are different
|
|
412
|
+
if role_admin == not_role_admin {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
let WorkerBaseMock {
|
|
417
|
+
worker, access_control, safe_access_control, ..,
|
|
418
|
+
} =
|
|
419
|
+
deploy_worker_base_with_additional_roles(
|
|
420
|
+
message_libs.arr.span(), price_feed, role_admin, admins.arr.span(),
|
|
421
|
+
);
|
|
422
|
+
|
|
423
|
+
// Attempt to grant admin role
|
|
424
|
+
// Caller is not the role admin
|
|
425
|
+
start_cheat_caller_address(worker, not_role_admin);
|
|
426
|
+
let res = safe_access_control.grant_role(ADMIN_ROLE, grantee);
|
|
427
|
+
stop_cheat_caller_address(worker);
|
|
428
|
+
|
|
429
|
+
// Should panic with missing role error because not_role_admin is not a role admin
|
|
430
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
431
|
+
assert(!access_control.has_role(ADMIN_ROLE, grantee), 'Admin role should not be set');
|
|
432
|
+
|
|
433
|
+
// Attempt to grant message lib role
|
|
434
|
+
// Caller is not the role admin
|
|
435
|
+
start_cheat_caller_address(worker, not_role_admin);
|
|
436
|
+
let res = safe_access_control.grant_role(MESSAGE_LIB_ROLE, grantee);
|
|
437
|
+
stop_cheat_caller_address(worker);
|
|
438
|
+
|
|
439
|
+
// Should panic with missing role error because not_role_admin is not a role admin
|
|
440
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
441
|
+
assert(!access_control.has_role(MESSAGE_LIB_ROLE, grantee), 'Msg lib role should not be set');
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/// Admins cannot grant roles
|
|
445
|
+
#[test]
|
|
446
|
+
#[fuzzer(runs: 10)]
|
|
447
|
+
#[feature("safe_dispatcher")]
|
|
448
|
+
fn access_control_grant_roles_fail_when_admin(
|
|
449
|
+
role_admin: ContractAddress,
|
|
450
|
+
price_feed: ContractAddress,
|
|
451
|
+
grantee: ContractAddress,
|
|
452
|
+
admins: ContractAddressArrayList,
|
|
453
|
+
) {
|
|
454
|
+
let WorkerBaseMock {
|
|
455
|
+
worker, access_control, safe_access_control, ..,
|
|
456
|
+
} =
|
|
457
|
+
deploy_worker_base_with_additional_roles(
|
|
458
|
+
array![].span(), price_feed, role_admin, admins.arr.span(),
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
for admin in admins.arr {
|
|
462
|
+
// Ensure that admin and role_admin are different
|
|
463
|
+
if admin == role_admin {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Attempt to grant admin role
|
|
468
|
+
// Caller has admin role
|
|
469
|
+
start_cheat_caller_address(worker, admin);
|
|
470
|
+
let res = safe_access_control.grant_role(ADMIN_ROLE, grantee);
|
|
471
|
+
|
|
472
|
+
// Should panic with missing role error because admin is not a role admin
|
|
473
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
474
|
+
assert(!access_control.has_role(ADMIN_ROLE, grantee), 'Admin role should not be set');
|
|
475
|
+
|
|
476
|
+
// Attempt to grant message lib role
|
|
477
|
+
let res = safe_access_control.grant_role(MESSAGE_LIB_ROLE, grantee);
|
|
478
|
+
stop_cheat_caller_address(worker);
|
|
479
|
+
|
|
480
|
+
// Should panic with missing role error because admin is not a role admin
|
|
481
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
482
|
+
assert(
|
|
483
|
+
!access_control.has_role(MESSAGE_LIB_ROLE, grantee), 'Msg lib role should not be set',
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/// Message libs cannot grant roles
|
|
489
|
+
#[test]
|
|
490
|
+
#[fuzzer(runs: 10)]
|
|
491
|
+
#[feature("safe_dispatcher")]
|
|
492
|
+
fn access_control_grant_roles_fail_when_message_lib(
|
|
493
|
+
role_admin: ContractAddress,
|
|
494
|
+
price_feed: ContractAddress,
|
|
495
|
+
grantee: ContractAddress,
|
|
496
|
+
message_libs: ContractAddressArrayList,
|
|
497
|
+
) {
|
|
498
|
+
let WorkerBaseMock {
|
|
499
|
+
worker, access_control, safe_access_control, ..,
|
|
500
|
+
} =
|
|
501
|
+
deploy_worker_base_with_additional_roles(
|
|
502
|
+
message_libs.arr.span(), price_feed, role_admin, array![].span(),
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
for msg_lib in message_libs.arr {
|
|
506
|
+
// Ensure that msg_lib and role_admin are different
|
|
507
|
+
if msg_lib == role_admin {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Attempt to grant admin role
|
|
512
|
+
// Caller has msg lib role
|
|
513
|
+
start_cheat_caller_address(worker, msg_lib);
|
|
514
|
+
let res = safe_access_control.grant_role(ADMIN_ROLE, grantee);
|
|
515
|
+
|
|
516
|
+
// Should panic with missing role error because msg_lib is not a role admin
|
|
517
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
518
|
+
assert(!access_control.has_role(ADMIN_ROLE, grantee), 'Admin role should not be set');
|
|
519
|
+
|
|
520
|
+
// Attempt to grant message lib role
|
|
521
|
+
let res = safe_access_control.grant_role(MESSAGE_LIB_ROLE, grantee);
|
|
522
|
+
stop_cheat_caller_address(worker);
|
|
523
|
+
|
|
524
|
+
// Should panic with missing role error because msg_lib is not a role admin
|
|
525
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
526
|
+
assert(
|
|
527
|
+
!access_control.has_role(MESSAGE_LIB_ROLE, grantee), 'Msg lib role should not be set',
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/// A role admin can grant a new role admin which can then grant admin roles
|
|
533
|
+
#[test]
|
|
534
|
+
#[fuzzer(runs: 10)]
|
|
535
|
+
fn access_control_grant_role_chain_succeeds(
|
|
536
|
+
role_admin: ContractAddress,
|
|
537
|
+
new_role_admin: ContractAddress,
|
|
538
|
+
admin: ContractAddress,
|
|
539
|
+
msg_lib: ContractAddress,
|
|
540
|
+
price_feed: ContractAddress,
|
|
541
|
+
) {
|
|
542
|
+
let WorkerBaseMock { worker, access_control, .. } = deploy_worker_base(price_feed, role_admin);
|
|
543
|
+
|
|
544
|
+
// Role admin grants admin role
|
|
545
|
+
// Caller is the role admin
|
|
546
|
+
start_cheat_caller_address(worker, role_admin);
|
|
547
|
+
access_control.grant_role(DEFAULT_ADMIN_ROLE, new_role_admin);
|
|
548
|
+
stop_cheat_caller_address(worker);
|
|
549
|
+
|
|
550
|
+
// Check that new_role_admin is the new role admin
|
|
551
|
+
assert(
|
|
552
|
+
access_control.has_role(DEFAULT_ADMIN_ROLE, new_role_admin), 'New role admin should be set',
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
// New role admin grants admin role
|
|
556
|
+
// Caller is a role admin
|
|
557
|
+
start_cheat_caller_address(worker, new_role_admin);
|
|
558
|
+
access_control.grant_role(ADMIN_ROLE, admin);
|
|
559
|
+
stop_cheat_caller_address(worker);
|
|
560
|
+
|
|
561
|
+
// Check that admin has the admin role
|
|
562
|
+
assert(access_control.has_role(ADMIN_ROLE, admin), 'Admin role should be set');
|
|
563
|
+
|
|
564
|
+
// New role admin grants message lib role
|
|
565
|
+
// Caller is a role admin
|
|
566
|
+
start_cheat_caller_address(worker, new_role_admin);
|
|
567
|
+
access_control.grant_role(MESSAGE_LIB_ROLE, msg_lib);
|
|
568
|
+
stop_cheat_caller_address(worker);
|
|
569
|
+
|
|
570
|
+
// Check that msg_lib has the message lib role
|
|
571
|
+
assert(access_control.has_role(MESSAGE_LIB_ROLE, msg_lib), 'Msg lib role should be set');
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
#[test]
|
|
575
|
+
#[fuzzer(runs: 10)]
|
|
576
|
+
fn access_control_role_admin_is_default(role_admin: RoleAdmin, price_feed: ContractAddress) {
|
|
577
|
+
let WorkerBaseMock { access_control, .. } = deploy_worker_base(price_feed, role_admin.address);
|
|
578
|
+
assert!(
|
|
579
|
+
access_control.get_role_admin(DEFAULT_ADMIN_ROLE) == DEFAULT_ADMIN_ROLE,
|
|
580
|
+
"Role admin is self admin",
|
|
581
|
+
);
|
|
582
|
+
assert!(
|
|
583
|
+
access_control.get_role_admin(ADMIN_ROLE) == DEFAULT_ADMIN_ROLE,
|
|
584
|
+
"Role admin is admin admin",
|
|
585
|
+
);
|
|
586
|
+
assert!(
|
|
587
|
+
access_control.get_role_admin(MESSAGE_LIB_ROLE) == DEFAULT_ADMIN_ROLE,
|
|
588
|
+
"Role admin is msg lib admin",
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
#[test]
|
|
593
|
+
#[fuzzer(runs: 10)]
|
|
594
|
+
fn access_control_revoking_roles_succeeds(
|
|
595
|
+
role_admin: RoleAdmin, admin: ContractAddress, msg_lib: ContractAddress,
|
|
596
|
+
) {
|
|
597
|
+
let role_admin = role_admin.address;
|
|
598
|
+
let WorkerBaseMock {
|
|
599
|
+
worker, access_control, ..,
|
|
600
|
+
} =
|
|
601
|
+
deploy_worker_base_with_additional_roles(
|
|
602
|
+
array![msg_lib].span(), ZERO_ADDRESS, role_admin, array![admin].span(),
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
// Role admin revokes admin role
|
|
606
|
+
start_cheat_caller_address(worker, role_admin);
|
|
607
|
+
access_control.revoke_role(ADMIN_ROLE, admin);
|
|
608
|
+
stop_cheat_caller_address(worker);
|
|
609
|
+
|
|
610
|
+
// Check that admin does not have the admin role
|
|
611
|
+
assert(!access_control.has_role(ADMIN_ROLE, admin), 'Admin role should not be set');
|
|
612
|
+
|
|
613
|
+
// Role admin revokes message lib role
|
|
614
|
+
start_cheat_caller_address(worker, role_admin);
|
|
615
|
+
access_control.revoke_role(MESSAGE_LIB_ROLE, msg_lib);
|
|
616
|
+
stop_cheat_caller_address(worker);
|
|
617
|
+
|
|
618
|
+
// Check that msg_lib does not have the message lib role
|
|
619
|
+
assert(!access_control.has_role(MESSAGE_LIB_ROLE, msg_lib), 'Msg lib role should not be set');
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
////////////////////////////////
|
|
623
|
+
// Set default multiplier bps //
|
|
624
|
+
////////////////////////////////
|
|
625
|
+
|
|
626
|
+
/// An admin can set the default multiplier basis points - corresponding event is emitted
|
|
627
|
+
#[test]
|
|
628
|
+
#[fuzzer(runs: 10)]
|
|
629
|
+
fn set_default_multiplier_bps_succeeds_when_admin(
|
|
630
|
+
role_admin: RoleAdmin,
|
|
631
|
+
admin: ContractAddress,
|
|
632
|
+
price_feed: ContractAddress,
|
|
633
|
+
default_multiplier_bps: u16,
|
|
634
|
+
) {
|
|
635
|
+
let role_admin = role_admin.address;
|
|
636
|
+
let WorkerBaseMock {
|
|
637
|
+
worker, dispatcher, ..,
|
|
638
|
+
} =
|
|
639
|
+
deploy_worker_base_with_additional_roles(
|
|
640
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
641
|
+
);
|
|
642
|
+
|
|
643
|
+
let mut spy = spy_events();
|
|
644
|
+
|
|
645
|
+
// Caller has admin role
|
|
646
|
+
start_cheat_caller_address(worker, admin);
|
|
647
|
+
dispatcher.set_default_multiplier_bps(default_multiplier_bps);
|
|
648
|
+
stop_cheat_caller_address(worker);
|
|
649
|
+
|
|
650
|
+
// Check that default multiplier bps is set
|
|
651
|
+
assert!(
|
|
652
|
+
dispatcher.get_default_multiplier_bps() == default_multiplier_bps,
|
|
653
|
+
"Default multiplier bps should be set",
|
|
654
|
+
);
|
|
655
|
+
|
|
656
|
+
// Verify DefaultMultiplierBpsSet event was emitted
|
|
657
|
+
let expected_event = WorkerBaseComponent::Event::DefaultMultiplierBpsSet(
|
|
658
|
+
DefaultMultiplierBpsSet { default_multiplier_bps },
|
|
659
|
+
);
|
|
660
|
+
spy.assert_emitted(@array![(worker, expected_event)]);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/// A non-admin cannot set the default multiplier basis points - no event is emitted
|
|
664
|
+
#[test]
|
|
665
|
+
#[fuzzer(runs: 10)]
|
|
666
|
+
#[feature("safe_dispatcher")]
|
|
667
|
+
fn set_default_multiplier_bps_fails_when_not_admin(
|
|
668
|
+
role_admin: RoleAdmin,
|
|
669
|
+
price_feed: ContractAddress,
|
|
670
|
+
not_admin: ContractAddress,
|
|
671
|
+
default_multiplier_bps: u16,
|
|
672
|
+
) {
|
|
673
|
+
let role_admin = role_admin.address;
|
|
674
|
+
let WorkerBaseMock { worker, safe_dispatcher, .. } = deploy_worker_base(price_feed, role_admin);
|
|
675
|
+
|
|
676
|
+
let mut spy = spy_events();
|
|
677
|
+
|
|
678
|
+
// Caller does not have admin role
|
|
679
|
+
start_cheat_caller_address(worker, not_admin);
|
|
680
|
+
let res = safe_dispatcher.set_default_multiplier_bps(default_multiplier_bps);
|
|
681
|
+
stop_cheat_caller_address(worker);
|
|
682
|
+
|
|
683
|
+
// Should panic with missing role error because not_admin does not have admin role
|
|
684
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
685
|
+
|
|
686
|
+
// Verify DefaultMultiplierBpsSet event was not emitted
|
|
687
|
+
let event = WorkerBaseComponent::Event::DefaultMultiplierBpsSet(
|
|
688
|
+
DefaultMultiplierBpsSet { default_multiplier_bps },
|
|
689
|
+
);
|
|
690
|
+
spy.assert_not_emitted(@array![(worker, event)]);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
////////////////////////
|
|
694
|
+
// Withdraw fee tests //
|
|
695
|
+
////////////////////////
|
|
696
|
+
|
|
697
|
+
/// Admin can withdraw fee
|
|
698
|
+
#[test]
|
|
699
|
+
#[fuzzer(runs: 10)]
|
|
700
|
+
fn withdraw_fee_succeeds_when_correct(
|
|
701
|
+
role_admin: RoleAdmin,
|
|
702
|
+
admin: ContractAddress,
|
|
703
|
+
price_feed: ContractAddress,
|
|
704
|
+
token_holder: ContractAddress,
|
|
705
|
+
recipient: ContractAddress,
|
|
706
|
+
amount: u256,
|
|
707
|
+
) {
|
|
708
|
+
let role_admin = role_admin.address;
|
|
709
|
+
let WorkerBaseMock {
|
|
710
|
+
worker, dispatcher, ..,
|
|
711
|
+
} =
|
|
712
|
+
deploy_worker_base_with_additional_roles(
|
|
713
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
// Give token_holder ERC20 tokens
|
|
717
|
+
const MIN_AMOUNT: u256 = 1_000;
|
|
718
|
+
const MAX_AMOUNT: u256 = 9_000;
|
|
719
|
+
let amount = MIN_AMOUNT + amount % MAX_AMOUNT;
|
|
720
|
+
let ERC20Mock { token, token_dispatcher } = deploy_mock_erc20(amount, token_holder);
|
|
721
|
+
|
|
722
|
+
// Holder transfers tokens to worker
|
|
723
|
+
// Caller has tokens
|
|
724
|
+
start_cheat_caller_address(token, token_holder);
|
|
725
|
+
token_dispatcher.transfer(worker, amount);
|
|
726
|
+
stop_cheat_caller_address(token);
|
|
727
|
+
|
|
728
|
+
// Check that worker received tokens
|
|
729
|
+
assert(token_dispatcher.balance_of(worker) == amount, 'Worker balance should be amount');
|
|
730
|
+
|
|
731
|
+
let mut spy = spy_events();
|
|
732
|
+
|
|
733
|
+
// Admin withdraws fee
|
|
734
|
+
// Caller has admin role
|
|
735
|
+
let withdraw_amount = amount / 2;
|
|
736
|
+
start_cheat_caller_address(worker, admin);
|
|
737
|
+
dispatcher.withdraw_fee(token, recipient, withdraw_amount);
|
|
738
|
+
stop_cheat_caller_address(worker);
|
|
739
|
+
|
|
740
|
+
// Verify balances
|
|
741
|
+
assert!(
|
|
742
|
+
token_dispatcher.balance_of(recipient) == withdraw_amount,
|
|
743
|
+
"Recipient balance should be withdraw amount",
|
|
744
|
+
);
|
|
745
|
+
assert!(
|
|
746
|
+
token_dispatcher.balance_of(worker) == amount - withdraw_amount,
|
|
747
|
+
"Worker balance should be remaining",
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
// Verify WithdrawFee event was emitted
|
|
751
|
+
let expected_event = WorkerBaseComponent::Event::FeeWithdrawn(
|
|
752
|
+
FeeWithdrawn { to: recipient, amount: withdraw_amount },
|
|
753
|
+
);
|
|
754
|
+
spy.assert_emitted(@array![(worker, expected_event)]);
|
|
755
|
+
|
|
756
|
+
// Verify ERC20 transfer event was emitted
|
|
757
|
+
let erc20_event = ERC20Event::Transfer(
|
|
758
|
+
Transfer { from: worker, to: recipient, value: withdraw_amount },
|
|
759
|
+
);
|
|
760
|
+
spy.assert_emitted(@array![(token, erc20_event)]);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/// Fees cannot be withdrawn if
|
|
764
|
+
/// - caller is not admin
|
|
765
|
+
/// - caller is admin but trying to withdraw more than worker balance
|
|
766
|
+
#[test]
|
|
767
|
+
#[fuzzer(runs: 10)]
|
|
768
|
+
#[feature("safe_dispatcher")]
|
|
769
|
+
fn withdraw_fee_fails_when_incorrect(
|
|
770
|
+
role_admin: RoleAdmin,
|
|
771
|
+
admin: ContractAddress,
|
|
772
|
+
not_admin: ContractAddress,
|
|
773
|
+
price_feed: ContractAddress,
|
|
774
|
+
token_holder: ContractAddress,
|
|
775
|
+
recipient: ContractAddress,
|
|
776
|
+
amount: u256,
|
|
777
|
+
) {
|
|
778
|
+
// Ensure that admin and not_admin are different
|
|
779
|
+
if admin == not_admin {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
let role_admin = role_admin.address;
|
|
784
|
+
let WorkerBaseMock {
|
|
785
|
+
worker, safe_dispatcher, ..,
|
|
786
|
+
} =
|
|
787
|
+
deploy_worker_base_with_additional_roles(
|
|
788
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
789
|
+
);
|
|
790
|
+
|
|
791
|
+
// Give token_holder ERC20 tokens
|
|
792
|
+
const MIN_AMOUNT: u256 = 1_000;
|
|
793
|
+
const MAX_AMOUNT: u256 = 9_000;
|
|
794
|
+
let amount = MIN_AMOUNT + amount % MAX_AMOUNT;
|
|
795
|
+
let ERC20Mock { token, token_dispatcher } = deploy_mock_erc20(amount, token_holder);
|
|
796
|
+
|
|
797
|
+
// Holder transfers tokens to worker
|
|
798
|
+
// Caller has tokens
|
|
799
|
+
start_cheat_caller_address(token, token_holder);
|
|
800
|
+
token_dispatcher.transfer(worker, amount);
|
|
801
|
+
stop_cheat_caller_address(token);
|
|
802
|
+
|
|
803
|
+
// Check that worker received tokens
|
|
804
|
+
assert(token_dispatcher.balance_of(worker) == amount, 'Worker balance should be amount');
|
|
805
|
+
|
|
806
|
+
///////////////////////////////////
|
|
807
|
+
// Non-admin cannot withdraw fee //
|
|
808
|
+
///////////////////////////////////
|
|
809
|
+
|
|
810
|
+
// Non-admin attempts to withdraw fee
|
|
811
|
+
// Caller does not have admin role
|
|
812
|
+
let withdraw_amount = amount / 2;
|
|
813
|
+
start_cheat_caller_address(worker, not_admin);
|
|
814
|
+
let res = safe_dispatcher.withdraw_fee(token, recipient, withdraw_amount);
|
|
815
|
+
stop_cheat_caller_address(worker);
|
|
816
|
+
|
|
817
|
+
// Should panic with missing role error because not_admin does not have the admin role
|
|
818
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
819
|
+
|
|
820
|
+
// Verify balances are unchanged
|
|
821
|
+
assert(token_dispatcher.balance_of(recipient) == 0, 'Recipient balance should be 0');
|
|
822
|
+
assert(token_dispatcher.balance_of(worker) == amount, 'Worker balance should be amount');
|
|
823
|
+
|
|
824
|
+
//////////////////////////////////////////////
|
|
825
|
+
// Cannot withdraw more than worker balance //
|
|
826
|
+
//////////////////////////////////////////////
|
|
827
|
+
|
|
828
|
+
// Admin attempts to withdraw more than worker balance
|
|
829
|
+
let withdraw_amount = amount + 1;
|
|
830
|
+
start_cheat_caller_address(worker, admin);
|
|
831
|
+
let res = safe_dispatcher.withdraw_fee(token, recipient, withdraw_amount);
|
|
832
|
+
stop_cheat_caller_address(worker);
|
|
833
|
+
|
|
834
|
+
// Should panic with insufficient balance error because admin is trying to withdraw more than
|
|
835
|
+
// worker balance
|
|
836
|
+
assert_panic_with_felt_error(res, ERC20Errors::INSUFFICIENT_BALANCE);
|
|
837
|
+
|
|
838
|
+
// Verify balances are unchanged
|
|
839
|
+
assert(token_dispatcher.balance_of(recipient) == 0, 'Recipient balance should be 0');
|
|
840
|
+
assert(token_dispatcher.balance_of(worker) == amount, 'Worker balance should be amount');
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
////////////////////////////
|
|
844
|
+
// Worker fee_lib tests //
|
|
845
|
+
////////////////////////////
|
|
846
|
+
|
|
847
|
+
/// An admin can set the worker fee_lib address - corresponding event is emitted
|
|
848
|
+
#[test]
|
|
849
|
+
#[fuzzer(runs: 10)]
|
|
850
|
+
fn set_worker_fee_lib_succeeds_when_admin(
|
|
851
|
+
role_admin: RoleAdmin,
|
|
852
|
+
admin: ContractAddress,
|
|
853
|
+
price_feed: ContractAddress,
|
|
854
|
+
initial_worker_fee_lib: ContractAddress,
|
|
855
|
+
new_worker_fee_lib: ContractAddress,
|
|
856
|
+
) {
|
|
857
|
+
let role_admin = role_admin.address;
|
|
858
|
+
let WorkerBaseMock {
|
|
859
|
+
worker, dispatcher, ..,
|
|
860
|
+
} =
|
|
861
|
+
deploy_worker_base_with_additional_roles(
|
|
862
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
863
|
+
);
|
|
864
|
+
|
|
865
|
+
// Set initial worker fee_lib
|
|
866
|
+
start_cheat_caller_address(worker, admin);
|
|
867
|
+
dispatcher.set_worker_fee_lib(initial_worker_fee_lib);
|
|
868
|
+
stop_cheat_caller_address(worker);
|
|
869
|
+
|
|
870
|
+
let mut spy = spy_events();
|
|
871
|
+
|
|
872
|
+
// Set new worker fee_lib
|
|
873
|
+
start_cheat_caller_address(worker, admin);
|
|
874
|
+
dispatcher.set_worker_fee_lib(new_worker_fee_lib);
|
|
875
|
+
stop_cheat_caller_address(worker);
|
|
876
|
+
|
|
877
|
+
// Check that worker fee_lib is set
|
|
878
|
+
assert!(dispatcher.get_worker_fee_lib() == new_worker_fee_lib, "Worker fee_lib should be set");
|
|
879
|
+
|
|
880
|
+
// Verify WorkerFeeLibSet event was emitted
|
|
881
|
+
let expected_event = WorkerBaseComponent::Event::WorkerFeeLibSet(
|
|
882
|
+
WorkerFeeLibSet {
|
|
883
|
+
old_worker_fee_lib: initial_worker_fee_lib, new_worker_fee_lib: new_worker_fee_lib,
|
|
884
|
+
},
|
|
885
|
+
);
|
|
886
|
+
spy.assert_emitted(@array![(worker, expected_event)]);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
/// A non-admin cannot set the worker fee_lib address - no event is emitted
|
|
890
|
+
#[test]
|
|
891
|
+
#[fuzzer(runs: 10)]
|
|
892
|
+
#[feature("safe_dispatcher")]
|
|
893
|
+
fn set_worker_fee_lib_fails_when_not_admin(
|
|
894
|
+
role_admin: RoleAdmin,
|
|
895
|
+
price_feed: ContractAddress,
|
|
896
|
+
not_admin: ContractAddress,
|
|
897
|
+
worker_fee_lib: ContractAddress,
|
|
898
|
+
) {
|
|
899
|
+
let role_admin = role_admin.address;
|
|
900
|
+
let WorkerBaseMock { worker, safe_dispatcher, .. } = deploy_worker_base(price_feed, role_admin);
|
|
901
|
+
|
|
902
|
+
let mut spy = spy_events();
|
|
903
|
+
|
|
904
|
+
// Caller does not have admin role
|
|
905
|
+
start_cheat_caller_address(worker, not_admin);
|
|
906
|
+
let res = safe_dispatcher.set_worker_fee_lib(worker_fee_lib);
|
|
907
|
+
stop_cheat_caller_address(worker);
|
|
908
|
+
|
|
909
|
+
// Should panic with missing role error because not_admin does not have admin role
|
|
910
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
911
|
+
|
|
912
|
+
// Check that worker fee_lib is not set (should be zero address by default)
|
|
913
|
+
assert!(
|
|
914
|
+
safe_dispatcher.get_worker_fee_lib().unwrap() == ZERO_ADDRESS,
|
|
915
|
+
"Worker fee_lib should not be set",
|
|
916
|
+
);
|
|
917
|
+
|
|
918
|
+
// Verify WorkerFeeLibSet event was not emitted
|
|
919
|
+
let event = WorkerBaseComponent::Event::WorkerFeeLibSet(
|
|
920
|
+
WorkerFeeLibSet { old_worker_fee_lib: ZERO_ADDRESS, new_worker_fee_lib: worker_fee_lib },
|
|
921
|
+
);
|
|
922
|
+
spy.assert_not_emitted(@array![(worker, event)]);
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/// A message lib cannot set the worker fee_lib address
|
|
926
|
+
#[test]
|
|
927
|
+
#[fuzzer(runs: 10)]
|
|
928
|
+
#[feature("safe_dispatcher")]
|
|
929
|
+
fn set_worker_fee_lib_fails_when_msg_lib(
|
|
930
|
+
role_admin: RoleAdmin,
|
|
931
|
+
msg_lib: ContractAddress,
|
|
932
|
+
price_feed: ContractAddress,
|
|
933
|
+
worker_fee_lib: ContractAddress,
|
|
934
|
+
) {
|
|
935
|
+
let role_admin = role_admin.address;
|
|
936
|
+
let WorkerBaseMock {
|
|
937
|
+
worker, safe_dispatcher, ..,
|
|
938
|
+
} =
|
|
939
|
+
deploy_worker_base_with_additional_roles(
|
|
940
|
+
array![msg_lib].span(), price_feed, role_admin, array![].span(),
|
|
941
|
+
);
|
|
942
|
+
|
|
943
|
+
// Attempt to set worker fee_lib
|
|
944
|
+
// Caller has msg lib role
|
|
945
|
+
start_cheat_caller_address(worker, msg_lib);
|
|
946
|
+
let res = safe_dispatcher.set_worker_fee_lib(worker_fee_lib);
|
|
947
|
+
stop_cheat_caller_address(worker);
|
|
948
|
+
|
|
949
|
+
// Should panic with missing role error because msg_lib does not have admin role
|
|
950
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/// Admin can set multiple worker fee_lib addresses successfully
|
|
954
|
+
#[test]
|
|
955
|
+
#[fuzzer(runs: 10)]
|
|
956
|
+
fn set_multiple_worker_fee_lib_succeeds(
|
|
957
|
+
role_admin: RoleAdmin,
|
|
958
|
+
admin: ContractAddress,
|
|
959
|
+
price_feed: ContractAddress,
|
|
960
|
+
first_worker_fee_lib: ContractAddress,
|
|
961
|
+
second_worker_fee_lib: ContractAddress,
|
|
962
|
+
) {
|
|
963
|
+
let role_admin = role_admin.address;
|
|
964
|
+
let WorkerBaseMock {
|
|
965
|
+
worker, dispatcher, ..,
|
|
966
|
+
} =
|
|
967
|
+
deploy_worker_base_with_additional_roles(
|
|
968
|
+
array![].span(), price_feed, role_admin, array![admin].span(),
|
|
969
|
+
);
|
|
970
|
+
|
|
971
|
+
// Caller has admin role
|
|
972
|
+
start_cheat_caller_address(worker, admin);
|
|
973
|
+
|
|
974
|
+
// First worker fee_lib update
|
|
975
|
+
dispatcher.set_worker_fee_lib(first_worker_fee_lib);
|
|
976
|
+
let fee_lib = dispatcher.get_worker_fee_lib();
|
|
977
|
+
assert(fee_lib == first_worker_fee_lib, 'First update should succeed');
|
|
978
|
+
|
|
979
|
+
// Second worker fee_lib update
|
|
980
|
+
dispatcher.set_worker_fee_lib(second_worker_fee_lib);
|
|
981
|
+
let fee_lib = dispatcher.get_worker_fee_lib();
|
|
982
|
+
assert(fee_lib == second_worker_fee_lib, 'Second update should succeed');
|
|
983
|
+
|
|
984
|
+
stop_cheat_caller_address(worker);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/// Get worker fee_lib returns zero address by default
|
|
988
|
+
#[test]
|
|
989
|
+
#[fuzzer(runs: 10)]
|
|
990
|
+
fn get_worker_fee_lib_returns_zero_by_default(role_admin: RoleAdmin, price_feed: ContractAddress) {
|
|
991
|
+
let role_admin = role_admin.address;
|
|
992
|
+
let WorkerBaseMock { dispatcher, .. } = deploy_worker_base(price_feed, role_admin);
|
|
993
|
+
|
|
994
|
+
// Should return zero address by default
|
|
995
|
+
assert!(
|
|
996
|
+
dispatcher.get_worker_fee_lib() == ZERO_ADDRESS,
|
|
997
|
+
"Worker fee_lib should be zero address by default",
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
////////////////////////////
|
|
1002
|
+
// Renouncing roles tests //
|
|
1003
|
+
////////////////////////////
|
|
1004
|
+
|
|
1005
|
+
/// Renouncing roles is disabled
|
|
1006
|
+
#[test]
|
|
1007
|
+
#[fuzzer(runs: 10)]
|
|
1008
|
+
#[feature("safe_dispatcher")]
|
|
1009
|
+
fn renounce_roles_disabled(
|
|
1010
|
+
role_admin: RoleAdmin, admin: ContractAddress, price_feed: ContractAddress,
|
|
1011
|
+
) {
|
|
1012
|
+
let role_admin = role_admin.address;
|
|
1013
|
+
let WorkerBaseMock {
|
|
1014
|
+
worker, access_control, safe_access_control, ..,
|
|
1015
|
+
} = deploy_worker_base(price_feed, role_admin);
|
|
1016
|
+
|
|
1017
|
+
// Caller is the role admin
|
|
1018
|
+
start_cheat_caller_address(worker, role_admin);
|
|
1019
|
+
let res = safe_access_control.renounce_role(DEFAULT_ADMIN_ROLE, role_admin);
|
|
1020
|
+
stop_cheat_caller_address(worker);
|
|
1021
|
+
|
|
1022
|
+
// Should panic with renouncing role error because role admin cannot renounce role
|
|
1023
|
+
assert_panic_with_error(res, errors::err_role_renouncing_disabled());
|
|
1024
|
+
|
|
1025
|
+
// Check that admin does not have the admin role
|
|
1026
|
+
assert(access_control.has_role(DEFAULT_ADMIN_ROLE, role_admin), 'Role should not be renounced');
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
////////////////////
|
|
1030
|
+
// Pausable tests //
|
|
1031
|
+
////////////////////
|
|
1032
|
+
|
|
1033
|
+
/// Default admin can pause the contract
|
|
1034
|
+
#[test]
|
|
1035
|
+
#[fuzzer(runs: 10)]
|
|
1036
|
+
fn pause_succeeds_when_default_admin(role_admin: RoleAdmin, price_feed: ContractAddress) {
|
|
1037
|
+
let role_admin = role_admin.address;
|
|
1038
|
+
let WorkerBaseMock {
|
|
1039
|
+
worker, dispatcher, access_control, ..,
|
|
1040
|
+
} = deploy_worker_base(price_feed, role_admin);
|
|
1041
|
+
|
|
1042
|
+
let mut spy = spy_events();
|
|
1043
|
+
|
|
1044
|
+
// Caller has default admin role
|
|
1045
|
+
assert!(
|
|
1046
|
+
access_control.has_role(DEFAULT_ADMIN_ROLE, role_admin),
|
|
1047
|
+
"Role admin should have default admin role",
|
|
1048
|
+
);
|
|
1049
|
+
start_cheat_caller_address(worker, role_admin);
|
|
1050
|
+
dispatcher.pause();
|
|
1051
|
+
stop_cheat_caller_address(worker);
|
|
1052
|
+
|
|
1053
|
+
// Check that contract is paused
|
|
1054
|
+
let pausable_dispatcher = IPausableDispatcher { contract_address: worker };
|
|
1055
|
+
assert(pausable_dispatcher.is_paused(), 'Contract should be paused');
|
|
1056
|
+
|
|
1057
|
+
// Verify Paused event was emitted
|
|
1058
|
+
let expected_event = PausableComponent::Event::Paused(
|
|
1059
|
+
PausableComponent::Paused { account: role_admin },
|
|
1060
|
+
);
|
|
1061
|
+
spy.assert_emitted(@array![(worker, expected_event)]);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/// Non-default admin cannot pause the contract
|
|
1065
|
+
#[test]
|
|
1066
|
+
#[fuzzer(runs: 10)]
|
|
1067
|
+
#[feature("safe_dispatcher")]
|
|
1068
|
+
fn pause_fails_when_not_default_admin(
|
|
1069
|
+
role_admin: RoleAdmin, price_feed: ContractAddress, not_default_admin: ContractAddress,
|
|
1070
|
+
) {
|
|
1071
|
+
// Ensure that role_admin and not_default_admin are different
|
|
1072
|
+
let role_admin = role_admin.address;
|
|
1073
|
+
if role_admin == not_default_admin {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
let WorkerBaseMock {
|
|
1078
|
+
worker, safe_dispatcher, access_control, ..,
|
|
1079
|
+
} = deploy_worker_base(price_feed, role_admin);
|
|
1080
|
+
|
|
1081
|
+
// Caller does not have default admin role
|
|
1082
|
+
assert!(
|
|
1083
|
+
!access_control.has_role(DEFAULT_ADMIN_ROLE, not_default_admin),
|
|
1084
|
+
"Caller should not have default admin role",
|
|
1085
|
+
);
|
|
1086
|
+
start_cheat_caller_address(worker, not_default_admin);
|
|
1087
|
+
let res = safe_dispatcher.pause();
|
|
1088
|
+
stop_cheat_caller_address(worker);
|
|
1089
|
+
|
|
1090
|
+
// Check that contract is not paused
|
|
1091
|
+
let pausable_dispatcher = IPausableDispatcher { contract_address: worker };
|
|
1092
|
+
assert(!pausable_dispatcher.is_paused(), 'Contract should not be paused');
|
|
1093
|
+
|
|
1094
|
+
// Should panic with missing role error because not_default_admin does not have default admin
|
|
1095
|
+
// role
|
|
1096
|
+
assert_panic_with_felt_error(res, AccessControlComponent::Errors::MISSING_ROLE);
|
|
1097
|
+
}
|