From ebd76de75f5a1d029eaa9138d95a9c8d754e9047 Mon Sep 17 00:00:00 2001 From: Maxim Kucherov Date: Mon, 4 Mar 2024 12:59:58 +0300 Subject: [PATCH] Etherlink: add governance smart contracts --- .../tezos_contracts/governance/.gitignore | 3 + etherlink/tezos_contracts/governance/LICENSE | 21 + etherlink/tezos_contracts/governance/Makefile | 10 + .../tezos_contracts/governance/README.md | 248 ++ .../governance/build/kernel_governance.tz | 1505 +++++++++ .../governance/build/sequencer_governance.tz | 1545 +++++++++ .../build/test/internal_test_proxy.tz | 343 ++ .../governance/build/test/rollup_mock.tz | 7 + .../contracts/common/constants.mligo | 3 + .../contracts/common/entrypoints.mligo | 102 + .../governance/contracts/common/errors.mligo | 24 + .../governance/contracts/common/events.mligo | 30 + .../governance/contracts/common/rollup.mligo | 100 + .../governance/contracts/common/storage.mligo | 106 + .../contracts/common/utils/byte_utils.mligo | 10 + .../contracts/common/utils/converters.mligo | 78 + .../contracts/common/utils/rlp.mligo | 31 + .../contracts/common/validation.mligo | 11 + .../governance/contracts/common/views.mligo | 34 + .../governance/contracts/common/voting.mligo | 352 +++ .../contracts/kernel_governance.mligo | 59 + .../contracts/sequencer_governance.mligo | 62 + .../contracts/test/internal_test_proxy.mligo | 56 + .../contracts/test/rollup_mock.mligo | 14 + .../tezos_contracts/governance/example.env | 2 + .../tezos_contracts/governance/poetry.lock | 2782 +++++++++++++++++ .../tezos_contracts/governance/pyproject.toml | 25 + .../governance/scripts/__init__.py | 0 .../governance/scripts/contract_type.py | 3 + .../governance/scripts/environment.py | 10 + .../governance/scripts/governance.py | 141 + .../governance/scripts/metadata.py | 29 + .../governance/tests/__init__.py | 0 .../tezos_contracts/governance/tests/base.py | 93 + .../governance/tests/common/__init__.py | 0 .../tests/common/internal/__init__.py | 0 .../internal/test_address_to_key_hash.py | 17 + .../common/internal/test_normalize_params.py | 13 + .../internal/test_payload_decoration.py | 39 + .../tests/common/test_gas_consumption.py | 195 ++ .../tests/common/test_promotion_period.py | 345 ++ .../tests/common/test_proposal_period.py | 372 +++ .../governance/tests/gas_consumption.json | 98 + .../governance/tests/helpers/__init__.py | 0 .../tests/helpers/contracts/__init__.py | 17 + .../tests/helpers/contracts/contract.py | 67 + .../helpers/contracts/governance_base.py | 38 + .../helpers/contracts/internal_test_proxy.py | 26 + .../helpers/contracts/kernel_governance.py | 46 + .../tests/helpers/contracts/rollup_mock.py | 20 + .../helpers/contracts/sequencer_governance.py | 44 + .../governance/tests/helpers/errors.py | 16 + .../governance/tests/helpers/metadata.py | 37 + .../helpers/operation_result_recorder.py | 17 + .../governance/tests/helpers/utility.py | 141 + .../tests/kernel_governance/__init__.py | 0 .../kernel_governance/entrypoints/__init__.py | 0 .../entrypoints/test_new_proposal.py | 181 ++ .../test_trigger_kernel_upgrade.py | 120 + .../entrypoints/test_upvote_proposal.py | 215 ++ .../entrypoints/test_vote.py | 205 ++ .../tests/sequencer_governance/__init__.py | 0 .../entrypoints/__init__.py | 0 .../entrypoints/test_new_proposal.py | 217 ++ .../test_trigger_committee_upgrade.py | 121 + .../entrypoints/test_upvote_proposal.py | 248 ++ .../entrypoints/test_vote.py | 213 ++ 67 files changed, 10907 insertions(+) create mode 100644 etherlink/tezos_contracts/governance/.gitignore create mode 100644 etherlink/tezos_contracts/governance/LICENSE create mode 100644 etherlink/tezos_contracts/governance/Makefile create mode 100644 etherlink/tezos_contracts/governance/README.md create mode 100644 etherlink/tezos_contracts/governance/build/kernel_governance.tz create mode 100644 etherlink/tezos_contracts/governance/build/sequencer_governance.tz create mode 100644 etherlink/tezos_contracts/governance/build/test/internal_test_proxy.tz create mode 100644 etherlink/tezos_contracts/governance/build/test/rollup_mock.tz create mode 100644 etherlink/tezos_contracts/governance/contracts/common/constants.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/entrypoints.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/errors.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/events.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/rollup.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/storage.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/utils/byte_utils.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/utils/converters.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/utils/rlp.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/validation.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/views.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/common/voting.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/kernel_governance.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/sequencer_governance.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/test/internal_test_proxy.mligo create mode 100644 etherlink/tezos_contracts/governance/contracts/test/rollup_mock.mligo create mode 100644 etherlink/tezos_contracts/governance/example.env create mode 100644 etherlink/tezos_contracts/governance/poetry.lock create mode 100644 etherlink/tezos_contracts/governance/pyproject.toml create mode 100644 etherlink/tezos_contracts/governance/scripts/__init__.py create mode 100644 etherlink/tezos_contracts/governance/scripts/contract_type.py create mode 100644 etherlink/tezos_contracts/governance/scripts/environment.py create mode 100644 etherlink/tezos_contracts/governance/scripts/governance.py create mode 100644 etherlink/tezos_contracts/governance/scripts/metadata.py create mode 100644 etherlink/tezos_contracts/governance/tests/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/base.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/internal/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/internal/test_address_to_key_hash.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/internal/test_normalize_params.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/internal/test_payload_decoration.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/test_gas_consumption.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/test_promotion_period.py create mode 100644 etherlink/tezos_contracts/governance/tests/common/test_proposal_period.py create mode 100644 etherlink/tezos_contracts/governance/tests/gas_consumption.json create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/contract.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/governance_base.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/internal_test_proxy.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/kernel_governance.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/rollup_mock.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/contracts/sequencer_governance.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/errors.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/metadata.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/operation_result_recorder.py create mode 100644 etherlink/tezos_contracts/governance/tests/helpers/utility.py create mode 100644 etherlink/tezos_contracts/governance/tests/kernel_governance/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_new_proposal.py create mode 100644 etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_trigger_kernel_upgrade.py create mode 100644 etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_upvote_proposal.py create mode 100644 etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_vote.py create mode 100644 etherlink/tezos_contracts/governance/tests/sequencer_governance/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/__init__.py create mode 100644 etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_new_proposal.py create mode 100644 etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_trigger_committee_upgrade.py create mode 100644 etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_upvote_proposal.py create mode 100644 etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_vote.py diff --git a/etherlink/tezos_contracts/governance/.gitignore b/etherlink/tezos_contracts/governance/.gitignore new file mode 100644 index 000000000000..1bd1cc8e8fc9 --- /dev/null +++ b/etherlink/tezos_contracts/governance/.gitignore @@ -0,0 +1,3 @@ +.ligo/ +**/__pycache__/** +.env \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/LICENSE b/etherlink/tezos_contracts/governance/LICENSE new file mode 100644 index 000000000000..5a6e19022621 --- /dev/null +++ b/etherlink/tezos_contracts/governance/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Baking Bad + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/etherlink/tezos_contracts/governance/Makefile b/etherlink/tezos_contracts/governance/Makefile new file mode 100644 index 000000000000..4d1540550b19 --- /dev/null +++ b/etherlink/tezos_contracts/governance/Makefile @@ -0,0 +1,10 @@ +LIGO_COMPILER = docker run --rm -v "${PWD}":"${PWD}" -w "${PWD}" ligolang/ligo:1.4.0 + +compile: + rm -r -f ./build + mkdir ./build + ${LIGO_COMPILER} compile contract contracts/kernel_governance.mligo -o build/kernel_governance.tz + ${LIGO_COMPILER} compile contract contracts/sequencer_governance.mligo -o build/sequencer_governance.tz + mkdir ./build/test + ${LIGO_COMPILER} compile contract contracts/test/rollup_mock.mligo -o build/test/rollup_mock.tz + ${LIGO_COMPILER} compile contract contracts/test/internal_test_proxy.mligo -o build/test/internal_test_proxy.tz \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/README.md b/etherlink/tezos_contracts/governance/README.md new file mode 100644 index 000000000000..18a75941df1f --- /dev/null +++ b/etherlink/tezos_contracts/governance/README.md @@ -0,0 +1,248 @@ +# Etherlink governance smart contracts + +The repository contains contracts designed to upgrade the Etherlink kernel and sequencer by voting. +## Commands + +### Build +``` +make compile +``` + +### Test +The testing stack for the contracts is based on Python and requires [poetry](https://python-poetry.org/), [pytezos](https://pytezos.org/), and [pytest](https://docs.pytest.org/en/7.4.x/) to be installed. +``` +poetry run pytest +``` + +### Deploy Kernel Governance contract +``` +poetry run deploy_contract --rpc-url https://rpc.tzkt.io/ghostnet --contract kernel_regular_governance --upvoting_limit 20 --period_length 128 --adoption_period_sec 57600 --proposal_quorum_percent 10.5 --promotion_quorum_percent 15.5 --promotion_supermajority_percent 95.7 +``` + +### Deploy Kernel Security Governance contract +``` +poetry run deploy_contract --rpc-url https://rpc.tzkt.io/ghostnet --contract kernel_security_governance --upvoting_limit 20 --period_length 128 --adoption_period_sec 57600 --proposal_quorum_percent 10.5 --promotion_quorum_percent 15.5 --promotion_supermajority_percent 95.7 +``` + +### Deploy Sequencer Committee Governance contract +``` +poetry run deploy_contract --rpc-url https://rpc.tzkt.io/ghostnet --contract sequencer_governance --upvoting_limit 20 --period_length 128 --adoption_period_sec 57600 --proposal_quorum_percent 10.5 --promotion_quorum_percent 15.5 --promotion_supermajority_percent 95.7 +``` + +## Kernel governance contract + +The contract allows bakers to make proposals and vote for kernel upgrade as well as trigger kernel upgrade with the latest voting winner payload stored in the smart contract and updated through the voting process + +### Entrypoints + +#### new_proposal + +Creates and upvotes a new proposal. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "new_proposal" --arg "%KERNEL_ROOT_HASH%" +``` + +##### Example + +```bash +octez-client transfer 0 from tz1RfbwbXjE8UaRLLjZjUyxbj4KCxibTp9xN to KT1HfJb718fGszcgYguA4bfTjAqe1BEmFHkv --entrypoint "new_proposal" --arg "0x009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606abc" +``` + +#### upvote_proposal + +Upvotes an existing proposal. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "upvote_proposal" --arg "%KERNEL_ROOT_HASH%" +``` + +##### Example + +```bash +octez-client transfer 0 from tz1RfbwbXjE8UaRLLjZjUyxbj4KCxibTp9xN to KT1HfJb718fGszcgYguA4bfTjAqe1BEmFHkv --entrypoint "upvote_proposal" --arg "0x009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606abc" +``` + +#### vote + +Votes with **yea**, **nay** or **pass** on the proposal that has advanced to the promotion period. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "vote" --arg "\"%YOUR_VOTE%\"" +``` + +where `%YOUR_VOTE%` is one of the values: `yea`, `nay` or `pass` + +##### Example + +```bash +octez-client transfer 0 from tz1RfbwbXjE8UaRLLjZjUyxbj4KCxibTp9xN to KT1HfJb718fGszcgYguA4bfTjAqe1BEmFHkv --entrypoint "vote" --arg "\"yea\"" +``` + + +#### trigger_kernel_upgrade + +Calls a smart rollup's upgrade entrypoint and passes the latest voting winner payload (kernel root hash). It can be called any number of times. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "trigger_kernel_upgrade" --arg "\"%SMART_ROLLUP_ADDRESS%\"" +``` + +##### Example + +```bash +octez-client transfer 0 from tz1RfbwbXjE8UaRLLjZjUyxbj4KCxibTp9xN to KT1HfJb718fGszcgYguA4bfTjAqe1BEmFHkv --entrypoint "trigger_kernel_upgrade" --arg "\"sr1EStimadnRRA3vnjpWV1RwNAsDbM3JaDt6\"" +``` + + +## Sequencer committee governance contract + +The contract allows bakers to make proposals and vote for sequencer committee upgrade as well as trigger sequencer committee upgrade with the latest voting winner payload stored in the smart contract and updated through the voting process + +### Entrypoints + +#### new_proposal + +Creates and upvotes a new proposal. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "new_proposal" --arg "Pair \"%PUBLIC KEY%\" %L2_ADDRESS%" +``` + +##### Example + +```bash +octez-client transfer 0 from tz1RLPEeMxbJYQBFbXYw8WHdXjeUjnG5ZXNq to KT1FRzozuzFMWLimpFeSdADHTMxzU8KtgCr9 --entrypoint "new_proposal" --arg "Pair \"edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X\" 0xb7a97043983f24991398e5a82f63f4c58a417185" +``` + +#### upvote_proposal + +Upvotes an existing proposal. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "upvote_proposal" --arg "Pair \"%PUBLIC KEY%\" %L2_ADDRESS%" +``` + +##### Example + +```bash +octez-client transfer 0 from tz1RLPEeMxbJYQBFbXYw8WHdXjeUjnG5ZXNq to KT1FRzozuzFMWLimpFeSdADHTMxzU8KtgCr9 --entrypoint "upvote_proposal" --arg "Pair \"edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X\" 0xb7a97043983f24991398e5a82f63f4c58a417185" +``` + +#### vote + +Votes with **yea**, **nay** or **pass** on the proposal that has advanced to the promotion period. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "vote" --arg "\"%YOUR_VOTE%\"" +``` + +where `%YOUR_VOTE%` is one of the values: `yea`, `nay` or `pass` + +##### Example + +```bash +octez-client transfer 0 from tz1RLPEeMxbJYQBFbXYw8WHdXjeUjnG5ZXNq to KT1FRzozuzFMWLimpFeSdADHTMxzU8KtgCr9 --entrypoint "vote" --arg "\"yea\"" +``` + + +#### trigger_committee_upgrade + +Calls a smart rollup's upgrade entrypoint and passes the latest voting winner payload (committee addresses). It can be called any number of times. + +##### Client command + +```bash +octez-client transfer 0 from %YOUR_ADDRESS% to %CONTRACT_ADDRESS% --entrypoint "trigger_committee_upgrade" --arg "\"%SMART_ROLLUP_ADDRESS%\"" +``` + +##### Example + +```bash +octez-client transfer 0 from tz1RfbwbXjE8UaRLLjZjUyxbj4KCxibTp9xN to KT1Bda2EHR3pwjPgQc6mBHwtfCP8Cuf5ud5j --entrypoint "trigger_committee_upgrade" --arg "\"sr1EStimadnRRA3vnjpWV1RwNAsDbM3JaDt6\"" +``` + +## The get_voting_state on-chain view and voting_finished events + +**Note: Don't use just the storage to get the actual state** + + +Use the [get_voting_state](https://better-call.dev/ghostnet/KT1JA6kdnWJqXRpKKHU5e99yuE3Yd1X5KyrL/views) view to obtain the actual state of current voting process at the time of the call. This returns the actual recalculated `voting_context` value as well as pending `voting_finished` event payload in case if the latest voting period is finished but the event was not sent to blockchain yet. The event will be sent after the next successful call to any entrypoint. + +Use the [contract events](https://better-call.dev/ghostnet/KT1JA6kdnWJqXRpKKHU5e99yuE3Yd1X5KyrL/events) to see the history of voting epochs + + +## Config + +All contracts mentioned above use the same config for voting process. Here is a description of the config values +```ocaml +(* + NOTE: + started_at_level and period_length values should be chosen carefully + to be sure that the contract governance periods + never cross the boundaries of the tezos protocol governance periods. + This ensures the immutability of voting power throughout the entire voting period +*) +type config_t = { + (* + Used to align voting periods with protocol governance periods. + Should be the start level of the current protocol governance period + *) + started_at_level : nat; + + (* + The duration of the of proposal and promotion periods represented in blocks. + period_length = tezos_governance_period_length / N, where N is integer divisor (factor) + *) + period_length : nat; + + (* + The duration of the l2 adoption period counted in seconds. + Used to generate an upgrade payload with activation timestamp + on trigger_upgrade entrypoint call + *) + adoption_period_sec : nat; + + (* Number of proposals that an account may upvote and submit *) + upvoting_limit : nat; + + (* + The scale for proposal_quorum, promotion_quorum and promotion_supermajority params. + For example if config.scale = 100 and config.proposal_quorum = 80 + then proposal_quorum_% == 80 / 100 == .80 == 80% + *) + scale : nat; + + (* + Minimum ratio of all the cumulated stake of a proposal upvotes to the total stake + to advance the proposal to promotion period + *) + proposal_quorum : nat; + + (* + Minimum ratio of all the cumulated stake of cast ballots (yea, nay, and pass ballots) + to the total stake to consider the proposal as a voting winner + *) + promotion_quorum : nat; + + (* + Minimum ratio of cumulated stake of Yea ballots to the cumulated stake + of Yea and Nay ballots to consider the proposal as a voting winner + *) + promotion_supermajority : nat; +} +``` diff --git a/etherlink/tezos_contracts/governance/build/kernel_governance.tz b/etherlink/tezos_contracts/governance/build/kernel_governance.tz new file mode 100644 index 000000000000..08f6c2417ffa --- /dev/null +++ b/etherlink/tezos_contracts/governance/build/kernel_governance.tz @@ -0,0 +1,1505 @@ +{ parameter + (or (address %trigger_kernel_upgrade) + (or (string %vote) (or (bytes %upvote_proposal) (bytes %new_proposal)))) ; + storage + (pair (pair %config + (nat %started_at_level) + (nat %period_length) + (nat %adoption_period_sec) + (nat %upvoting_limit) + (nat %scale) + (nat %proposal_quorum) + (nat %promotion_quorum) + (nat %promotion_supermajority)) + (option %voting_context + (pair (nat %period_index) + (or %period + (pair %proposal + (big_map %upvoters_upvotes_count key_hash nat) + (big_map %upvoters_proposals (pair key_hash bytes) unit) + (big_map %proposals bytes (pair (key_hash %proposer) (nat %upvotes_voting_power))) + (option %max_upvotes_voting_power nat) + (option %winner_candidate bytes) + (nat %total_voting_power)) + (pair %promotion + (big_map %voters key_hash string) + (nat %yea_voting_power) + (nat %nay_voting_power) + (nat %pass_voting_power) + (nat %total_voting_power) + (bytes %winner_candidate))))) + (option %last_winner + (pair (bytes %payload) (big_map %trigger_history address unit))) + (big_map %metadata string bytes)) ; + code { PUSH string "NOT_PROPOSAL_PERIOD" ; + LAMBDA + address + key_hash + { DUP ; + PACK ; + PUSH bytes 0x00 ; + DUP 2 ; + PUSH nat 1 ; + PUSH nat 6 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + COMPARE ; + EQ ; + IF {} { PUSH string "NOT_IMPLICIT_ADDRESS" ; FAILWITH } ; + PUSH bytes 0x ; + NIL bytes ; + DUP 3 ; + PUSH nat 21 ; + PUSH nat 7 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + PUSH bytes 0x00000015 ; + CONS ; + DIG 2 ; + PUSH nat 2 ; + PUSH nat 0 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + UNPACK key_hash ; + PUSH string "FAILED_TO_CAST_ADDRESS_TO_KEY_HASH" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + PUSH string "KEY_HASH_NOT_EQUAL_TO_SOURCE_ADDRESS" ; + DIG 2 ; + DUP 3 ; + IMPLICIT_ACCOUNT ; + ADDRESS ; + COMPARE ; + EQ ; + IF { DROP } { FAILWITH } } ; + LAMBDA + (pair nat nat) + bytes + { UNPAIR ; + PUSH nat 56 ; + DUP 2 ; + COMPARE ; + LT ; + IF { ADD ; BYTES } + { BYTES ; + DUP ; + SIZE ; + PUSH nat 9 ; + DUP 2 ; + COMPARE ; + LT ; + IF {} { PUSH string "INPUT_TOO_LONG_FOR_RLP" ; FAILWITH } ; + PUSH nat 55 ; + DIG 3 ; + DIG 2 ; + ADD ; + ADD ; + BYTES ; + CONCAT } } ; + LAMBDA + unit + unit + { DROP ; + PUSH string "TEZ_IN_TRANSACTION_DISALLOWED" ; + PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + EQ ; + IF { DROP ; UNIT } { FAILWITH } } ; + LAMBDA + nat + unit + { PUSH nat 0 ; + SWAP ; + COMPARE ; + GT ; + IF { UNIT } { PUSH string "NO_VOTING_POWER" ; FAILWITH } } ; + LAMBDA + (pair nat nat nat nat nat nat nat nat) + nat + { DUP ; + CAR ; + LEVEL ; + SUB ; + ISNAT ; + IF_NONE + { DROP ; PUSH string "CURRENT_LEVEL_LESS_THAN_START_LEVEL" ; FAILWITH } + { SWAP ; + GET 3 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR } } ; + DIG 6 ; + UNPAIR ; + IF_LEFT + { DIG 3 ; + DIG 6 ; + DIG 7 ; + DROP 3 ; + UNIT ; + DIG 4 ; + SWAP ; + EXEC ; + DROP ; + DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option bytes)) ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option bytes)) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE bytes } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE bytes ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option bytes)) } ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option bytes)) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash bytes) unit) + (big_map bytes (pair key_hash nat)) + (option nat) + (option bytes) + nat) } + { SWAP ; + DROP ; + NONE bytes ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE bytes } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 4 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 4 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + SWAP ; + IF_NONE { PUSH string "LAST_WINNER_NOT_FOUND" ; FAILWITH } {} ; + DUP ; + CDR ; + DUP 5 ; + MEM ; + NOT ; + IF {} { PUSH string "UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED" ; FAILWITH } ; + DUP 4 ; + CONTRACT (or (or (pair %d bytes (ticket (pair nat (option bytes)))) (bytes %a)) (bytes %u)) ; + IF_NONE { PUSH string "ROLLUP_ENTRYPOINT_NOT_FOUND" ; FAILWITH } {} ; + DUP 6 ; + CAR ; + GET 5 ; + INT ; + NOW ; + ADD ; + PUSH timestamp 0 ; + SWAP ; + SUB ; + ISNAT ; + PUSH string "NEGATIVE_TIMESTAMP" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + BYTES ; + PUSH bytes 0x ; + PUSH int 1 ; + PUSH int 1 ; + DUP 4 ; + SIZE ; + SUB ; + PUSH int 0 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 + { ISNAT ; + PUSH string "INDEX_NOT_NAT" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + SWAP ; + DUP 3 ; + PUSH nat 1 ; + DIG 3 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + SWAP ; + DROP ; + DUP ; + SIZE ; + INT ; + PUSH int 1 ; + PUSH int 1 ; + PUSH nat 8 ; + SUB ; + DIG 2 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 { DROP ; PUSH bytes 0x00 ; SWAP ; CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + NIL bytes ; + SWAP ; + CONS ; + DUP 3 ; + CAR ; + CONS ; + MAP { DUP ; + SIZE ; + PUSH bytes 0x80 ; + DUP 3 ; + COMPARE ; + LT ; + PUSH nat 1 ; + DUP 3 ; + COMPARE ; + EQ ; + AND ; + IF { DROP ; PUSH bytes 0x } + { PUSH nat 128 ; SWAP ; PAIR ; DUP 9 ; SWAP ; EXEC } ; + CONCAT } ; + PUSH bytes 0x ; + SWAP ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + PUSH nat 192 ; + DUP 2 ; + SIZE ; + PAIR ; + DIG 8 ; + SWAP ; + EXEC ; + CONCAT ; + RIGHT (or (pair bytes (ticket (pair nat (option bytes)))) bytes) ; + SWAP ; + PUSH mutez 0 ; + DIG 2 ; + TRANSFER_TOKENS ; + DIG 3 ; + IF_NONE + { NIL operation } + { NIL operation ; + SWAP ; + EMIT %voting_finished + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload bytes)) ; + CONS } ; + DIG 5 ; + DIG 4 ; + SOME ; + UPDATE 3 ; + DUP 4 ; + DIG 4 ; + CDR ; + UNIT ; + SOME ; + DIG 6 ; + UPDATE ; + UPDATE 2 ; + SOME ; + UPDATE 5 ; + SWAP ; + DIG 2 ; + CONS } + { DIG 5 ; + DROP ; + IF_LEFT + { DIG 6 ; + DROP ; + DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option bytes)) ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option bytes)) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE bytes } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE bytes ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option bytes)) } ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option bytes)) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash bytes) unit) + (big_map bytes (pair key_hash nat)) + (option nat) + (option bytes) + nat) } + { SWAP ; + DROP ; + NONE bytes ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE bytes } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } ; + DIG 2 ; + PAIR } } ; + SWAP ; + DROP ; + SENDER ; + DIG 6 ; + SWAP ; + EXEC ; + DUP ; + VOTING_POWER ; + UNIT ; + DIG 7 ; + SWAP ; + EXEC ; + DROP ; + DUP ; + DIG 6 ; + SWAP ; + EXEC ; + DROP ; + DUP 3 ; + CDR ; + IF_LEFT { DROP ; PUSH string "NOT_PROMOTION_PERIOD" ; FAILWITH } {} ; + DUP ; + CAR ; + DUP 4 ; + MEM ; + NOT ; + IF {} { PUSH string "PROMOTION_ALREADY_VOTED" ; FAILWITH } ; + PUSH string "yea" ; + DUP 6 ; + COMPARE ; + EQ ; + IF { DUP ; DIG 2 ; DUP 3 ; GET 3 ; ADD ; UPDATE 3 } + { PUSH string "nay" ; + DUP 6 ; + COMPARE ; + EQ ; + IF { DUP ; DIG 2 ; DUP 3 ; GET 5 ; ADD ; UPDATE 5 } + { PUSH string "pass" ; + DUP 6 ; + COMPARE ; + EQ ; + IF { DUP ; DIG 2 ; DUP 3 ; GET 7 ; ADD ; UPDATE 7 } + { SWAP ; DROP ; PUSH string "INCORRECT_VOTE_VALUE" ; FAILWITH } } } ; + SWAP ; + CAR ; + DIG 4 ; + SOME ; + DIG 3 ; + UPDATE ; + UPDATE 1 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash bytes) unit) + (big_map bytes (pair key_hash nat)) + (option nat) + (option bytes) + nat) ; + UPDATE 2 ; + SOME ; + UPDATE 3 ; + NIL operation } + { IF_LEFT + { DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option bytes)) ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option bytes)) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE bytes } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE bytes ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option bytes)) } ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option bytes)) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash bytes) unit) + (big_map bytes (pair key_hash nat)) + (option nat) + (option bytes) + nat) } + { SWAP ; + DROP ; + NONE bytes ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE bytes } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 4 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 4 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + SENDER ; + DIG 8 ; + SWAP ; + EXEC ; + DUP ; + VOTING_POWER ; + UNIT ; + DIG 9 ; + SWAP ; + EXEC ; + DROP ; + DUP ; + DIG 8 ; + SWAP ; + EXEC ; + DROP ; + DUP 3 ; + CDR ; + IF_LEFT { DIG 8 ; DROP } { DROP ; DIG 7 ; FAILWITH } ; + DUP ; + CAR ; + DUP 9 ; + CAR ; + GET 7 ; + DUP 2 ; + DUP 6 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + COMPARE ; + LT ; + IF {} { PUSH string "UPVOTING_LIMIT_EXCEEDED" ; FAILWITH } ; + DUP 2 ; + GET 5 ; + DUP 9 ; + GET ; + IF_NONE { PUSH string "PROPOSAL_NOT_FOUND" ; FAILWITH } {} ; + DUP 3 ; + GET 3 ; + DUP ; + DUP 11 ; + DUP 8 ; + PAIR ; + MEM ; + NOT ; + IF {} { PUSH string "PROPOSAL_ALREADY_UPVOTED" ; FAILWITH } ; + DIG 4 ; + DUP 3 ; + CDR ; + ADD ; + DUP 5 ; + DUP 5 ; + DUP 8 ; + GET ; + IF_NONE + { DIG 4 ; PUSH nat 1 ; SOME ; DUP 8 ; UPDATE } + { DIG 5 ; PUSH nat 1 ; DIG 2 ; ADD ; SOME ; DUP 8 ; UPDATE } ; + UPDATE 1 ; + DIG 2 ; + UNIT ; + SOME ; + DUP 11 ; + DIG 7 ; + PAIR ; + UPDATE ; + UPDATE 3 ; + DIG 3 ; + GET 5 ; + DIG 3 ; + DUP 4 ; + UPDATE 2 ; + SOME ; + DUP 8 ; + UPDATE ; + UPDATE 5 ; + DUP ; + GET 7 ; + IF_NONE + { SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DUP ; + DUP 4 ; + COMPARE ; + GT ; + IF { DROP ; SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DIG 6 ; + DROP ; + DIG 2 ; + COMPARE ; + EQ ; + IF { NONE bytes ; UPDATE 9 } {} } } ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 3 ; + IF_NONE + { NIL operation } + { NIL operation ; + SWAP ; + EMIT %voting_finished + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload bytes)) ; + CONS } ; + DIG 4 ; + DIG 3 ; + DIG 3 ; + UPDATE 2 ; + SOME ; + UPDATE 3 ; + DIG 2 ; + UPDATE 5 } + { PUSH nat 33 ; + DUP 2 ; + SIZE ; + COMPARE ; + EQ ; + IF {} { PUSH string "INCORRECT_KERNEL_ROOT_HASH_LENGTH" ; FAILWITH } ; + DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option bytes)) ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option bytes)) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE bytes } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE bytes ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option bytes)) } ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option bytes)) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash bytes) unit) + (big_map bytes (pair key_hash nat)) + (option nat) + (option bytes) + nat) } + { SWAP ; + DROP ; + NONE bytes ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE bytes } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 4 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 4 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + SENDER ; + DIG 8 ; + SWAP ; + EXEC ; + DUP ; + VOTING_POWER ; + UNIT ; + DIG 9 ; + SWAP ; + EXEC ; + DROP ; + DUP ; + DIG 8 ; + SWAP ; + EXEC ; + DROP ; + DUP 3 ; + CDR ; + IF_LEFT { DIG 8 ; DROP } { DROP ; DIG 7 ; FAILWITH } ; + DUP ; + CAR ; + DUP 9 ; + CAR ; + GET 7 ; + DUP 2 ; + DUP 6 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + COMPARE ; + LT ; + IF {} { PUSH string "UPVOTING_LIMIT_EXCEEDED" ; FAILWITH } ; + DUP 2 ; + GET 5 ; + DUP 9 ; + MEM ; + NOT ; + IF {} { PUSH string "PROPOSAL_ALREADY_CREATED" ; FAILWITH } ; + DUP 2 ; + DUP 2 ; + DUP 6 ; + GET ; + IF_NONE + { SWAP ; PUSH nat 1 ; SOME ; DUP 6 ; UPDATE } + { DIG 2 ; PUSH nat 1 ; DIG 2 ; ADD ; SOME ; DUP 6 ; UPDATE } ; + UPDATE 1 ; + DUP 2 ; + GET 3 ; + UNIT ; + SOME ; + DUP 10 ; + DUP 7 ; + PAIR ; + UPDATE ; + UPDATE 3 ; + SWAP ; + GET 5 ; + DUP 3 ; + DIG 4 ; + PAIR ; + SOME ; + DUP 8 ; + UPDATE ; + UPDATE 5 ; + DUP ; + GET 7 ; + IF_NONE + { SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DUP ; + DUP 4 ; + COMPARE ; + GT ; + IF { DROP ; SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DIG 6 ; + DROP ; + DIG 2 ; + COMPARE ; + EQ ; + IF { NONE bytes ; UPDATE 9 } {} } } ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 3 ; + IF_NONE + { NIL operation } + { NIL operation ; + SWAP ; + EMIT %voting_finished + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload bytes)) ; + CONS } ; + DIG 4 ; + DIG 3 ; + DIG 3 ; + UPDATE 2 ; + SOME ; + UPDATE 3 ; + DIG 2 ; + UPDATE 5 } ; + SWAP } } ; + PAIR } ; + view "get_voting_state" + unit + (pair (nat %period_index) + (or %period_type (unit %proposal) (unit %promotion)) + (nat %remaining_blocks) + (option %finished_voting + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload bytes)))) + { PUSH string "CURRENT_LEVEL_LESS_THAN_START_LEVEL" ; + SWAP ; + CDR ; + DUP ; + CAR ; + DUP ; + CAR ; + LEVEL ; + SUB ; + ISNAT ; + IF_NONE + { DROP ; DUP 2 ; FAILWITH } + { SWAP ; + GET 3 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR } ; + DUP 2 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option bytes)) ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option bytes)) ; SWAP } + { DUP 3 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE bytes } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE bytes ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option bytes)) } ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option bytes)) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash bytes) unit) + (big_map bytes (pair key_hash nat)) + (option nat) + (option bytes) + nat) } + { SWAP ; + DROP ; + NONE bytes ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE bytes } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE bytes ; + NONE nat ; + EMPTY_BIG_MAP bytes (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat bytes) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 3 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 3 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + PAIR 3 ; + DUP ; + CAR ; + SWAP ; + GET 4 ; + DIG 2 ; + CAR ; + DUP ; + CAR ; + LEVEL ; + SUB ; + SWAP ; + GET 3 ; + SWAP ; + ISNAT ; + IF_NONE + { DROP ; DIG 2 ; FAILWITH } + { DIG 4 ; + DROP ; + DUP 2 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "MOD by 0" ; FAILWITH } {} ; + CDR ; + SWAP ; + SUB ; + ISNAT ; + IF_NONE { PUSH string "option is None" ; FAILWITH } {} } ; + DUP 3 ; + CDR ; + IF_LEFT { DROP ; UNIT ; LEFT unit } { DROP ; UNIT ; RIGHT unit } ; + DIG 3 ; + CAR ; + PAIR 4 } } + diff --git a/etherlink/tezos_contracts/governance/build/sequencer_governance.tz b/etherlink/tezos_contracts/governance/build/sequencer_governance.tz new file mode 100644 index 000000000000..f9646794736f --- /dev/null +++ b/etherlink/tezos_contracts/governance/build/sequencer_governance.tz @@ -0,0 +1,1545 @@ +{ parameter + (or (address %trigger_committee_upgrade) + (or (string %vote) + (or (pair %upvote_proposal (string %sequencer_pk) (bytes %pool_address)) + (pair %new_proposal (string %sequencer_pk) (bytes %pool_address))))) ; + storage + (pair (pair %config + (nat %started_at_level) + (nat %period_length) + (nat %adoption_period_sec) + (nat %upvoting_limit) + (nat %scale) + (nat %proposal_quorum) + (nat %promotion_quorum) + (nat %promotion_supermajority)) + (option %voting_context + (pair (nat %period_index) + (or %period + (pair %proposal + (big_map %upvoters_upvotes_count key_hash nat) + (big_map %upvoters_proposals + (pair key_hash (string %sequencer_pk) (bytes %pool_address)) + unit) + (big_map %proposals + (pair (string %sequencer_pk) (bytes %pool_address)) + (pair (key_hash %proposer) (nat %upvotes_voting_power))) + (option %max_upvotes_voting_power nat) + (option %winner_candidate (pair (string %sequencer_pk) (bytes %pool_address))) + (nat %total_voting_power)) + (pair %promotion + (big_map %voters key_hash string) + (nat %yea_voting_power) + (nat %nay_voting_power) + (nat %pass_voting_power) + (nat %total_voting_power) + (pair %winner_candidate (string %sequencer_pk) (bytes %pool_address)))))) + (option %last_winner + (pair (pair %payload (string %sequencer_pk) (bytes %pool_address)) + (big_map %trigger_history address unit))) + (big_map %metadata string bytes)) ; + code { PUSH string "NOT_PROPOSAL_PERIOD" ; + LAMBDA + address + key_hash + { DUP ; + PACK ; + PUSH bytes 0x00 ; + DUP 2 ; + PUSH nat 1 ; + PUSH nat 6 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + COMPARE ; + EQ ; + IF {} { PUSH string "NOT_IMPLICIT_ADDRESS" ; FAILWITH } ; + PUSH bytes 0x ; + NIL bytes ; + DUP 3 ; + PUSH nat 21 ; + PUSH nat 7 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + PUSH bytes 0x00000015 ; + CONS ; + DIG 2 ; + PUSH nat 2 ; + PUSH nat 0 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + UNPACK key_hash ; + PUSH string "FAILED_TO_CAST_ADDRESS_TO_KEY_HASH" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + PUSH string "KEY_HASH_NOT_EQUAL_TO_SOURCE_ADDRESS" ; + DIG 2 ; + DUP 3 ; + IMPLICIT_ACCOUNT ; + ADDRESS ; + COMPARE ; + EQ ; + IF { DROP } { FAILWITH } } ; + LAMBDA + (pair nat nat) + bytes + { UNPAIR ; + PUSH nat 56 ; + DUP 2 ; + COMPARE ; + LT ; + IF { ADD ; BYTES } + { BYTES ; + DUP ; + SIZE ; + PUSH nat 9 ; + DUP 2 ; + COMPARE ; + LT ; + IF {} { PUSH string "INPUT_TOO_LONG_FOR_RLP" ; FAILWITH } ; + PUSH nat 55 ; + DIG 3 ; + DIG 2 ; + ADD ; + ADD ; + BYTES ; + CONCAT } } ; + LAMBDA + unit + unit + { DROP ; + PUSH string "TEZ_IN_TRANSACTION_DISALLOWED" ; + PUSH mutez 0 ; + AMOUNT ; + COMPARE ; + EQ ; + IF { DROP ; UNIT } { FAILWITH } } ; + LAMBDA + nat + unit + { PUSH nat 0 ; + SWAP ; + COMPARE ; + GT ; + IF { UNIT } { PUSH string "NO_VOTING_POWER" ; FAILWITH } } ; + LAMBDA + (pair nat nat nat nat nat nat nat nat) + nat + { DUP ; + CAR ; + LEVEL ; + SUB ; + ISNAT ; + IF_NONE + { DROP ; PUSH string "CURRENT_LEVEL_LESS_THAN_START_LEVEL" ; FAILWITH } + { SWAP ; + GET 3 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR } } ; + DIG 6 ; + UNPAIR ; + IF_LEFT + { DIG 3 ; + DIG 6 ; + DIG 7 ; + DROP 3 ; + UNIT ; + DIG 4 ; + SWAP ; + EXEC ; + DROP ; + DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option (pair string bytes))) ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE (pair string bytes) } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE (pair string bytes) ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) } ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option (pair string bytes))) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash string bytes) unit) + (big_map (pair string bytes) (pair key_hash nat)) + (option nat) + (option (pair string bytes)) + nat) } + { SWAP ; + DROP ; + NONE (pair string bytes) ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE (pair string bytes) } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 4 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 4 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + SWAP ; + IF_NONE { PUSH string "LAST_WINNER_NOT_FOUND" ; FAILWITH } {} ; + DUP ; + CDR ; + DUP 5 ; + MEM ; + NOT ; + IF {} { PUSH string "UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED" ; FAILWITH } ; + DUP 4 ; + CONTRACT (or (or (pair %d bytes (ticket (pair nat (option bytes)))) (bytes %a)) (bytes %u)) ; + IF_NONE { PUSH string "ROLLUP_ENTRYPOINT_NOT_FOUND" ; FAILWITH } {} ; + DUP 2 ; + CAR ; + DUP 7 ; + CAR ; + GET 5 ; + INT ; + NOW ; + ADD ; + DUP 2 ; + CAR ; + PACK ; + DUP ; + PUSH nat 4 ; + PUSH nat 2 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + NAT ; + PUSH timestamp 0 ; + DIG 3 ; + SUB ; + ISNAT ; + PUSH string "NEGATIVE_TIMESTAMP" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + BYTES ; + PUSH bytes 0x ; + PUSH int 1 ; + PUSH int 1 ; + DUP 4 ; + SIZE ; + SUB ; + PUSH int 0 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 + { ISNAT ; + PUSH string "INDEX_NOT_NAT" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + SWAP ; + DUP 3 ; + PUSH nat 1 ; + DIG 3 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + SWAP ; + DROP ; + DUP ; + SIZE ; + INT ; + PUSH int 1 ; + PUSH int 1 ; + PUSH nat 8 ; + SUB ; + DIG 2 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 { DROP ; PUSH bytes 0x00 ; SWAP ; CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + NIL bytes ; + SWAP ; + CONS ; + DIG 3 ; + CDR ; + CONS ; + DUG 2 ; + PUSH nat 6 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + MAP { DUP ; + SIZE ; + PUSH bytes 0x80 ; + DUP 3 ; + COMPARE ; + LT ; + PUSH nat 1 ; + DUP 3 ; + COMPARE ; + EQ ; + AND ; + IF { DROP ; PUSH bytes 0x } + { PUSH nat 128 ; SWAP ; PAIR ; DUP 9 ; SWAP ; EXEC } ; + CONCAT } ; + PUSH bytes 0x ; + SWAP ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + PUSH nat 192 ; + DUP 2 ; + SIZE ; + PAIR ; + DIG 8 ; + SWAP ; + EXEC ; + CONCAT ; + RIGHT (or (pair bytes (ticket (pair nat (option bytes)))) bytes) ; + SWAP ; + PUSH mutez 0 ; + DIG 2 ; + TRANSFER_TOKENS ; + DIG 3 ; + IF_NONE + { NIL operation } + { NIL operation ; + SWAP ; + EMIT %voting_finished + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload + (pair (string %sequencer_pk) (bytes %pool_address)))) ; + CONS } ; + DIG 5 ; + DIG 4 ; + SOME ; + UPDATE 3 ; + DUP 4 ; + DIG 4 ; + CDR ; + UNIT ; + SOME ; + DIG 6 ; + UPDATE ; + UPDATE 2 ; + SOME ; + UPDATE 5 ; + SWAP ; + DIG 2 ; + CONS } + { DIG 5 ; + DROP ; + IF_LEFT + { DIG 6 ; + DROP ; + DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option (pair string bytes))) ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE (pair string bytes) } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE (pair string bytes) ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) } ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option (pair string bytes))) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash string bytes) unit) + (big_map (pair string bytes) (pair key_hash nat)) + (option nat) + (option (pair string bytes)) + nat) } + { SWAP ; + DROP ; + NONE (pair string bytes) ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE (pair string bytes) } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } ; + DIG 2 ; + PAIR } } ; + SWAP ; + DROP ; + SENDER ; + DIG 6 ; + SWAP ; + EXEC ; + DUP ; + VOTING_POWER ; + UNIT ; + DIG 7 ; + SWAP ; + EXEC ; + DROP ; + DUP ; + DIG 6 ; + SWAP ; + EXEC ; + DROP ; + DUP 3 ; + CDR ; + IF_LEFT { DROP ; PUSH string "NOT_PROMOTION_PERIOD" ; FAILWITH } {} ; + DUP ; + CAR ; + DUP 4 ; + MEM ; + NOT ; + IF {} { PUSH string "PROMOTION_ALREADY_VOTED" ; FAILWITH } ; + PUSH string "yea" ; + DUP 6 ; + COMPARE ; + EQ ; + IF { DUP ; DIG 2 ; DUP 3 ; GET 3 ; ADD ; UPDATE 3 } + { PUSH string "nay" ; + DUP 6 ; + COMPARE ; + EQ ; + IF { DUP ; DIG 2 ; DUP 3 ; GET 5 ; ADD ; UPDATE 5 } + { PUSH string "pass" ; + DUP 6 ; + COMPARE ; + EQ ; + IF { DUP ; DIG 2 ; DUP 3 ; GET 7 ; ADD ; UPDATE 7 } + { SWAP ; DROP ; PUSH string "INCORRECT_VOTE_VALUE" ; FAILWITH } } } ; + SWAP ; + CAR ; + DIG 4 ; + SOME ; + DIG 3 ; + UPDATE ; + UPDATE 1 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash string bytes) unit) + (big_map (pair string bytes) (pair key_hash nat)) + (option nat) + (option (pair string bytes)) + nat) ; + UPDATE 2 ; + SOME ; + UPDATE 3 ; + NIL operation } + { IF_LEFT + { DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option (pair string bytes))) ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE (pair string bytes) } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE (pair string bytes) ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) } ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option (pair string bytes))) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash string bytes) unit) + (big_map (pair string bytes) (pair key_hash nat)) + (option nat) + (option (pair string bytes)) + nat) } + { SWAP ; + DROP ; + NONE (pair string bytes) ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE (pair string bytes) } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 4 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 4 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + SENDER ; + DIG 8 ; + SWAP ; + EXEC ; + DUP ; + VOTING_POWER ; + UNIT ; + DIG 9 ; + SWAP ; + EXEC ; + DROP ; + DUP ; + DIG 8 ; + SWAP ; + EXEC ; + DROP ; + DUP 3 ; + CDR ; + IF_LEFT { DIG 8 ; DROP } { DROP ; DIG 7 ; FAILWITH } ; + DUP ; + CAR ; + DUP 9 ; + CAR ; + GET 7 ; + DUP 2 ; + DUP 6 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + COMPARE ; + LT ; + IF {} { PUSH string "UPVOTING_LIMIT_EXCEEDED" ; FAILWITH } ; + DUP 2 ; + GET 5 ; + DUP 9 ; + GET ; + IF_NONE { PUSH string "PROPOSAL_NOT_FOUND" ; FAILWITH } {} ; + DUP 3 ; + GET 3 ; + DUP ; + DUP 11 ; + DUP 8 ; + PAIR ; + MEM ; + NOT ; + IF {} { PUSH string "PROPOSAL_ALREADY_UPVOTED" ; FAILWITH } ; + DIG 4 ; + DUP 3 ; + CDR ; + ADD ; + DUP 5 ; + DUP 5 ; + DUP 8 ; + GET ; + IF_NONE + { DIG 4 ; PUSH nat 1 ; SOME ; DUP 8 ; UPDATE } + { DIG 5 ; PUSH nat 1 ; DIG 2 ; ADD ; SOME ; DUP 8 ; UPDATE } ; + UPDATE 1 ; + DIG 2 ; + UNIT ; + SOME ; + DUP 11 ; + DIG 7 ; + PAIR ; + UPDATE ; + UPDATE 3 ; + DIG 3 ; + GET 5 ; + DIG 3 ; + DUP 4 ; + UPDATE 2 ; + SOME ; + DUP 8 ; + UPDATE ; + UPDATE 5 ; + DUP ; + GET 7 ; + IF_NONE + { SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DUP ; + DUP 4 ; + COMPARE ; + GT ; + IF { DROP ; SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DIG 6 ; + DROP ; + DIG 2 ; + COMPARE ; + EQ ; + IF { NONE (pair string bytes) ; UPDATE 9 } {} } } ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 3 ; + IF_NONE + { NIL operation } + { NIL operation ; + SWAP ; + EMIT %voting_finished + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload + (pair (string %sequencer_pk) (bytes %pool_address)))) ; + CONS } ; + DIG 4 ; + DIG 3 ; + DIG 3 ; + UPDATE 2 ; + SOME ; + UPDATE 3 ; + DIG 2 ; + UPDATE 5 } + { DUP ; + UNPAIR ; + SIZE ; + PUSH nat 55 ; + DUP 2 ; + COMPARE ; + EQ ; + PUSH nat 54 ; + DIG 2 ; + COMPARE ; + EQ ; + OR ; + IF {} { PUSH string "INCORRECT_SEQUENCER_PK_LENGTH" ; FAILWITH } ; + PUSH nat 20 ; + SWAP ; + SIZE ; + COMPARE ; + EQ ; + IF {} { PUSH string "INCORRECT_POOL_ADDRESS_LENGTH" ; FAILWITH } ; + DUP 2 ; + CAR ; + DIG 3 ; + SWAP ; + EXEC ; + DUP 3 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option (pair string bytes))) ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) ; SWAP } + { DUP 4 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE (pair string bytes) } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE (pair string bytes) ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) } ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option (pair string bytes))) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash string bytes) unit) + (big_map (pair string bytes) (pair key_hash nat)) + (option nat) + (option (pair string bytes)) + nat) } + { SWAP ; + DROP ; + NONE (pair string bytes) ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE (pair string bytes) } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 4 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 4 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + SENDER ; + DIG 8 ; + SWAP ; + EXEC ; + DUP ; + VOTING_POWER ; + UNIT ; + DIG 9 ; + SWAP ; + EXEC ; + DROP ; + DUP ; + DIG 8 ; + SWAP ; + EXEC ; + DROP ; + DUP 3 ; + CDR ; + IF_LEFT { DIG 8 ; DROP } { DROP ; DIG 7 ; FAILWITH } ; + DUP ; + CAR ; + DUP 9 ; + CAR ; + GET 7 ; + DUP 2 ; + DUP 6 ; + GET ; + IF_NONE { PUSH nat 0 } {} ; + COMPARE ; + LT ; + IF {} { PUSH string "UPVOTING_LIMIT_EXCEEDED" ; FAILWITH } ; + DUP 2 ; + GET 5 ; + DUP 9 ; + MEM ; + NOT ; + IF {} { PUSH string "PROPOSAL_ALREADY_CREATED" ; FAILWITH } ; + DUP 2 ; + DUP 2 ; + DUP 6 ; + GET ; + IF_NONE + { SWAP ; PUSH nat 1 ; SOME ; DUP 6 ; UPDATE } + { DIG 2 ; PUSH nat 1 ; DIG 2 ; ADD ; SOME ; DUP 6 ; UPDATE } ; + UPDATE 1 ; + DUP 2 ; + GET 3 ; + UNIT ; + SOME ; + DUP 10 ; + DUP 7 ; + PAIR ; + UPDATE ; + UPDATE 3 ; + SWAP ; + GET 5 ; + DUP 3 ; + DIG 4 ; + PAIR ; + SOME ; + DUP 8 ; + UPDATE ; + UPDATE 5 ; + DUP ; + GET 7 ; + IF_NONE + { SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DUP ; + DUP 4 ; + COMPARE ; + GT ; + IF { DROP ; SWAP ; SOME ; UPDATE 7 ; DIG 4 ; SOME ; UPDATE 9 } + { DIG 6 ; + DROP ; + DIG 2 ; + COMPARE ; + EQ ; + IF { NONE (pair string bytes) ; UPDATE 9 } {} } } ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 3 ; + IF_NONE + { NIL operation } + { NIL operation ; + SWAP ; + EMIT %voting_finished + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload + (pair (string %sequencer_pk) (bytes %pool_address)))) ; + CONS } ; + DIG 4 ; + DIG 3 ; + DIG 3 ; + UPDATE 2 ; + SOME ; + UPDATE 3 ; + DIG 2 ; + UPDATE 5 } ; + SWAP } } ; + PAIR } ; + view "get_voting_state" + unit + (pair (nat %period_index) + (or %period_type (unit %proposal) (unit %promotion)) + (nat %remaining_blocks) + (option %finished_voting + (pair (nat %finished_at_period_index) + (or %finished_at_period_type (unit %proposal) (unit %promotion)) + (option %winner_proposal_payload + (pair (string %sequencer_pk) (bytes %pool_address)))))) + { PUSH string "CURRENT_LEVEL_LESS_THAN_START_LEVEL" ; + SWAP ; + CDR ; + DUP ; + CAR ; + DUP ; + CAR ; + LEVEL ; + SUB ; + ISNAT ; + IF_NONE + { DROP ; DUP 2 ; FAILWITH } + { SWAP ; + GET 3 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "DIV by 0" ; FAILWITH } {} ; + CAR } ; + DUP 2 ; + GET 3 ; + IF_NONE + { NONE (pair nat (or unit unit) (option (pair string bytes))) ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) ; + DIG 2 ; + PAIR } + { DUP ; + CAR ; + DUP 3 ; + COMPARE ; + EQ ; + IF { SWAP ; DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) ; SWAP } + { DUP 3 ; + CAR ; + DUP 2 ; + CDR ; + IF_LEFT + { DUP 2 ; + GET 11 ; + DUP 2 ; + GET 10 ; + MUL ; + DIG 2 ; + GET 9 ; + DUP 3 ; + GET 7 ; + IF_NONE { PUSH nat 0 } {} ; + MUL ; + COMPARE ; + GE ; + IF { DUP ; GET 9 } { NONE (pair string bytes) } ; + IF_NONE + { GET 7 ; + IF_NONE { PUSH bool False } { DROP ; PUSH bool True } ; + IF { NONE (pair string bytes) ; + UNIT ; + LEFT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME } + { DROP ; NONE (pair nat (or unit unit) (option (pair string bytes))) } ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } + { SWAP ; + DROP ; + PUSH nat 1 ; + DIG 2 ; + CAR ; + ADD ; + DUP ; + DUP 4 ; + COMPARE ; + EQ ; + IF { DROP ; + NONE (pair nat (or unit unit) (option (pair string bytes))) ; + SWAP ; + TOTAL_VOTING_POWER ; + PUSH nat 0 ; + PUSH nat 0 ; + PUSH nat 0 ; + EMPTY_BIG_MAP key_hash string ; + PAIR 6 ; + RIGHT + (pair (big_map key_hash nat) + (big_map (pair key_hash string bytes) unit) + (big_map (pair string bytes) (pair key_hash nat)) + (option nat) + (option (pair string bytes)) + nat) } + { SWAP ; + DROP ; + NONE (pair string bytes) ; + UNIT ; + RIGHT unit ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } } } + { UNPAIR 6 ; + DROP ; + DIG 3 ; + DUP 6 ; + GET 13 ; + MUL ; + DUP 6 ; + GET 9 ; + DIG 4 ; + DUP 5 ; + DUP 5 ; + ADD ; + ADD ; + MUL ; + COMPARE ; + GE ; + DIG 2 ; + DUP 3 ; + ADD ; + DUP ; + DUP 6 ; + GET 14 ; + MUL ; + DIG 5 ; + GET 9 ; + DIG 4 ; + MUL ; + COMPARE ; + GE ; + PUSH nat 0 ; + DIG 2 ; + COMPARE ; + GT ; + AND ; + AND ; + IF { SOME } { DROP ; NONE (pair string bytes) } ; + UNIT ; + RIGHT unit ; + DIG 2 ; + CAR ; + DUG 2 ; + PUSH nat 1 ; + DIG 3 ; + ADD ; + PAIR 3 ; + SOME ; + TOTAL_VOTING_POWER ; + NONE (pair string bytes) ; + NONE nat ; + EMPTY_BIG_MAP (pair string bytes) (pair key_hash nat) ; + EMPTY_BIG_MAP (pair key_hash string bytes) unit ; + EMPTY_BIG_MAP key_hash nat ; + PAIR 6 ; + LEFT (pair (big_map key_hash string) nat nat nat nat (pair string bytes)) } ; + DIG 2 ; + PAIR } } ; + DUP 2 ; + DIG 2 ; + IF_NONE + { DUP 3 ; GET 5 } + { GET 4 ; + IF_NONE + { DUP 3 ; GET 5 } + { EMPTY_BIG_MAP address unit ; SWAP ; PAIR ; SOME } } ; + DIG 2 ; + PAIR 3 ; + DUP ; + CAR ; + SWAP ; + GET 4 ; + DIG 2 ; + CAR ; + DUP ; + CAR ; + LEVEL ; + SUB ; + SWAP ; + GET 3 ; + SWAP ; + ISNAT ; + IF_NONE + { DROP ; DIG 2 ; FAILWITH } + { DIG 4 ; + DROP ; + DUP 2 ; + SWAP ; + EDIV ; + IF_NONE { PUSH string "MOD by 0" ; FAILWITH } {} ; + CDR ; + SWAP ; + SUB ; + ISNAT ; + IF_NONE { PUSH string "option is None" ; FAILWITH } {} } ; + DUP 3 ; + CDR ; + IF_LEFT { DROP ; UNIT ; LEFT unit } { DROP ; UNIT ; RIGHT unit } ; + DIG 3 ; + CAR ; + PAIR 4 } } + diff --git a/etherlink/tezos_contracts/governance/build/test/internal_test_proxy.tz b/etherlink/tezos_contracts/governance/build/test/internal_test_proxy.tz new file mode 100644 index 000000000000..734d0bd3d2cc --- /dev/null +++ b/etherlink/tezos_contracts/governance/build/test/internal_test_proxy.tz @@ -0,0 +1,343 @@ +{ parameter unit ; + storage unit ; + code { CDR ; NIL operation ; PAIR } ; + view "get_kernel_upgrade_payload" + (pair (bytes %kernel_root_hash) (timestamp %activation_timestamp)) + bytes + { LAMBDA + (pair nat nat) + bytes + { UNPAIR ; + PUSH nat 56 ; + DUP 2 ; + COMPARE ; + LT ; + IF { ADD ; BYTES } + { BYTES ; + DUP ; + SIZE ; + PUSH nat 9 ; + DUP 2 ; + COMPARE ; + LT ; + IF {} { PUSH string "INPUT_TOO_LONG_FOR_RLP" ; FAILWITH } ; + PUSH nat 55 ; + DIG 3 ; + DIG 2 ; + ADD ; + ADD ; + BYTES ; + CONCAT } } ; + SWAP ; + CAR ; + UNPAIR ; + PUSH nat 33 ; + DUP 2 ; + SIZE ; + COMPARE ; + EQ ; + IF {} { PUSH string "INCORRECT_KERNEL_ROOT_HASH_LENGTH" ; FAILWITH } ; + PUSH timestamp 0 ; + DIG 2 ; + SUB ; + ISNAT ; + PUSH string "NEGATIVE_TIMESTAMP" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + BYTES ; + PUSH bytes 0x ; + PUSH int 1 ; + PUSH int 1 ; + DUP 4 ; + SIZE ; + SUB ; + PUSH int 0 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 + { ISNAT ; + PUSH string "INDEX_NOT_NAT" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + SWAP ; + DUP 3 ; + PUSH nat 1 ; + DIG 3 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + SWAP ; + DROP ; + DUP ; + SIZE ; + INT ; + PUSH int 1 ; + PUSH int 1 ; + PUSH nat 8 ; + SUB ; + DIG 2 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 { DROP ; PUSH bytes 0x00 ; SWAP ; CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + NIL bytes ; + SWAP ; + CONS ; + SWAP ; + CONS ; + MAP { DUP ; + SIZE ; + PUSH bytes 0x80 ; + DUP 3 ; + COMPARE ; + LT ; + PUSH nat 1 ; + DUP 3 ; + COMPARE ; + EQ ; + AND ; + IF { DROP ; PUSH bytes 0x } + { PUSH nat 128 ; SWAP ; PAIR ; DUP 3 ; SWAP ; EXEC } ; + CONCAT } ; + PUSH bytes 0x ; + SWAP ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + PUSH nat 192 ; + DUP 2 ; + SIZE ; + PAIR ; + DIG 2 ; + SWAP ; + EXEC ; + CONCAT } ; + view "get_sequencer_upgrade_payload" + (pair (string %sequencer_pk) + (bytes %pool_address) + (timestamp %activation_timestamp)) + bytes + { LAMBDA + (pair nat nat) + bytes + { UNPAIR ; + PUSH nat 56 ; + DUP 2 ; + COMPARE ; + LT ; + IF { ADD ; BYTES } + { BYTES ; + DUP ; + SIZE ; + PUSH nat 9 ; + DUP 2 ; + COMPARE ; + LT ; + IF {} { PUSH string "INPUT_TOO_LONG_FOR_RLP" ; FAILWITH } ; + PUSH nat 55 ; + DIG 3 ; + DIG 2 ; + ADD ; + ADD ; + BYTES ; + CONCAT } } ; + SWAP ; + CAR ; + UNPAIR 3 ; + DUP ; + SIZE ; + PUSH nat 55 ; + DUP 2 ; + COMPARE ; + EQ ; + PUSH nat 54 ; + DIG 2 ; + COMPARE ; + EQ ; + OR ; + IF {} { PUSH string "INCORRECT_SEQUENCER_PK_LENGTH" ; FAILWITH } ; + PUSH nat 20 ; + DUP 3 ; + SIZE ; + COMPARE ; + EQ ; + IF {} { PUSH string "INCORRECT_POOL_ADDRESS_LENGTH" ; FAILWITH } ; + PACK ; + DUP ; + PUSH nat 4 ; + PUSH nat 2 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + NAT ; + PUSH timestamp 0 ; + DIG 4 ; + SUB ; + ISNAT ; + PUSH string "NEGATIVE_TIMESTAMP" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + BYTES ; + PUSH bytes 0x ; + PUSH int 1 ; + PUSH int 1 ; + DUP 4 ; + SIZE ; + SUB ; + PUSH int 0 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 + { ISNAT ; + PUSH string "INDEX_NOT_NAT" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + SWAP ; + DUP 3 ; + PUSH nat 1 ; + DIG 3 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + SWAP ; + DROP ; + DUP ; + SIZE ; + INT ; + PUSH int 1 ; + PUSH int 1 ; + PUSH nat 8 ; + SUB ; + DIG 2 ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE ; + LOOP { DUP ; + DUG 3 ; + DIP 3 { DROP ; PUSH bytes 0x00 ; SWAP ; CONCAT } ; + DUP 3 ; + ADD ; + DUP 2 ; + DUP 2 ; + COMPARE ; + LE } ; + DROP 3 ; + NIL bytes ; + SWAP ; + CONS ; + DIG 3 ; + CONS ; + DUG 2 ; + PUSH nat 6 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + MAP { DUP ; + SIZE ; + PUSH bytes 0x80 ; + DUP 3 ; + COMPARE ; + LT ; + PUSH nat 1 ; + DUP 3 ; + COMPARE ; + EQ ; + AND ; + IF { DROP ; PUSH bytes 0x } + { PUSH nat 128 ; SWAP ; PAIR ; DUP 3 ; SWAP ; EXEC } ; + CONCAT } ; + PUSH bytes 0x ; + SWAP ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + PUSH nat 192 ; + DUP 2 ; + SIZE ; + PAIR ; + DIG 2 ; + SWAP ; + EXEC ; + CONCAT } ; + view "address_to_key_hash" + address + key_hash + { CAR ; + DUP ; + PACK ; + PUSH bytes 0x00 ; + DUP 2 ; + PUSH nat 1 ; + PUSH nat 6 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + COMPARE ; + EQ ; + IF {} { PUSH string "NOT_IMPLICIT_ADDRESS" ; FAILWITH } ; + PUSH bytes 0x ; + NIL bytes ; + DUP 3 ; + PUSH nat 21 ; + PUSH nat 7 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + PUSH bytes 0x00000015 ; + CONS ; + DIG 2 ; + PUSH nat 2 ; + PUSH nat 0 ; + SLICE ; + IF_NONE { PUSH string "SLICE" ; FAILWITH } {} ; + CONS ; + NIL bytes ; + SWAP ; + ITER { CONS } ; + ITER { CONCAT } ; + UNPACK key_hash ; + PUSH string "FAILED_TO_CAST_ADDRESS_TO_KEY_HASH" ; + SWAP ; + IF_NONE { FAILWITH } { SWAP ; DROP } ; + PUSH string "KEY_HASH_NOT_EQUAL_TO_SOURCE_ADDRESS" ; + DIG 2 ; + DUP 3 ; + IMPLICIT_ACCOUNT ; + ADDRESS ; + COMPARE ; + EQ ; + IF { DROP } { FAILWITH } } } + diff --git a/etherlink/tezos_contracts/governance/build/test/rollup_mock.tz b/etherlink/tezos_contracts/governance/build/test/rollup_mock.tz new file mode 100644 index 000000000000..f5e6b69569ae --- /dev/null +++ b/etherlink/tezos_contracts/governance/build/test/rollup_mock.tz @@ -0,0 +1,7 @@ +{ parameter (or (or (pair %d bytes (ticket (pair nat (option bytes)))) (bytes %a)) (bytes %u)) ; + storage bytes ; + code { CAR ; + IF_LEFT { DROP ; PUSH string "WRONG_ROLLUP_ENTRYPOINT" ; FAILWITH } {} ; + NIL operation ; + PAIR } } + diff --git a/etherlink/tezos_contracts/governance/contracts/common/constants.mligo b/etherlink/tezos_contracts/governance/contracts/common/constants.mligo new file mode 100644 index 000000000000..6b81e75de554 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/constants.mligo @@ -0,0 +1,3 @@ +let yea = "yea" +let nay = "nay" +let pass = "pass" \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/common/entrypoints.mligo b/etherlink/tezos_contracts/governance/contracts/common/entrypoints.mligo new file mode 100644 index 000000000000..fa6e7b894a10 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/entrypoints.mligo @@ -0,0 +1,102 @@ +#import "storage.mligo" "Storage" +#import "errors.mligo" "Errors" +#import "voting.mligo" "Voting" +#import "rollup.mligo" "Rollup" +#import "events.mligo" "Events" +#import "validation.mligo" "Validation" +#import "utils/converters.mligo" "Converters" + + +let new_proposal + (type pt) + (payload : pt) + (storage : pt Storage.t) + : operation list * pt Storage.t = + let { voting_context; finished_voting; last_winner } = Voting.get_voting_state storage in + let proposer = Converters.address_to_key_hash (Tezos.get_sender ()) in + let voting_power = Tezos.voting_power proposer in + let _ = Validation.assert_no_tez_in_transaction () in + let _ = Validation.assert_voting_power_positive voting_power in + let proposal_period = Voting.get_proposal_period voting_context in + let updated_period = Voting.add_new_proposal_and_upvote payload proposer voting_power proposal_period storage.config in + let operations = match finished_voting with + | Some event_payload -> [Events.create_voting_finished_event_operation event_payload] + | None -> [] in + let updated_storage = { + storage with + voting_context = Some { voting_context with period = updated_period; }; + last_winner = last_winner; + } in + operations, updated_storage + + +let upvote_proposal + (type pt) + (payload : pt) + (storage : pt Storage.t) + : operation list * pt Storage.t = + let { voting_context; finished_voting; last_winner } = Voting.get_voting_state storage in + let upvoter = Converters.address_to_key_hash (Tezos.get_sender ()) in + let voting_power = Tezos.voting_power upvoter in + let _ = Validation.assert_no_tez_in_transaction () in + let _ = Validation.assert_voting_power_positive voting_power in + let proposal_period = Voting.get_proposal_period voting_context in + let updated_period = Voting.upvote_proposal payload upvoter voting_power proposal_period storage.config in + let operations = match finished_voting with + | Some event_payload -> [Events.create_voting_finished_event_operation event_payload] + | None -> [] in + let updated_storage = { + storage with + voting_context = Some { voting_context with period = updated_period }; + last_winner = last_winner; + } in + operations, updated_storage + + +let vote + (type pt) + (vote : string) + (storage : pt Storage.t) + : operation list * pt Storage.t = + let voting_state = Voting.get_voting_state storage in + let voting_context = voting_state.voting_context in + let voter = Converters.address_to_key_hash (Tezos.get_sender ()) in + let voting_power = Tezos.voting_power voter in + let _ = Validation.assert_no_tez_in_transaction () in + let _ = Validation.assert_voting_power_positive voting_power in + let promotion_period = Voting.get_promotion_period voting_context in + let updated_period = Voting.vote_promotion vote voter voting_power promotion_period in + let updated_storage = { + storage with + voting_context = Some { voting_context with period = updated_period }; + } in + [], updated_storage + + +let trigger_rollup_upgrade + (type pt) + (rollup_address : address) + (storage : pt Storage.t) + (pack_payload : pt -> bytes) + : operation list * pt Storage.t = + let _ = Validation.assert_no_tez_in_transaction () in + let { voting_context; finished_voting; last_winner = last_winner_opt } = Voting.get_voting_state storage in + let last_winner = Option.value_with_error Errors.last_winner_not_found last_winner_opt in + let last_winner_trigger_history = last_winner.trigger_history in + let _ = assert_with_error (not Big_map.mem rollup_address last_winner.trigger_history) Errors.upgrade_for_address_already_triggered in + let rollup_entry = Rollup.get_entry rollup_address in + let upgrade_params = Rollup.get_upgrade_params (pack_payload last_winner.payload) in + let upgrade_operation = Tezos.transaction upgrade_params 0tez rollup_entry in + let operations = match finished_voting with + | Some event_payload -> [Events.create_voting_finished_event_operation event_payload] + | None -> [] in + let operations = upgrade_operation :: operations in + let updated_storage = { + storage with + voting_context = Some voting_context; + last_winner = Some { + last_winner with + trigger_history = Big_map.add rollup_address unit last_winner_trigger_history + } + } in + operations, updated_storage diff --git a/etherlink/tezos_contracts/governance/contracts/common/errors.mligo b/etherlink/tezos_contracts/governance/contracts/common/errors.mligo new file mode 100644 index 000000000000..7c01ba5af301 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/errors.mligo @@ -0,0 +1,24 @@ +let no_voting_power = "NO_VOTING_POWER" +let not_proposal_period = "NOT_PROPOSAL_PERIOD" +let not_promotion_period = "NOT_PROMOTION_PERIOD" +let tez_in_transaction_disallowed = "TEZ_IN_TRANSACTION_DISALLOWED" +let upvoting_limit_exceeded = "UPVOTING_LIMIT_EXCEEDED" +let proposal_not_found = "PROPOSAL_NOT_FOUND" +let proposal_already_created = "PROPOSAL_ALREADY_CREATED" +let proposal_already_upvoted = "PROPOSAL_ALREADY_UPVOTED" +let promotion_already_voted = "PROMOTION_ALREADY_VOTED" +let rollup_entrypoint_not_found = "ROLLUP_ENTRYPOINT_NOT_FOUND" +let last_winner_not_found = "LAST_WINNER_NOT_FOUND" +let current_level_less_than_start_level = "CURRENT_LEVEL_LESS_THAN_START_LEVEL" +let incorrect_kernel_root_hash_length = "INCORRECT_KERNEL_ROOT_HASH_LENGTH" +let incorrect_sequencer_pk_length = "INCORRECT_SEQUENCER_PK_LENGTH" +let incorrect_pool_address_length = "INCORRECT_POOL_ADDRESS_LENGTH" +let incorrect_vote_value = "INCORRECT_VOTE_VALUE" +let not_implicit_address = "NOT_IMPLICIT_ADDRESS" +let failed_to_cast_address_to_key_hash = "FAILED_TO_CAST_ADDRESS_TO_KEY_HASH" +let key_hash_not_equal_to_source_address = "KEY_HASH_NOT_EQUAL_TO_SOURCE_ADDRESS" +let wrong_rollup_entrypoint = "WRONG_ROLLUP_ENTRYPOINT" +let upgrade_for_address_already_triggered = "UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED" +let index_not_nat = "INDEX_NOT_NAT" +let input_too_long_for_rlp = "INPUT_TOO_LONG_FOR_RLP" +let negative_timestamp = "NEGATIVE_TIMESTAMP" \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/common/events.mligo b/etherlink/tezos_contracts/governance/contracts/common/events.mligo new file mode 100644 index 000000000000..8730dc449cd7 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/events.mligo @@ -0,0 +1,30 @@ +#import "storage.mligo" "Storage" + +type period_type_t = Proposal | Promotion + +type 'pt voting_finished_event_payload_t = { + finished_at_period_index : nat; + finished_at_period_type : period_type_t; + winner_proposal_payload : 'pt option; +} + +[@inline] +let create_voting_finished_event + (type pt) + (period_index : nat) + (period_type : period_type_t) + (winner_proposal_payload : pt option) + : pt voting_finished_event_payload_t = + { + finished_at_period_index = period_index + 1n; + finished_at_period_type = period_type; + winner_proposal_payload = winner_proposal_payload; + } + + +[@inline] +let create_voting_finished_event_operation + (type pt) + (event_payload : pt voting_finished_event_payload_t) + : operation = + Tezos.emit "%voting_finished" event_payload diff --git a/etherlink/tezos_contracts/governance/contracts/common/rollup.mligo b/etherlink/tezos_contracts/governance/contracts/common/rollup.mligo new file mode 100644 index 000000000000..914ddfe60c34 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/rollup.mligo @@ -0,0 +1,100 @@ +#import "errors.mligo" "Errors" +#import "utils/converters.mligo" "Converters" +#import "utils/rlp.mligo" "RLP" +#import "utils/byte_utils.mligo" "ByteUtils" +#import "utils/converters.mligo" "Converters" + +type content_t = nat * bytes option +type ticket_t = content_t ticket +type deposit_t = bytes * ticket_t + +type deposit_or_bytes_t = ( + deposit_t, + "d", + bytes, + "a" +) michelson_or + +type t = ( + deposit_or_bytes_t, + "", + bytes, + "u" +) michelson_or + + +let get_entry // NOTE: the entrypoint is used to upgrade kernel and sequencer committee as well + (rollup : address) + : t contract = + match Tezos.get_contract_opt rollup with + | None -> failwith Errors.rollup_entrypoint_not_found + | Some entry -> entry + + +let get_upgrade_params + (payload : bytes) + : t = + M_right payload + + +let timestamp_to_padded_little_endian_bytes + (value : timestamp) + : bytes = + let timestamp_number : nat = Converters.timestamp_to_nat value in + let timestamp_bytes = Converters.nat_to_little_endian_bytes timestamp_number in + ByteUtils.pad_end timestamp_bytes 8n + + +let assert_kernel_root_hash_has_correct_length + (kernel_root_hash : bytes) + : unit = + assert_with_error ((Bytes.length kernel_root_hash) = 33n) Errors.incorrect_kernel_root_hash_length + + +let get_kernel_upgrade_payload + (kernel_root_hash : bytes) + (activation_timestamp : timestamp) + : bytes = + let timestamp_bytes = timestamp_to_padded_little_endian_bytes activation_timestamp in + RLP.encode_list [kernel_root_hash ; timestamp_bytes] + + +let assert_sequencer_upgrade_payload_is_correct + (sequencer_pk : string) + (pool_address : bytes) + : unit = + let sequencer_pk_length = String.length sequencer_pk in + let _ = assert_with_error ((sequencer_pk_length = 54n) || (sequencer_pk_length = 55n)) Errors.incorrect_sequencer_pk_length in + assert_with_error ((Bytes.length pool_address) = 20n) Errors.incorrect_pool_address_length + + +let public_key_to_bytes + (public_key : string) + : bytes = + let michelson_bytes = Bytes.pack public_key in + let length = Converters.bytes_to_nat (Bytes.sub 2n 4n michelson_bytes) in + Bytes.sub 6n length michelson_bytes + + +let get_sequencer_upgrade_payload + (sequencer_pk : string) + (pool_address : bytes) + (activation_timestamp : timestamp) + : bytes = + let sequencer_pk_bytes = public_key_to_bytes sequencer_pk in + let timestamp_bytes = timestamp_to_padded_little_endian_bytes activation_timestamp in + RLP.encode_list [sequencer_pk_bytes ; pool_address ; timestamp_bytes] + + +let decode_upgrade_payload + (rollup_entry : t) + : bytes = + match rollup_entry with + | M_right bytes -> bytes + | M_left _ -> failwith Errors.wrong_rollup_entrypoint + + +let get_activation_timestamp + (adoption_period_sec : nat) + : timestamp = + Tezos.get_now () + (int adoption_period_sec) diff --git a/etherlink/tezos_contracts/governance/contracts/common/storage.mligo b/etherlink/tezos_contracts/governance/contracts/common/storage.mligo new file mode 100644 index 000000000000..0fcce253d953 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/storage.mligo @@ -0,0 +1,106 @@ +(* + NOTE: + started_at_level and period_length values should be chosen carefully + to be sure that the contract governance periods + never cross the boundaries of the tezos protocol governance periods. + This ensures the immutability of voting power throughout the entire voting period +*) +type config_t = { + (* + Used to align voting periods with protocol governance periods. + Should be the start level of the current protocol governance period + *) + started_at_level : nat; + + (* + The duration of the of proposal and promotion periods represented in blocks. + period_length = tezos_governance_period_length / N, where N is integer divisor (factor) + *) + period_length : nat; + + (* + The duration of the l2 adoption period counted in seconds. + Used to generate an upgrade payload with activation timestamp + on trigger_upgrade entrypoint call + *) + adoption_period_sec : nat; + + (* Number of proposals that an account may upvote and submit *) + upvoting_limit : nat; + + (* + The scale for proposal_quorum, promotion_quorum and promotion_supermajority params. + For example if config.scale = 100 and config.proposal_quorum = 80 + then proposal_quorum_% == 80 / 100 == .80 == 80% + *) + scale : nat; + + (* + Minimum ratio of all the cumulated stake of a proposal upvotes to the total stake + to advance the proposal to promotion period + *) + proposal_quorum : nat; + + (* + Minimum ratio of all the cumulated stake of cast ballots (yea, nay, and pass ballots) + to the total stake to consider the proposal as a voting winner + *) + promotion_quorum : nat; + + (* + Minimum ratio of cumulated stake of Yea ballots to the cumulated stake + of Yea and Nay ballots to consider the proposal as a voting winner + *) + promotion_supermajority : nat; +} + +type proposal_t = { + proposer : key_hash; + upvotes_voting_power : nat; +} + +(* 'pt - payload type. The value that bakers vote for *) +type 'pt proposals_t = ('pt, proposal_t) big_map + +type upvoters_upvotes_count_t = (key_hash, nat) big_map + +type 'pt upvoters_proposals_t = (key_hash * 'pt, unit) big_map + +type 'pt proposal_period_t = { + upvoters_upvotes_count : upvoters_upvotes_count_t; + upvoters_proposals : 'pt upvoters_proposals_t; + proposals : 'pt proposals_t; + max_upvotes_voting_power : nat option; + winner_candidate : 'pt option; + total_voting_power : nat; +} + +type 'pt promotion_period_t = { + voters : (key_hash, string) big_map; + yea_voting_power : nat; + nay_voting_power : nat; + pass_voting_power : nat; + total_voting_power : nat; + winner_candidate : 'pt; +} + +type 'pt period_t = + | Proposal of 'pt proposal_period_t + | Promotion of 'pt promotion_period_t + +type 'pt voting_context_t = { + period_index : nat; + period : 'pt period_t; +} + +type 'pt voting_winner_t = { + payload : 'pt; + trigger_history : (address, unit) big_map; +} + +type 'pt t = { + config : config_t; + voting_context : ('pt voting_context_t) option; + last_winner : ('pt voting_winner_t) option; + metadata : (string, bytes) big_map; +} diff --git a/etherlink/tezos_contracts/governance/contracts/common/utils/byte_utils.mligo b/etherlink/tezos_contracts/governance/contracts/common/utils/byte_utils.mligo new file mode 100644 index 000000000000..4fa095ff049c --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/utils/byte_utils.mligo @@ -0,0 +1,10 @@ +let pad_end + (source : bytes) + (target_length : nat) + : bytes = + let mut res = source in + let source_length = int (Bytes.length source) in + let _ = for _i = source_length upto target_length - 1 do + res := Bytes.concat res 0x00 + done in + res \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/common/utils/converters.mligo b/etherlink/tezos_contracts/governance/contracts/common/utils/converters.mligo new file mode 100644 index 000000000000..8b5a2c139c0e --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/utils/converters.mligo @@ -0,0 +1,78 @@ +#import "../errors.mligo" "Errors" + +[@inline] +let nat_to_bytes + (value : nat) + : bytes = + [%Michelson ({| { BYTES } |} : nat -> bytes)] value + +let bytes_to_nat + (value : bytes) + : nat = + [%Michelson ({| { NAT } |} : bytes -> nat)] value + +let nat_to_little_endian_bytes + (value : nat) + : bytes = + let bytes = nat_to_bytes value in + let mut res : bytes = 0x in + let bytes_length = Bytes.length bytes in + let _ = for i = 0 upto bytes_length - 1 do + let index : nat = Option.value_with_error Errors.index_not_nat (is_nat i) in + res := Bytes.concat (Bytes.sub index 1n bytes) res + done in + res + +let timestamp_to_nat + (value : timestamp) + : nat = + Option.value_with_error Errors.negative_timestamp (is_nat (value - (0 : timestamp))) + +let address_to_key_hash + (address : address) + : key_hash = + (* + NOTE: + This is a workaround solution. + Use the IS_IMPLICIT_ACCOUNT instruction of type address -> option key_hash when it will be available + (See: https://gitlab.com/tezos/tezos/-/merge_requests/12436) + Or pass address instead of key_hash to Tezos.voting_power instruction when it will be available + (See: https://gitlab.com/tezos/tezos/-/merge_requests/12425) + + Explanation of workaround + Bytes.pack for an address can return the following variants depending on address type + tz1NyAf1KeeFCCPPAZ9ard9YVshVGFibzVKa -> 0x050a0000001600002486eda3c7bbbe6be511b46d6deeb1594258a7fd + tz2VGBaXuS6rnaa5hpC92qkgadRJKdEbeGwc -> 0x050a000000160001e5c6d1f726796e98b2bad2a819a36f742b2fe25b + tz3WEJYwJ6pPwVbSL8FrSoAXRmFHHZTuEnMA -> 0x050a0000001600026c9b3ad59e0f8bdc2bd2011675825f9f547131da + tz4Jxn8MpRndqWUzkuZbQKmE3aNWJzYsSEso -> 0x050a0000001600036d39817a1e9a4a66bd28c2f2bb430a04b2d93ecf + KT1GzjQs7HLLVGG95GxURZXAPqEquAVyYD4c -> 0x050a00000016015c49311596d2b140b04401f2824b8ff4fe1256a200 + + the template for address in michelson bytes is 0xMMTT(LLx4)AA(DDx21) + MM - Michelson bytes mark (0x05) + TT - Michelson type (0x0a - address) + LLx4 - Data length (0x00000016 - 22 bytes) + AA - Address Type (0x00 - implicit, 0x01 - originated) + DDx21 - Address Data + + Bytes.pack for a key hash can return the following variants depending on address type + tz1NyAf1KeeFCCPPAZ9ard9YVshVGFibzVKa -> 0x050a00000015002486eda3c7bbbe6be511b46d6deeb1594258a7fd + tz2VGBaXuS6rnaa5hpC92qkgadRJKdEbeGwc -> 0x050a0000001501e5c6d1f726796e98b2bad2a819a36f742b2fe25b + tz3WEJYwJ6pPwVbSL8FrSoAXRmFHHZTuEnMA -> 0x050a00000015026c9b3ad59e0f8bdc2bd2011675825f9f547131da + tz4Jxn8MpRndqWUzkuZbQKmE3aNWJzYsSEso -> 0x050a00000015036d39817a1e9a4a66bd28c2f2bb430a04b2d93ecf + + the template for key hash in michelson bytes is 0xMMTT(LLx4)(DDx21) + MM - Michelson bytes mark (0x05) + TT - Michelson type (0x0a - address) + LLx4 - Data length (0x00000015 - 21 bytes) + DDx21 - Address Data + + so it's enough to check, that AA byte == 0x00, remove it, and update LL bytes to reflect that data length is 21 byte now + *) + let address_packed = Bytes.pack address in + let address_type = Bytes.sub 6n 1n address_packed in + let _ = assert_with_error (address_type = 0x00) Errors.not_implicit_address in + let length = 0x00000015 in + let key_hash_packed = Bytes.concats [(Bytes.sub 0n 2n address_packed); length; (Bytes.sub 7n 21n address_packed)] in + let key_hash = Option.value_with_error Errors.failed_to_cast_address_to_key_hash (Bytes.unpack key_hash_packed) in + let _ = assert_with_error (Tezos.address (Tezos.implicit_account key_hash) = address) Errors.key_hash_not_equal_to_source_address in + key_hash \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/common/utils/rlp.mligo b/etherlink/tezos_contracts/governance/contracts/common/utils/rlp.mligo new file mode 100644 index 000000000000..99294ca50098 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/utils/rlp.mligo @@ -0,0 +1,31 @@ +#import "converters.mligo" "Converters" +#import "../errors.mligo" "Errors" + +let encode_length + (length : nat) + (offset : nat) + : bytes = + if length < 56n + then Converters.nat_to_bytes (length + offset) + else + let length_bytes = Converters.nat_to_bytes length in + let length_of_length = Bytes.length length_bytes in + let _ = assert_with_error (length_of_length < 9n) Errors.input_too_long_for_rlp in + Bytes.concat (Converters.nat_to_bytes (length_of_length + offset + 55n)) length_bytes + +let encode_item + (value : bytes) + : bytes = + let length = Bytes.length value in + let prefix = if length = 1n && value < 0x80 + then 0x + else encode_length length 128n in + Bytes.concat prefix value + +let encode_list + (items : bytes list) + : bytes = + let list_body = Bytes.concats (List.map encode_item items) in + let list_length = Bytes.length list_body in + let prefix = encode_length list_length 192n in + Bytes.concat prefix list_body diff --git a/etherlink/tezos_contracts/governance/contracts/common/validation.mligo b/etherlink/tezos_contracts/governance/contracts/common/validation.mligo new file mode 100644 index 000000000000..509189e27586 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/validation.mligo @@ -0,0 +1,11 @@ +#import "errors.mligo" "Errors" + +let assert_no_tez_in_transaction + (_ : unit) + : unit = + assert_with_error (Tezos.get_amount () = 0mutez) Errors.tez_in_transaction_disallowed + +let assert_voting_power_positive + (voting_power : nat) + : unit = + assert_with_error (voting_power > 0n) Errors.no_voting_power diff --git a/etherlink/tezos_contracts/governance/contracts/common/views.mligo b/etherlink/tezos_contracts/governance/contracts/common/views.mligo new file mode 100644 index 000000000000..2e2d55f650ca --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/views.mligo @@ -0,0 +1,34 @@ +#import "storage.mligo" "Storage" +#import "events.mligo" "Events" +#import "voting.mligo" "Voting" + +type 'pt voting_state_t = { + period_index : nat; + period_type : Events.period_type_t; + remaining_blocks : nat; + finished_voting : 'pt Events.voting_finished_event_payload_t option; +} + + +let get_period_type + (type pt) + (period : pt Storage.period_t) + : Events.period_type_t = + match period with + | Proposal _ -> Proposal + | Promotion _ -> Promotion + + +[@inline] +let get_voting_state + (type pt) + (storage : pt Storage.t) + : pt voting_state_t = + let voting_state = Voting.get_voting_state storage in + let voting_context = voting_state.voting_context in + { + period_index = voting_context.period_index; + period_type = get_period_type voting_context.period; + remaining_blocks = Voting.get_current_period_remaining_blocks storage.config; + finished_voting = voting_state.finished_voting + } \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/common/voting.mligo b/etherlink/tezos_contracts/governance/contracts/common/voting.mligo new file mode 100644 index 000000000000..8a07d0e5e22a --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/common/voting.mligo @@ -0,0 +1,352 @@ +#import "storage.mligo" "Storage" +#import "errors.mligo" "Errors" +#import "events.mligo" "Events" +#import "constants.mligo" "Constants" + + +let get_period_index + (config : Storage.config_t) + : nat = + let blocks_after_start_int = Tezos.get_level () - config.started_at_level in + match is_nat blocks_after_start_int with + | Some blocks_after_start -> blocks_after_start / config.period_length + | None -> failwith Errors.current_level_less_than_start_level + + +[@inline] +let get_current_period_remaining_blocks + (config : Storage.config_t) + : nat = + let blocks_after_start_int = Tezos.get_level () - config.started_at_level in + let period_length = config.period_length in + match is_nat blocks_after_start_int with + | Some blocks_after_start -> + let remainder = blocks_after_start mod period_length in + Option.unopt (is_nat (period_length - remainder)) + | None -> failwith Errors.current_level_less_than_start_level + + +[@inline] +let get_proposal_winner + (type pt) + (proposal_period : pt Storage.proposal_period_t) + (config : Storage.config_t) + : pt option = + let winner_payload = proposal_period.winner_candidate in + let winner_upvotes_power = match proposal_period.max_upvotes_voting_power with + | Some value -> value + | None -> 0n in + let proposal_quorum_reached = winner_upvotes_power * config.scale >= proposal_period.total_voting_power * config.proposal_quorum in + if proposal_quorum_reached + then winner_payload + else None + + +[@inline] +let get_promotion_winner + (type pt) + (promotion_period : pt Storage.promotion_period_t) + (config : Storage.config_t) + : pt option = + let { total_voting_power; yea_voting_power; nay_voting_power; pass_voting_power; winner_candidate; voters = _} = promotion_period in + let quorum_reached = (yea_voting_power + nay_voting_power + pass_voting_power) * config.scale >= config.promotion_quorum * total_voting_power in + let yea_nay_voting_sum = yea_voting_power + nay_voting_power in + let supermajority_reached = yea_nay_voting_sum > 0n && yea_voting_power * config.scale >= config.promotion_supermajority * yea_nay_voting_sum in + if quorum_reached && supermajority_reached + then Some winner_candidate + else None + + +[@inline] +let init_new_proposal_voting_period + (type pt) + (period_index : nat) + : pt Storage.voting_context_t = + let proposal_period : pt Storage.proposal_period_t= { + proposals = Big_map.empty; + upvoters_upvotes_count = Big_map.empty; + upvoters_proposals = Big_map.empty; + max_upvotes_voting_power = None; + winner_candidate = None; + total_voting_power = Tezos.get_total_voting_power (); + } in + { + period_index = period_index; + period = Proposal proposal_period; + } + + +[@inline] +let init_new_promotion_voting_period + (type pt) + (period_index : nat) + (winner_candidate: pt) + : pt Storage.voting_context_t = + let promotion_period : pt Storage.promotion_period_t = { + voters = Big_map.empty; + yea_voting_power = 0n; + nay_voting_power = 0n; + pass_voting_power = 0n; + winner_candidate = winner_candidate; + total_voting_power = Tezos.get_total_voting_power (); + } in + { + period_index = period_index; + period = Promotion promotion_period; + } + + +type 'pt internal_voting_state_t = { + voting_context : 'pt Storage.voting_context_t; + finished_voting : 'pt Events.voting_finished_event_payload_t option; +} + +let init_new_voting_state + (type pt) + (voting_context : pt Storage.voting_context_t) + (config : Storage.config_t) + (period_index : nat) + : pt internal_voting_state_t = + match voting_context.period with + | Proposal proposal_period -> + (match get_proposal_winner proposal_period config with + | Some proposal_winner -> + let promotion_period_index = voting_context.period_index + 1n in + (if period_index = promotion_period_index + then + { + voting_context = init_new_promotion_voting_period period_index proposal_winner; + finished_voting = None; + } + else + { + voting_context = init_new_proposal_voting_period period_index; + finished_voting = Some (Events.create_voting_finished_event promotion_period_index Promotion None); + }) + | None -> + let at_least_one_proposal_was_submitted = Option.is_some proposal_period.max_upvotes_voting_power in + let finished_voting = if at_least_one_proposal_was_submitted + then Some (Events.create_voting_finished_event voting_context.period_index Proposal None) + else None in + { + voting_context = init_new_proposal_voting_period period_index; + finished_voting = finished_voting; + }) + | Promotion promotion_period -> + let promotion_winner = get_promotion_winner promotion_period config in + let finished_voting = Some (Events.create_voting_finished_event voting_context.period_index Promotion promotion_winner) in + { + voting_context = init_new_proposal_voting_period period_index; + finished_voting = finished_voting; + } + + + +type 'pt voting_state_t = { + voting_context : 'pt Storage.voting_context_t; + last_winner : 'pt Storage.voting_winner_t option; + finished_voting : 'pt Events.voting_finished_event_payload_t option; +} + +let get_voting_state + (type pt) + (storage : pt Storage.t) + : pt voting_state_t = + let period_index = get_period_index storage.config in + let voting_state = match storage.voting_context with + | None -> + { + voting_context = init_new_proposal_voting_period period_index; + finished_voting = None + } + | Some voting_context -> + if period_index = voting_context.period_index + then { voting_context = voting_context; finished_voting = None; } + else init_new_voting_state voting_context storage.config period_index in + let { voting_context; finished_voting } = voting_state in + { + voting_context = voting_context; + finished_voting = finished_voting; + last_winner = match finished_voting with + | Some event -> (match event.winner_proposal_payload with + | Some winner_payload -> + Some { + payload = winner_payload; + trigger_history = Big_map.empty; + } + | None -> storage.last_winner) + | None -> storage.last_winner + } + + +[@inline] +let get_proposal_period + (type pt) + (voting_context : pt Storage.voting_context_t) + : pt Storage.proposal_period_t = + match voting_context.period with + | Proposal proposal_period -> proposal_period + | Promotion _ -> failwith Errors.not_proposal_period + + +[@inline] +let get_promotion_period + (type pt) + (voting_context : pt Storage.voting_context_t) + : pt Storage.promotion_period_t = + match voting_context.period with + | Promotion promotion_period -> promotion_period + | Proposal _ -> failwith Errors.not_promotion_period + + +[@inline] +let assert_upvoting_allowed + (upvoters_upvotes_count : Storage.upvoters_upvotes_count_t) + (config : Storage.config_t) + (voter : key_hash) + : unit = + let upvotes_count = match Big_map.find_opt voter upvoters_upvotes_count with + | Some count -> count + | None -> 0n in + assert_with_error (upvotes_count < config.upvoting_limit) Errors.upvoting_limit_exceeded + + +[@inline] +let add_proposal_to_upvoter + (type pt) + (upvoter : key_hash) + (payload : pt) + (upvoters_proposals : pt Storage.upvoters_proposals_t) + : pt Storage.upvoters_proposals_t = + Big_map.add (upvoter, payload ) unit upvoters_proposals + + +[@inline] +let increment_upvotes_count + (upvoter : key_hash) + (upvoters_upvotes_count : Storage.upvoters_upvotes_count_t) + : Storage.upvoters_upvotes_count_t = + match Big_map.find_opt upvoter upvoters_upvotes_count with + | Some count -> Big_map.update upvoter (Some (count + 1n)) upvoters_upvotes_count + | None -> Big_map.add upvoter 1n upvoters_upvotes_count + + +[@inline] +let update_winner_candidate + (type pt) + (upvotes_voting_power : nat) + (payload : pt) + (proposal_period : pt Storage.proposal_period_t) + : pt Storage.proposal_period_t = + match proposal_period.max_upvotes_voting_power with + | Some max_upvotes_voting_power -> + if upvotes_voting_power > max_upvotes_voting_power + then + { + proposal_period with + max_upvotes_voting_power = Some upvotes_voting_power; + winner_candidate = Some payload + } + else if upvotes_voting_power = max_upvotes_voting_power + then + { + proposal_period with + winner_candidate = None + } + else + proposal_period + | None -> + { + proposal_period with + max_upvotes_voting_power = Some upvotes_voting_power; + winner_candidate = Some payload + } + + +[@inline] +let add_new_proposal_and_upvote + (type pt) + (payload : pt) + (proposer : key_hash) + (voting_power : nat) + (proposal_period : pt Storage.proposal_period_t) + (config : Storage.config_t) + : pt Storage.period_t = + let upvoters_upvotes_count = proposal_period.upvoters_upvotes_count in + let _ = assert_upvoting_allowed upvoters_upvotes_count config proposer in + let _ = assert_with_error (not Big_map.mem payload proposal_period.proposals) Errors.proposal_already_created in + let value = { + proposer = proposer; + upvotes_voting_power = voting_power; + } in + let updated_proposal_period = { + proposal_period with + upvoters_upvotes_count = increment_upvotes_count proposer upvoters_upvotes_count; + upvoters_proposals = add_proposal_to_upvoter proposer payload proposal_period.upvoters_proposals; + proposals = Big_map.add payload value proposal_period.proposals + } in + let proposal_period = update_winner_candidate voting_power payload updated_proposal_period in + Proposal proposal_period + + +[@inline] +let assert_proposal_not_already_upvoted + (type pt) + (upvoter : key_hash) + (payload : pt) + (upvoters_proposals : pt Storage.upvoters_proposals_t) + : unit = + assert_with_error (not Big_map.mem (upvoter, payload) upvoters_proposals) Errors.proposal_already_upvoted + + +[@inline] +let upvote_proposal + (type pt) + (payload : pt) + (upvoter : key_hash) + (voting_power : nat) + (proposal_period : pt Storage.proposal_period_t) + (config : Storage.config_t) + : pt Storage.period_t = + let upvoters_upvotes_count = proposal_period.upvoters_upvotes_count in + let _ = assert_upvoting_allowed upvoters_upvotes_count config upvoter in + let proposal = match Big_map.find_opt payload proposal_period.proposals with + | Some value -> value + | None -> failwith Errors.proposal_not_found in + let upvoters_proposals = proposal_period.upvoters_proposals in + let _ = assert_proposal_not_already_upvoted upvoter payload upvoters_proposals in + let upvotes_voting_power = proposal.upvotes_voting_power + voting_power in + let updated_proposal = { + proposal with + upvotes_voting_power = upvotes_voting_power + } in + let updated_proposal_period = { + proposal_period with + upvoters_upvotes_count = increment_upvotes_count upvoter upvoters_upvotes_count; + upvoters_proposals = add_proposal_to_upvoter upvoter payload upvoters_proposals; + proposals = Big_map.update payload (Some updated_proposal) proposal_period.proposals; + } in + let proposal_period = update_winner_candidate upvotes_voting_power payload updated_proposal_period in + Proposal proposal_period + +[@inline] +let vote_promotion + (type pt) + (vote : string) + (voter : key_hash) + (voting_power : nat) + (promotion_period : pt Storage.promotion_period_t) + : pt Storage.period_t = + let _ = assert_with_error (not Big_map.mem voter promotion_period.voters) Errors.promotion_already_voted in + let updated_promotion_period = if vote = Constants.yea + then { promotion_period with yea_voting_power = promotion_period.yea_voting_power + voting_power } + else if vote = Constants.nay + then { promotion_period with nay_voting_power = promotion_period.nay_voting_power + voting_power } + else if vote = Constants.pass + then { promotion_period with pass_voting_power = promotion_period.pass_voting_power + voting_power } + else failwith Errors.incorrect_vote_value in + let promotion_period = { + updated_promotion_period with + voters = Big_map.add voter vote promotion_period.voters + } in + Promotion promotion_period diff --git a/etherlink/tezos_contracts/governance/contracts/kernel_governance.mligo b/etherlink/tezos_contracts/governance/contracts/kernel_governance.mligo new file mode 100644 index 000000000000..8d1a6654db85 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/kernel_governance.mligo @@ -0,0 +1,59 @@ +#import "common/storage.mligo" "Storage" +#import "common/errors.mligo" "Errors" +#import "common/voting.mligo" "Voting" +#import "common/rollup.mligo" "Rollup" +#import "common/entrypoints.mligo" "Entrypoints" +#import "common/views.mligo" "Views" + +module KernelGovernance = struct + + type payload_t = bytes + type storage_t = payload_t Storage.t + type return_t = operation list * storage_t + + + [@entry] + let new_proposal + (kernel_root_hash : payload_t) + (storage : storage_t) + : return_t = + let _ = Rollup.assert_kernel_root_hash_has_correct_length kernel_root_hash in + Entrypoints.new_proposal kernel_root_hash storage + + + [@entry] + let upvote_proposal + (kernel_root_hash : payload_t) + (storage : storage_t) + : return_t = + Entrypoints.upvote_proposal kernel_root_hash storage + + + [@entry] + let vote + (vote : string) + (storage : storage_t) + : return_t = + Entrypoints.vote vote storage + + + [@entry] + let trigger_kernel_upgrade + (rollup_address : address) + (storage : storage_t) + : return_t = + let pack_payload = fun + (payload : payload_t) + : bytes -> + let activation_timestamp = Rollup.get_activation_timestamp storage.config.adoption_period_sec in + Rollup.get_kernel_upgrade_payload payload activation_timestamp in + Entrypoints.trigger_rollup_upgrade rollup_address storage pack_payload + + + [@view] + let get_voting_state + (_ : unit) + (storage : storage_t) + : payload_t Views.voting_state_t = + Views.get_voting_state storage +end \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/sequencer_governance.mligo b/etherlink/tezos_contracts/governance/contracts/sequencer_governance.mligo new file mode 100644 index 000000000000..2cfcfc153264 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/sequencer_governance.mligo @@ -0,0 +1,62 @@ +#import "common/storage.mligo" "Storage" +#import "common/errors.mligo" "Errors" +#import "common/voting.mligo" "Voting" +#import "common/rollup.mligo" "Rollup" +#import "common/entrypoints.mligo" "Entrypoints" +#import "common/views.mligo" "Views" + +module SequencerCommitteeGovernance = struct + + type payload_t = { + sequencer_pk : string; + pool_address : bytes; + } + type storage_t = payload_t Storage.t + type return_t = operation list * storage_t + + [@entry] + let new_proposal + (payload : payload_t) + (storage : storage_t) + : return_t = + let { sequencer_pk; pool_address; } = payload in + let _ = Rollup.assert_sequencer_upgrade_payload_is_correct sequencer_pk pool_address in + Entrypoints.new_proposal payload storage + + + [@entry] + let upvote_proposal + (payload : payload_t) + (storage : storage_t) + : return_t = + Entrypoints.upvote_proposal payload storage + + + [@entry] + let vote + (vote : string) + (storage : storage_t) + : return_t = + Entrypoints.vote vote storage + + + [@entry] + let trigger_committee_upgrade + (rollup_address : address) + (storage : storage_t) + : return_t = + let pack_payload = fun + (payload : payload_t) + : bytes -> + let activation_timestamp = Rollup.get_activation_timestamp storage.config.adoption_period_sec in + Rollup.get_sequencer_upgrade_payload payload.sequencer_pk payload.pool_address activation_timestamp in + Entrypoints.trigger_rollup_upgrade rollup_address storage pack_payload + + + [@view] + let get_voting_state + (_ : unit) + (storage : storage_t) + : payload_t Views.voting_state_t = + Views.get_voting_state storage +end \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/test/internal_test_proxy.mligo b/etherlink/tezos_contracts/governance/contracts/test/internal_test_proxy.mligo new file mode 100644 index 000000000000..bae06f6af226 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/test/internal_test_proxy.mligo @@ -0,0 +1,56 @@ +#import "../common/rollup.mligo" "Rollup" +#import "../common/utils/converters.mligo" "Converters" + +module InternalTestProxy = struct + (* The contract is used to test common internal functions *) + + type storage_t = unit + type result_t = operation list * storage_t + + + [@entry] + let default + (_ : unit) + (storage : storage_t) + : result_t = + [], storage + + + type kernel_upgrade_payload_params_t = { + kernel_root_hash : bytes; + activation_timestamp : timestamp; + } + + [@view] + let get_kernel_upgrade_payload + (params: kernel_upgrade_payload_params_t) + (_ : storage_t) + : bytes = + let { kernel_root_hash; activation_timestamp } = params in + let _ = Rollup.assert_kernel_root_hash_has_correct_length kernel_root_hash in + Rollup.get_kernel_upgrade_payload kernel_root_hash activation_timestamp + + + type sequencer_upgrade_payload_params_t = { + sequencer_pk : string; + pool_address : bytes; + activation_timestamp : timestamp; + } + + [@view] + let get_sequencer_upgrade_payload + (params: sequencer_upgrade_payload_params_t) + (_ : storage_t) + : bytes = + let { sequencer_pk; pool_address; activation_timestamp } = params in + let _ = Rollup.assert_sequencer_upgrade_payload_is_correct sequencer_pk pool_address in + Rollup.get_sequencer_upgrade_payload sequencer_pk pool_address activation_timestamp + + + [@view] + let address_to_key_hash + (address : address) + (_ : storage_t) + : key_hash = + Converters.address_to_key_hash address +end \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/contracts/test/rollup_mock.mligo b/etherlink/tezos_contracts/governance/contracts/test/rollup_mock.mligo new file mode 100644 index 000000000000..55f9bde3ff89 --- /dev/null +++ b/etherlink/tezos_contracts/governance/contracts/test/rollup_mock.mligo @@ -0,0 +1,14 @@ +#import "../common/rollup.mligo" "Rollup" + +module RollupMock = struct + + type storage_t = bytes + type return_t = operation list * storage_t + + [@entry] + let rollup + (rollup_entry : Rollup.t) + (_ : storage_t) + : return_t = + [], Rollup.decode_upgrade_payload rollup_entry +end \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/example.env b/etherlink/tezos_contracts/governance/example.env new file mode 100644 index 000000000000..7889065fb98e --- /dev/null +++ b/etherlink/tezos_contracts/governance/example.env @@ -0,0 +1,2 @@ +PRIVATE_KEY= +RPC_URL= \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/poetry.lock b/etherlink/tezos_contracts/governance/poetry.lock new file mode 100644 index 000000000000..ffdea98267dc --- /dev/null +++ b/etherlink/tezos_contracts/governance/poetry.lock @@ -0,0 +1,2782 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. + +[[package]] +name = "anyio" +version = "4.2.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, + {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} + +[package.extras] +doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] +trio = ["trio (>=0.23)"] + +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = "*" +files = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] + +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + +[[package]] +name = "arrow" +version = "1.3.0" +description = "Better dates & times for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80"}, + {file = "arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85"}, +] + +[package.dependencies] +python-dateutil = ">=2.7.0" +types-python-dateutil = ">=2.8.10" + +[package.extras] +doc = ["doc8", "sphinx (>=7.0.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx_rtd_theme (>=1.3.0)"] +test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "pytz (==2021.1)", "simplejson (==3.*)"] + +[[package]] +name = "asttokens" +version = "2.4.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "base58" +version = "2.1.1" +description = "Base58 and Base58Check implementation." +optional = false +python-versions = ">=3.5" +files = [ + {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, + {file = "base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c"}, +] + +[package.extras] +tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bleach" +version = "6.1.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.8" +files = [ + {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, + {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.3)"] + +[[package]] +name = "cached-property" +version = "1.5.2" +description = "A decorator for caching properties in classes." +optional = false +python-versions = "*" +files = [ + {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, + {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, +] + +[[package]] +name = "cattrs" +version = "23.2.3" +description = "Composable complex class support for attrs and dataclasses." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cattrs-23.2.3-py3-none-any.whl", hash = "sha256:0341994d94971052e9ee70662542699a3162ea1e0c62f7ce1b4a57f563685108"}, + {file = "cattrs-23.2.3.tar.gz", hash = "sha256:a934090d95abaa9e911dac357e3a8699e0b4b14f8529bcc7d2b1ad9d51672b9f"}, +] + +[package.dependencies] +attrs = ">=23.1.0" +exceptiongroup = {version = ">=1.1.1", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.1.0,<4.6.3 || >4.6.3", markers = "python_version < \"3.11\""} + +[package.extras] +bson = ["pymongo (>=4.4.0)"] +cbor2 = ["cbor2 (>=5.4.6)"] +msgpack = ["msgpack (>=1.0.5)"] +orjson = ["orjson (>=3.9.2)"] +pyyaml = ["pyyaml (>=6.0)"] +tomlkit = ["tomlkit (>=0.11.8)"] +ujson = ["ujson (>=5.7.0)"] + +[[package]] +name = "certifi" +version = "2023.11.17" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "comm" +version = "0.2.1" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.8" +files = [ + {file = "comm-0.2.1-py3-none-any.whl", hash = "sha256:87928485c0dfc0e7976fd89fc1e187023cf587e7c353e4a9b417555b44adf021"}, + {file = "comm-0.2.1.tar.gz", hash = "sha256:0bc91edae1344d39d3661dcbc36937181fdaddb304790458f8b044dbc064b89a"}, +] + +[package.dependencies] +traitlets = ">=4" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "cryptography" +version = "41.0.7" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, + {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, + {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, + {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, + {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, + {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, + {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, + {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, + {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, + {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "cytoolz" +version = "0.12.2" +description = "Cython implementation of Toolz: High performance functional utilities" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cytoolz-0.12.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bff49986c9bae127928a2f9fd6313146a342bfae8292f63e562f872bd01b871"}, + {file = "cytoolz-0.12.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:908c13f305d34322e11b796de358edaeea47dd2d115c33ca22909c5e8fb036fd"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:735147aa41b8eeb104da186864b55e2a6623c758000081d19c93d759cd9523e3"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d352d4de060604e605abdc5c8a5d0429d5f156cb9866609065d3003454d4cea"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89247ac220031a4f9f689688bcee42b38fd770d4cce294e5d914afc53b630abe"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9070ae35c410d644e6df98a8f69f3ed2807e657d0df2a26b2643127cbf6944a5"}, + {file = "cytoolz-0.12.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:843500cd3e4884b92fd4037912bc42d5f047108d2c986d36352e880196d465b0"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6a93644d7996fd696ab7f1f466cd75d718d0a00d5c8118b9fe8c64231dc1f85e"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:96796594c770bc6587376e74ddc7d9c982d68f47116bb69d90873db5e0ea88b6"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:48425107fbb1af3f0f2410c004f16be10ffc9374358e5600b57fa543f46f8def"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:cde6dbb788a4cbc4a80a72aa96386ba4c2b17bdfff3ace0709799adbe16d6476"}, + {file = "cytoolz-0.12.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68ae7091cc73a752f0b938f15bb193de80ca5edf5ae2ea6360d93d3e9228357b"}, + {file = "cytoolz-0.12.2-cp310-cp310-win32.whl", hash = "sha256:997b7e0960072f6bb445402da162f964ea67387b9f18bda2361edcc026e13597"}, + {file = "cytoolz-0.12.2-cp310-cp310-win_amd64.whl", hash = "sha256:663911786dcde3e4a5d88215c722c531c7548903dc07d418418c0d1c768072c0"}, + {file = "cytoolz-0.12.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a7d8b869ded171f6cdf584fc2fc6ae03b30a0e1e37a9daf213a59857a62ed90"}, + {file = "cytoolz-0.12.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9b28787eaf2174e68f0acb3c66f9c6b98bdfeb0930c0d0b08e1941c7aedc8d27"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00547da587f124b32b072ce52dd5e4b37cf199fedcea902e33c67548523e4678"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:275d53fd769df2102d6c9fc98e553bd8a9a38926f54d6b20cf29f0dd00bf3b75"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5556acde785a61d4cf8b8534ae109b023cbd2f9df65ee2afbe070be47c410f8c"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b41a85b9b9a2530b72b0d3d10e383fc3c2647ae88169d557d5e216f881860318"}, + {file = "cytoolz-0.12.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673d6e9e3aa86949343b46ac2b7be266c36e07ce77fa1d40f349e6987a814d6e"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81e6a9a8fda78a2f4901d2915b25bf620f372997ca1f20a14f7cefef5ad6f6f4"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fa44215bc31675a6380cd896dadb7f2054a7b94cfb87e53e52af844c65406a54"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a08b4346350660799d81d4016e748bcb134a9083301d41f9618f64a6077f89f2"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2fb740482794a72e2e5fec58e4d9b00dcd5a60a8cef68431ff12f2ba0e0d9a7e"}, + {file = "cytoolz-0.12.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9007bb1290c79402be6b84bcf9e7a622a073859d61fcee146dc7bc47afe328f3"}, + {file = "cytoolz-0.12.2-cp311-cp311-win32.whl", hash = "sha256:a973f5286758f76824ecf19ae1999f6697371a9121c8f163295d181d19a819d7"}, + {file = "cytoolz-0.12.2-cp311-cp311-win_amd64.whl", hash = "sha256:1ce324d1b413636ea5ee929f79637821f13c9e55e9588f38228947294944d2ed"}, + {file = "cytoolz-0.12.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c08094b9e5d1b6dfb0845a0253cc2655ca64ce70d15162dfdb102e28c8993493"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baf020f4b708f800b353259cd7575e335a79f1ac912d9dda55b2aa0bf3616e42"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4416ee86a87180b6a28e7483102c92debc077bec59c67eda8cc63fc52a218ac0"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6ee222671eed5c5b16a5ad2aea07f0a715b8b199ee534834bc1dd2798f1ade7"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad92e37be0b106fdbc575a3a669b43b364a5ef334495c9764de4c2d7541f7a99"}, + {file = "cytoolz-0.12.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460c05238fbfe6d848141669d17a751a46c923f9f0c9fd8a3a462ab737623a44"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:9e5075e30be626ef0f9bedf7a15f55ed4d7209e832bc314fdc232dbd61dcbf44"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:03b58f843f09e73414e82e57f7e8d88f087eaabf8f276b866a40661161da6c51"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:5e4e612b7ecc9596e7c859cd9e0cd085e6d0c576b4f0d917299595eb56bf9c05"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:08a0e03f287e45eb694998bb55ac1643372199c659affa8319dfbbdec7f7fb3c"}, + {file = "cytoolz-0.12.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b029bdd5a8b6c9a7c0e8fdbe4fc25ffaa2e09b77f6f3462314696e3a20511829"}, + {file = "cytoolz-0.12.2-cp36-cp36m-win32.whl", hash = "sha256:18580d060fa637ff01541640ecde6de832a248df02b8fb57e6dd578f189d62c7"}, + {file = "cytoolz-0.12.2-cp36-cp36m-win_amd64.whl", hash = "sha256:97cf514a9f3426228d8daf880f56488330e4b2948a6d183a106921217850d9eb"}, + {file = "cytoolz-0.12.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:18a0f838677f9510aef0330c0096778dd6406d21d4ff9504bf79d85235a18460"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb081b2b02bf4405c804de1ece6f904916838ab0e057f1446e4ac12fac827960"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:57233e1600560ceb719bed759dc78393edd541b9a3e7fefc3079abd83c26a6ea"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0295289c4510efa41174850e75bc9188f82b72b1b54d0ea57d1781729c2924d5"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a92aab8dd1d427ac9bc7480cfd3481dbab0ef024558f2f5a47de672d8a5ffaa"}, + {file = "cytoolz-0.12.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51d3495235af09f21aa92a7cdd51504bda640b108b6be834448b774f52852c09"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9c690b359f503f18bf1c46a6456370e4f6f3fc4320b8774ae69c4f85ecc6c94"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:481e3129a76ea01adcc0e7097ccb8dbddab1cfc40b6f0e32c670153512957c0f"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:55e94124af9c8fbb1df54195cc092688fdad0765641b738970b6f1d5ea72e776"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:5616d386dfbfba7c39e9418ba668c734f6ceaacc0130877e8a100cad11e6838b"}, + {file = "cytoolz-0.12.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:732d08228fa8d366fec284f7032cc868d28a99fa81fc71e3adf7ecedbcf33a0f"}, + {file = "cytoolz-0.12.2-cp37-cp37m-win32.whl", hash = "sha256:f039c5373f7b314b151432c73219216857b19ab9cb834f0eb5d880f74fc7851c"}, + {file = "cytoolz-0.12.2-cp37-cp37m-win_amd64.whl", hash = "sha256:246368e983eaee9851b15d7755f82030eab4aa82098d2a34f6bef9c689d33fcc"}, + {file = "cytoolz-0.12.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:81074edf3c74bc9bd250d223408a5df0ff745d1f7a462597536cd26b9390e2d6"}, + {file = "cytoolz-0.12.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:960d85ebaa974ecea4e71fa56d098378fa51fd670ee744614cbb95bf95e28fc7"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c8d0dff4865da54ae825d43e1721925721b19f3b9aca8e730c2ce73dee2c630"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a9d12436fd64937bd2c9609605f527af7f1a8db6e6637639b44121c0fe715d6"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd461e402e24929d866f05061d2f8337e3a8456e75e21b72c125abff2477c7f7"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0568d4da0a9ee9f9f5ab318f6501557f1cfe26d18c96c8e0dac7332ae04c6717"}, + {file = "cytoolz-0.12.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:101b5bd32badfc8b1f9c7be04ba3ae04fb47f9c8736590666ce9449bff76e0b1"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8bb624dbaef4661f5e3625c1e39ad98ecceef281d1380e2774d8084ad0810275"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3e993804e6b04113d61fdb9541b6df2f096ec265a506dad7437517470919c90f"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ab911033e5937fc221a2c165acce7f66ae5ac9d3e54bec56f3c9c197a96be574"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6de6a4bdfaee382c2de2a3580b3ae76fce6105da202bbd835e5efbeae6a9c6e"}, + {file = "cytoolz-0.12.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9480b4b327be83c4d29cb88bcace761b11f5e30198ffe2287889455c6819e934"}, + {file = "cytoolz-0.12.2-cp38-cp38-win32.whl", hash = "sha256:4180b2785d1278e6abb36a72ac97c92432db53fa2df00ee943d2c15a33627d31"}, + {file = "cytoolz-0.12.2-cp38-cp38-win_amd64.whl", hash = "sha256:d0086ba8d41d73647b13087a3ca9c020f6bfec338335037e8f5172b4c7c8dce5"}, + {file = "cytoolz-0.12.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d29988bde28a90a00367edcf92afa1a2f7ecf43ea3ae383291b7da6d380ccc25"}, + {file = "cytoolz-0.12.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:24c0d71e9ac91f4466b1bd280f7de43aa4d94682daaf34d85d867a9b479b87cc"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa436abd4ac9ca71859baf5794614e6ec8fa27362f0162baedcc059048da55f7"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45c7b4eac7571707269ebc2893facdf87e359cd5c7cfbfa9e6bd8b33fb1079c5"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:294d24edc747ef4e1b28e54365f713becb844e7898113fafbe3e9165dc44aeea"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:478051e5ef8278b2429864c8d148efcebdc2be948a61c9a44757cd8c816c98f5"}, + {file = "cytoolz-0.12.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14108cafb140dd68fdda610c2bbc6a37bf052cd48cfebf487ed44145f7a2b67f"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fef7b602ccf8a3c77ab483479ccd7a952a8c5bb1c263156671ba7aaa24d1035"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9bf51354e15520715f068853e6ab8190e77139940e8b8b633bdb587956a08fb0"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:388f840fd911d61a96e9e595eaf003f9dc39e847c9060b8e623ab29e556f009b"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:a67f75cc51a2dc7229a8ac84291e4d61dc5abfc8940befcf37a2836d95873340"}, + {file = "cytoolz-0.12.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63b31345e20afda2ae30dba246955517a4264464d75e071fc2fa641e88c763ec"}, + {file = "cytoolz-0.12.2-cp39-cp39-win32.whl", hash = "sha256:f6e86ac2b45a95f75c6f744147483e0fc9697ce7dfe1726083324c236f873f8b"}, + {file = "cytoolz-0.12.2-cp39-cp39-win_amd64.whl", hash = "sha256:5998f81bf6a2b28a802521efe14d9fc119f74b64e87b62ad1b0e7c3d8366d0c7"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:593e89e2518eaf81e96edcc9ef2c5fca666e8fc922b03d5cb7a7b8964dbee336"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff451d614ca1d4227db0ffa627fb51df71968cf0d9baf0210528dad10fdbc3ab"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ad9ea4a50d2948738351790047d45f2b1a023facc01bf0361988109b177e8b2f"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbe038bb78d599b5a29d09c438905defaa615a522bc7e12f8016823179439497"}, + {file = "cytoolz-0.12.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d494befe648c13c98c0f3d56d05489c839c9228a32f58e9777305deb6c2c1cee"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c26805b6c8dc8565ed91045c44040bf6c0fe5cb5b390c78cd1d9400d08a6cd39"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4e32badb2ccf1773e1e74020b7e3b8caf9e92f842c6be7d14888ecdefc2c6c"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce7889dc3701826d519ede93cdff11940fb5567dbdc165dce0e78047eece02b7"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c820608e7077416f766b148d75e158e454881961881b657cff808529d261dd24"}, + {file = "cytoolz-0.12.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:698da4fa1f7baeea0607738cb1f9877ed1ba50342b29891b0223221679d6f729"}, + {file = "cytoolz-0.12.2.tar.gz", hash = "sha256:31d4b0455d72d914645f803d917daf4f314d115c70de0578d3820deb8b101f66"}, +] + +[package.dependencies] +toolz = ">=0.8.0" + +[package.extras] +cython = ["cython"] + +[[package]] +name = "debugpy" +version = "1.8.0" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "debugpy-1.8.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7fb95ca78f7ac43393cd0e0f2b6deda438ec7c5e47fa5d38553340897d2fbdfb"}, + {file = "debugpy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9ab7df0b9a42ed9c878afd3eaaff471fce3fa73df96022e1f5c9f8f8c87ada"}, + {file = "debugpy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:a8b7a2fd27cd9f3553ac112f356ad4ca93338feadd8910277aff71ab24d8775f"}, + {file = "debugpy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5d9de202f5d42e62f932507ee8b21e30d49aae7e46d5b1dd5c908db1d7068637"}, + {file = "debugpy-1.8.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:ef54404365fae8d45cf450d0544ee40cefbcb9cb85ea7afe89a963c27028261e"}, + {file = "debugpy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60009b132c91951354f54363f8ebdf7457aeb150e84abba5ae251b8e9f29a8a6"}, + {file = "debugpy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:8cd0197141eb9e8a4566794550cfdcdb8b3db0818bdf8c49a8e8f8053e56e38b"}, + {file = "debugpy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a64093656c4c64dc6a438e11d59369875d200bd5abb8f9b26c1f5f723622e153"}, + {file = "debugpy-1.8.0-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:b05a6b503ed520ad58c8dc682749113d2fd9f41ffd45daec16e558ca884008cd"}, + {file = "debugpy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c6fb41c98ec51dd010d7ed650accfd07a87fe5e93eca9d5f584d0578f28f35f"}, + {file = "debugpy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:46ab6780159eeabb43c1495d9c84cf85d62975e48b6ec21ee10c95767c0590aa"}, + {file = "debugpy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:bdc5ef99d14b9c0fcb35351b4fbfc06ac0ee576aeab6b2511702e5a648a2e595"}, + {file = "debugpy-1.8.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:61eab4a4c8b6125d41a34bad4e5fe3d2cc145caecd63c3fe953be4cc53e65bf8"}, + {file = "debugpy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:125b9a637e013f9faac0a3d6a82bd17c8b5d2c875fb6b7e2772c5aba6d082332"}, + {file = "debugpy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:57161629133113c97b387382045649a2b985a348f0c9366e22217c87b68b73c6"}, + {file = "debugpy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:e3412f9faa9ade82aa64a50b602544efcba848c91384e9f93497a458767e6926"}, + {file = "debugpy-1.8.0-py2.py3-none-any.whl", hash = "sha256:9c9b0ac1ce2a42888199df1a1906e45e6f3c9555497643a85e0bf2406e3ffbc4"}, + {file = "debugpy-1.8.0.zip", hash = "sha256:12af2c55b419521e33d5fb21bd022df0b5eb267c3e178f1d374a63a2a6bdccd0"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "deprecation" +version = "2.1.0" +description = "A library to handle automated deprecations" +optional = false +python-versions = "*" +files = [ + {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, + {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, +] + +[package.dependencies] +packaging = "*" + +[[package]] +name = "docker" +version = "6.1.3" +description = "A Python library for the Docker Engine API." +optional = false +python-versions = ">=3.7" +files = [ + {file = "docker-6.1.3-py3-none-any.whl", hash = "sha256:aecd2277b8bf8e506e484f6ab7aec39abe0038e29fa4a6d3ba86c3fe01844ed9"}, + {file = "docker-6.1.3.tar.gz", hash = "sha256:aa6d17830045ba5ef0168d5eaa34d37beeb113948c413affe1d5991fc11f9a20"}, +] + +[package.dependencies] +packaging = ">=14.0" +pywin32 = {version = ">=304", markers = "sys_platform == \"win32\""} +requests = ">=2.26.0" +urllib3 = ">=1.26.0" +websocket-client = ">=0.32.0" + +[package.extras] +ssh = ["paramiko (>=2.4.3)"] + +[[package]] +name = "entrypoints" +version = "0.4" +description = "Discover and load entry points from installed packages." +optional = false +python-versions = ">=3.6" +files = [ + {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"}, + {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"}, +] + +[[package]] +name = "eth-hash" +version = "0.6.0" +description = "eth-hash: The Ethereum hashing function, keccak256, sometimes (erroneously) called sha3" +optional = false +python-versions = ">=3.8, <4" +files = [ + {file = "eth-hash-0.6.0.tar.gz", hash = "sha256:ae72889e60db6acbb3872c288cfa02ed157f4c27630fcd7f9c8442302c31e478"}, + {file = "eth_hash-0.6.0-py3-none-any.whl", hash = "sha256:9f8daaa345764f8871dc461855049ac54ae4291d780279bce6fce7f24e3f17d3"}, +] + +[package.extras] +dev = ["build (>=0.9.0)", "bumpversion (>=0.5.3)", "ipython", "pre-commit (>=3.4.0)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "wheel"] +docs = ["sphinx (>=6.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +pycryptodome = ["pycryptodome (>=3.6.6,<4)"] +pysha3 = ["pysha3 (>=1.0.0,<2.0.0)", "safe-pysha3 (>=1.0.0)"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-typing" +version = "3.5.2" +description = "eth-typing: Common type annotations for ethereum python packages" +optional = false +python-versions = ">=3.7.2, <4" +files = [ + {file = "eth-typing-3.5.2.tar.gz", hash = "sha256:22bf051ddfaa35ff827c30090de167e5c5b8cc6d343f7f35c9b1c7553f6ab64d"}, + {file = "eth_typing-3.5.2-py3-none-any.whl", hash = "sha256:1842e628fb1ffa929b94f89a9d33caafbeb9978dc96abb6036a12bc91f1c624b"}, +] + +[package.dependencies] +typing-extensions = ">=4.0.1" + +[package.extras] +dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "ipython", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "types-setuptools", "wheel"] +docs = ["sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +lint = ["black (>=23)", "flake8 (==6.0.0)", "flake8-bugbear (==23.3.23)", "isort (>=5.10.1)", "mypy (==0.971)", "pydocstyle (>=6.0.0)", "types-setuptools"] +test = ["pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)"] + +[[package]] +name = "eth-utils" +version = "2.3.1" +description = "eth-utils: Common utility functions for python code that interacts with Ethereum" +optional = false +python-versions = ">=3.7,<4" +files = [ + {file = "eth-utils-2.3.1.tar.gz", hash = "sha256:56a969b0536d4969dcb27e580521de35abf2dbed8b1bf072b5c80770c4324e27"}, + {file = "eth_utils-2.3.1-py3-none-any.whl", hash = "sha256:614eedc5ffcaf4e6708ca39e23b12bd69526a312068c1170c773bd1307d13972"}, +] + +[package.dependencies] +cytoolz = {version = ">=0.10.1", markers = "implementation_name == \"cpython\""} +eth-hash = ">=0.3.1" +eth-typing = ">=3.0.0" +toolz = {version = ">0.8.2", markers = "implementation_name == \"pypy\""} + +[package.extras] +dev = ["black (>=23)", "build (>=0.9.0)", "bumpversion (>=0.5.3)", "eth-hash[pycryptodome]", "flake8 (==3.8.3)", "hypothesis (>=4.43.0)", "ipython", "isort (>=5.11.0)", "mypy (==0.971)", "pydocstyle (>=5.0.0)", "pytest (>=7.0.0)", "pytest-watch (>=4.1.0)", "pytest-xdist (>=2.4.0)", "sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)", "tox (>=4.0.0)", "twine", "types-setuptools", "wheel"] +docs = ["sphinx (>=5.0.0)", "sphinx-rtd-theme (>=1.0.0)", "towncrier (>=21,<22)"] +lint = ["black (>=23)", "flake8 (==3.8.3)", "isort (>=5.11.0)", "mypy (==0.971)", "pydocstyle (>=5.0.0)", "types-setuptools"] +test = ["hypothesis (>=4.43.0)", "mypy (==0.971)", "pytest (>=7.0.0)", "pytest-xdist (>=2.4.0)", "types-setuptools"] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "executing" +version = "2.0.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.5" +files = [ + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + +[[package]] +name = "fastecdsa" +version = "2.3.0" +description = "Fast elliptic curve digital signatures" +optional = false +python-versions = ">=3.7" +files = [ + {file = "fastecdsa-2.3.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0147804e6bf4915e83064f17a4bcc518d986dab87cba3609409e9f56b8d56772"}, + {file = "fastecdsa-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:c72f8f13160798b431c8a772e4e4bce39adf6faeea80fbf75f88010d0b304aa1"}, + {file = "fastecdsa-2.3.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:b943a1ad3e1e306f0df422b198f544d029a70f19581e5b56a36ddfbe6302a33d"}, + {file = "fastecdsa-2.3.0-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:82985e09b299ba400f1a21f2872dcc8e659bc127286f026d01b3540853298f9c"}, + {file = "fastecdsa-2.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8011db68e65b747b11ffa9575dc5bc6ad6d02aa971054e952e261694f705845a"}, + {file = "fastecdsa-2.3.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:fd61e461389a4fc1e965a1bbd5efb77588a0ebae2328aecdf011a5e9d439ce66"}, + {file = "fastecdsa-2.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b0a4637e99cc22b5107d32ae001c2e36a5821c7a50ac001b806d64c157bf62c0"}, + {file = "fastecdsa-2.3.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:7b91663b36137454299d7487a7a1b4a345120bd098ab5f7d7b0a02b50d6c9706"}, + {file = "fastecdsa-2.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:e45be9bcd063362576f93b344e032c743572c2a9ca7426eea3e4035ba21b1654"}, + {file = "fastecdsa-2.3.0.tar.gz", hash = "sha256:6c59aba650862a59f601ff7f66cd6712f4798ae68907c953d58417a5887103de"}, +] + +[[package]] +name = "fastjsonschema" +version = "2.19.1" +description = "Fastest Python implementation of JSON schema" +optional = false +python-versions = "*" +files = [ + {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, + {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + +[[package]] +name = "fqdn" +version = "1.5.1" +description = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers" +optional = false +python-versions = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4" +files = [ + {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"}, + {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"}, +] + +[[package]] +name = "idna" +version = "3.6" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "ipykernel" +version = "6.29.0" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.29.0-py3-none-any.whl", hash = "sha256:076663ca68492576f051e4af7720d33f34383e655f2be0d544c8b1c9de915b2f"}, + {file = "ipykernel-6.29.0.tar.gz", hash = "sha256:b5dd3013cab7b330df712891c96cd1ab868c27a7159e606f762015e9bf8ceb3f"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=24" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (==0.23.2)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.20.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +files = [ + {file = "ipython-8.20.0-py3-none-any.whl", hash = "sha256:bc9716aad6f29f36c449e30821c9dd0c1c1a7b59ddcc26931685b87b4c569619"}, + {file = "ipython-8.20.0.tar.gz", hash = "sha256:2f21bd3fc1d51550c89ee3944ae04bbc7bc79e129ea0937da6e6c68bfdbf117a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +prompt-toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" + +[package.extras] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.23)", "pandas", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath", "trio"] + +[[package]] +name = "ipython-genutils" +version = "0.2.0" +description = "Vestigial utilities from IPython" +optional = false +python-versions = "*" +files = [ + {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, + {file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"}, +] + +[[package]] +name = "isoduration" +version = "20.11.0" +description = "Operations with ISO 8601 durations" +optional = false +python-versions = ">=3.7" +files = [ + {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"}, + {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"}, +] + +[package.dependencies] +arrow = ">=0.15.0" + +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jinja2" +version = "3.1.3" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, + {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsonpointer" +version = "2.4" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"}, + {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"}, +] + +[[package]] +name = "jsonschema" +version = "4.21.1" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.21.1-py3-none-any.whl", hash = "sha256:7996507afae316306f9e2290407761157c6f78002dcf7419acb99822143d1c6f"}, + {file = "jsonschema-4.21.1.tar.gz", hash = "sha256:85727c00279f5fa6bedbe6238d2aa6403bedd8b4864ab11207d07df3cc1b2ee5"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +fqdn = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +idna = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +isoduration = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +jsonpointer = {version = ">1.13", optional = true, markers = "extra == \"format-nongpl\""} +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rfc3339-validator = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +rfc3986-validator = {version = ">0.1.0", optional = true, markers = "extra == \"format-nongpl\""} +rpds-py = ">=0.7.1" +uri-template = {version = "*", optional = true, markers = "extra == \"format-nongpl\""} +webcolors = {version = ">=1.11", optional = true, markers = "extra == \"format-nongpl\""} + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "jupyter-client" +version = "7.4.9" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jupyter_client-7.4.9-py3-none-any.whl", hash = "sha256:214668aaea208195f4c13d28eb272ba79f945fc0cf3f11c7092c20b2ca1980e7"}, + {file = "jupyter_client-7.4.9.tar.gz", hash = "sha256:52be28e04171f07aed8f20e1616a5a552ab9fee9cbbe6c1896ae170c3880d392"}, +] + +[package.dependencies] +entrypoints = "*" +jupyter-core = ">=4.9.2" +nest-asyncio = ">=1.5.4" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = "*" + +[package.extras] +doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyter-core" +version = "5.7.1" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.7.1-py3-none-any.whl", hash = "sha256:c65c82126453a723a2804aa52409930434598fd9d35091d63dfb919d2b765bb7"}, + {file = "jupyter_core-5.7.1.tar.gz", hash = "sha256:de61a9d7fc71240f688b2fb5ab659fbb56979458dc66a71decd098e03c79e218"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyter-events" +version = "0.9.0" +description = "Jupyter Event System library" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_events-0.9.0-py3-none-any.whl", hash = "sha256:d853b3c10273ff9bc8bb8b30076d65e2c9685579db736873de6c2232dde148bf"}, + {file = "jupyter_events-0.9.0.tar.gz", hash = "sha256:81ad2e4bc710881ec274d31c6c50669d71bbaa5dd9d01e600b56faa85700d399"}, +] + +[package.dependencies] +jsonschema = {version = ">=4.18.0", extras = ["format-nongpl"]} +python-json-logger = ">=2.0.4" +pyyaml = ">=5.3" +referencing = "*" +rfc3339-validator = "*" +rfc3986-validator = ">=0.1.1" +traitlets = ">=5.3" + +[package.extras] +cli = ["click", "rich"] +docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme", "sphinxcontrib-spelling"] +test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "rich"] + +[[package]] +name = "jupyter-server" +version = "2.12.5" +description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_server-2.12.5-py3-none-any.whl", hash = "sha256:184a0f82809a8522777cfb6b760ab6f4b1bb398664c5860a27cec696cb884923"}, + {file = "jupyter_server-2.12.5.tar.gz", hash = "sha256:0edb626c94baa22809be1323f9770cf1c00a952b17097592e40d03e6a3951689"}, +] + +[package.dependencies] +anyio = ">=3.1.0" +argon2-cffi = "*" +jinja2 = "*" +jupyter-client = ">=7.4.4" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +jupyter-events = ">=0.9.0" +jupyter-server-terminals = "*" +nbconvert = ">=6.4.4" +nbformat = ">=5.3.0" +overrides = "*" +packaging = "*" +prometheus-client = "*" +pywinpty = {version = "*", markers = "os_name == \"nt\""} +pyzmq = ">=24" +send2trash = ">=1.8.2" +terminado = ">=0.8.3" +tornado = ">=6.2.0" +traitlets = ">=5.6.0" +websocket-client = "*" + +[package.extras] +docs = ["ipykernel", "jinja2", "jupyter-client", "jupyter-server", "myst-parser", "nbformat", "prometheus-client", "pydata-sphinx-theme", "send2trash", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-openapi (>=0.8.0)", "sphinxcontrib-spelling", "sphinxemoji", "tornado", "typing-extensions"] +test = ["flaky", "ipykernel", "pre-commit", "pytest (>=7.0)", "pytest-console-scripts", "pytest-jupyter[server] (>=0.4)", "pytest-timeout", "requests"] + +[[package]] +name = "jupyter-server-terminals" +version = "0.5.1" +description = "A Jupyter Server Extension Providing Terminals." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_server_terminals-0.5.1-py3-none-any.whl", hash = "sha256:5e63e947ddd97bb2832db5ef837a258d9ccd4192cd608c1270850ad947ae5dd7"}, + {file = "jupyter_server_terminals-0.5.1.tar.gz", hash = "sha256:16d3be9cf48be6a1f943f3a6c93c033be259cf4779184c66421709cf63dccfea"}, +] + +[package.dependencies] +pywinpty = {version = ">=2.0.3", markers = "os_name == \"nt\""} +terminado = ">=0.8.3" + +[package.extras] +docs = ["jinja2", "jupyter-server", "mistune (<4.0)", "myst-parser", "nbformat", "packaging", "pydata-sphinx-theme", "sphinxcontrib-github-alt", "sphinxcontrib-openapi", "sphinxcontrib-spelling", "sphinxemoji", "tornado"] +test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (>=0.5.3)", "pytest-timeout"] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +description = "Pygments theme using JupyterLab CSS variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, + {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, +] + +[[package]] +name = "markupsafe" +version = "2.1.4" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"}, + {file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"}, + {file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"}, + {file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win32.whl", hash = "sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0"}, + {file = "MarkupSafe-2.1.4-cp37-cp37m-win_amd64.whl", hash = "sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win32.whl", hash = "sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a"}, + {file = "MarkupSafe-2.1.4-cp38-cp38-win_amd64.whl", hash = "sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win32.whl", hash = "sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6"}, + {file = "MarkupSafe-2.1.4-cp39-cp39-win_amd64.whl", hash = "sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959"}, + {file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"}, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mistune" +version = "3.0.2" +description = "A sane and fast Markdown parser with useful plugins and renderers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"}, + {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"}, +] + +[[package]] +name = "mnemonic" +version = "0.20" +description = "Implementation of Bitcoin BIP-0039" +optional = false +python-versions = ">=3.5" +files = [ + {file = "mnemonic-0.20-py3-none-any.whl", hash = "sha256:acd2168872d0379e7a10873bb3e12bf6c91b35de758135c4fbd1015ef18fafc5"}, + {file = "mnemonic-0.20.tar.gz", hash = "sha256:7c6fb5639d779388027a77944680aee4870f0fcd09b1e42a5525ee2ce4c625f6"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nbclassic" +version = "1.0.0" +description = "Jupyter Notebook as a Jupyter Server extension." +optional = false +python-versions = ">=3.7" +files = [ + {file = "nbclassic-1.0.0-py3-none-any.whl", hash = "sha256:f99e4769b4750076cd4235c044b61232110733322384a94a63791d2e7beacc66"}, + {file = "nbclassic-1.0.0.tar.gz", hash = "sha256:0ae11eb2319455d805596bf320336cda9554b41d99ab9a3c31bf8180bffa30e3"}, +] + +[package.dependencies] +argon2-cffi = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=6.1.1" +jupyter-core = ">=4.6.1" +jupyter-server = ">=1.8" +nbconvert = ">=5" +nbformat = "*" +nest-asyncio = ">=1.5" +notebook-shim = ">=0.2.3" +prometheus-client = "*" +pyzmq = ">=17" +Send2Trash = ">=1.8.0" +terminado = ">=0.8.3" +tornado = ">=6.1" +traitlets = ">=4.2.1" + +[package.extras] +docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +json-logging = ["json-logging"] +test = ["coverage", "nbval", "pytest", "pytest-cov", "pytest-jupyter", "pytest-playwright", "pytest-tornasync", "requests", "requests-unixsocket", "testpath"] + +[[package]] +name = "nbclient" +version = "0.9.0" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "nbclient-0.9.0-py3-none-any.whl", hash = "sha256:a3a1ddfb34d4a9d17fc744d655962714a866639acd30130e9be84191cd97cd15"}, + {file = "nbclient-0.9.0.tar.gz", hash = "sha256:4b28c207877cf33ef3a9838cdc7a54c5ceff981194a82eac59d558f05487295e"}, +] + +[package.dependencies] +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +nbformat = ">=5.1" +traitlets = ">=5.4" + +[package.extras] +dev = ["pre-commit"] +docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] + +[[package]] +name = "nbconvert" +version = "7.14.2" +description = "Converting Jupyter Notebooks" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbconvert-7.14.2-py3-none-any.whl", hash = "sha256:db28590cef90f7faf2ebbc71acd402cbecf13d29176df728c0a9025a49345ea1"}, + {file = "nbconvert-7.14.2.tar.gz", hash = "sha256:a7f8808fd4e082431673ac538400218dd45efd076fbeb07cc6e5aa5a3a4e949e"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +bleach = "!=5.0.0" +defusedxml = "*" +jinja2 = ">=3.0" +jupyter-core = ">=4.7" +jupyterlab-pygments = "*" +markupsafe = ">=2.0" +mistune = ">=2.0.3,<4" +nbclient = ">=0.5.0" +nbformat = ">=5.7" +packaging = "*" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +tinycss2 = "*" +traitlets = ">=5.1" + +[package.extras] +all = ["nbconvert[docs,qtpdf,serve,test,webpdf]"] +docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] +qtpdf = ["nbconvert[qtpng]"] +qtpng = ["pyqtwebengine (>=5.15)"] +serve = ["tornado (>=6.1)"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest"] +webpdf = ["playwright"] + +[[package]] +name = "nbformat" +version = "5.9.2" +description = "The Jupyter Notebook format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbformat-5.9.2-py3-none-any.whl", hash = "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9"}, + {file = "nbformat-5.9.2.tar.gz", hash = "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192"}, +] + +[package.dependencies] +fastjsonschema = "*" +jsonschema = ">=2.6" +jupyter-core = "*" +traitlets = ">=5.1" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["pep440", "pre-commit", "pytest", "testpath"] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + +[[package]] +name = "netstruct" +version = "1.1.2" +description = "Packed binary data for networking." +optional = false +python-versions = "*" +files = [ + {file = "netstruct-1.1.2.zip", hash = "sha256:70b6a5c73f5bbc7ab57b019369642adfb34dd8af41b948c400ce95f952b7df9a"}, +] + +[[package]] +name = "notebook" +version = "6.5.6" +description = "A web-based notebook environment for interactive computing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "notebook-6.5.6-py3-none-any.whl", hash = "sha256:c1e2eb2e3b6079a0552a04974883a48d04c3c05792170d64a4b23d707d453181"}, + {file = "notebook-6.5.6.tar.gz", hash = "sha256:b4625a4b7a597839dd3156b140d5ba2c7123761f98245a3290f67a8b8ee048d9"}, +] + +[package.dependencies] +argon2-cffi = "*" +ipykernel = "*" +ipython-genutils = "*" +jinja2 = "*" +jupyter-client = ">=5.3.4,<8" +jupyter-core = ">=4.6.1" +nbclassic = ">=0.4.7" +nbconvert = ">=5" +nbformat = "*" +nest-asyncio = ">=1.5" +prometheus-client = "*" +pyzmq = ">=17,<25" +Send2Trash = ">=1.8.0" +terminado = ">=0.8.3" +tornado = ">=6.1" +traitlets = ">=4.2.1" + +[package.extras] +docs = ["myst-parser", "nbsphinx", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-github-alt"] +json-logging = ["json-logging"] +test = ["coverage", "nbval", "pytest", "pytest-cov", "requests", "requests-unixsocket", "selenium (==4.1.5)", "testpath"] + +[[package]] +name = "notebook-shim" +version = "0.2.3" +description = "A shim layer for notebook traits and config" +optional = false +python-versions = ">=3.7" +files = [ + {file = "notebook_shim-0.2.3-py3-none-any.whl", hash = "sha256:a83496a43341c1674b093bfcebf0fe8e74cbe7eda5fd2bbc56f8e39e1486c0c7"}, + {file = "notebook_shim-0.2.3.tar.gz", hash = "sha256:f69388ac283ae008cd506dda10d0288b09a017d822d5e8c7129a152cbd3ce7e9"}, +] + +[package.dependencies] +jupyter-server = ">=1.8,<3" + +[package.extras] +test = ["pytest", "pytest-console-scripts", "pytest-jupyter", "pytest-tornasync"] + +[[package]] +name = "overrides" +version = "7.6.0" +description = "A decorator to automatically detect mismatch when overriding a method." +optional = false +python-versions = ">=3.6" +files = [ + {file = "overrides-7.6.0-py3-none-any.whl", hash = "sha256:c36e6635519ea9c5b043b65c36d4b886aee8bd45b7d4681d2a6df0898df4b654"}, + {file = "overrides-7.6.0.tar.gz", hash = "sha256:01e15bbbf15b766f0675c275baa1878bd1c7dc9bc7b9ee13e677cdba93dc1bd9"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +description = "Utilities for writing pandoc filters in python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, +] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "platformdirs" +version = "4.1.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, + {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, +] + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "ply" +version = "3.11" +description = "Python Lex & Yacc" +optional = false +python-versions = "*" +files = [ + {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, + {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, +] + +[[package]] +name = "prometheus-client" +version = "0.19.0" +description = "Python client for the Prometheus monitoring system." +optional = false +python-versions = ">=3.8" +files = [ + {file = "prometheus_client-0.19.0-py3-none-any.whl", hash = "sha256:c88b1e6ecf6b41cd8fb5731c7ae919bf66df6ec6fafa555cd6c0e16ca169ae92"}, + {file = "prometheus_client-0.19.0.tar.gz", hash = "sha256:4585b0d1223148c27a225b10dbec5ae9bc4c81a99a3fa80774fa6209935324e1"}, +] + +[package.extras] +twisted = ["twisted"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.43" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.43-py3-none-any.whl", hash = "sha256:a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6"}, + {file = "prompt_toolkit-3.0.43.tar.gz", hash = "sha256:3527b7af26106cbc65a040bcc84839a3566ec1b051bb0bfe953631e704b0ff7d"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] + +[[package]] +name = "py-ecc" +version = "6.0.0" +description = "Elliptic curve crypto in python including secp256k1 and alt_bn128" +optional = false +python-versions = ">=3.6, <4" +files = [ + {file = "py_ecc-6.0.0-py3-none-any.whl", hash = "sha256:54e8aa4c30374fa62d582c599a99f352c153f2971352171318bd6910a643be0b"}, + {file = "py_ecc-6.0.0.tar.gz", hash = "sha256:3fc8a79e38975e05dc443d25783fd69212a1ca854cc0efef071301a8f7d6ce1d"}, +] + +[package.dependencies] +cached-property = ">=1.5.1,<2" +eth-typing = ">=3.0.0,<4" +eth-utils = ">=2.0.0,<3" +mypy-extensions = ">=0.4.1" + +[package.extras] +dev = ["bumpversion (>=0.5.3,<1)", "flake8 (==3.5.0)", "mypy (==0.641)", "mypy-extensions (>=0.4.1)", "pytest (==6.2.5)", "pytest-xdist (==1.26.0)", "twine"] +lint = ["flake8 (==3.5.0)", "mypy (==0.641)", "mypy-extensions (>=0.4.1)"] +test = ["pytest (==6.2.5)", "pytest-xdist (==1.26.0)"] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pygments" +version = "2.17.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, +] + +[package.extras] +plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pysodium" +version = "0.7.17" +description = "python libsodium wrapper" +optional = false +python-versions = "*" +files = [ + {file = "pysodium-0.7.17.tar.gz", hash = "sha256:03afe011a36ab806380c0563591c48aba4e67b15e453b1249bf5c096fec9342d"}, +] + +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytezos" +version = "3.10.3" +description = "Python toolkit for Tezos" +optional = false +python-versions = ">=3.8,<3.12" +files = [ + {file = "pytezos-3.10.3-py3-none-any.whl", hash = "sha256:320bc6f720b9d4812e891edbcde94304ba32b0117b5f59977ec12eda2754556d"}, + {file = "pytezos-3.10.3.tar.gz", hash = "sha256:6f6b54b29eec4564014864fc11929c219ccac5f486b7e264c2be121573ab7826"}, +] + +[package.dependencies] +attrs = ">=21.4.0" +base58 = ">=2.1.1,<3.0.0" +cattrs = ">=22.1.0" +click = ">=8.1.3,<9.0.0" +cryptography = ">=41.0.0,<42.0.0" +deprecation = ">=2.1.0,<3.0.0" +docker = ">=6.0.0,<7.0.0" +fastecdsa = ">=2.2.3,<3.0.0" +jsonschema = ">=4.3.2,<5.0.0" +mnemonic = ">=0.20,<0.21" +netstruct = ">=1.1.2,<2.0.0" +notebook = ">=6.5.6,<7.0.0" +ply = ">=3.11,<4.0" +py-ecc = ">=6.0.0,<7.0.0" +pysodium = ">=0.7.10,<0.8.0" +python-dateutil = ">=2.8.2,<3.0.0" +requests = ">=2.28.2,<3.0.0" +secp256k1 = ">=0.14.0,<0.15.0" +setuptools = ">=67.8.0,<68.0.0" +simple-bson = ">=0.0.3,<0.0.4" +simplejson = ">=3.17.6,<4.0.0" +strict-rfc3339 = ">=0.7,<0.8" +tabulate = ">=0.9.0,<0.10.0" +testcontainers = ">=3.7.0,<4.0.0" +tqdm = ">=4.62.3,<5.0.0" + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "1.0.1" +description = "Read key-value pairs from a .env file and set them as environment variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"}, + {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, +] + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-json-logger" +version = "2.0.7" +description = "A python library adding a json log formatter" +optional = false +python-versions = ">=3.6" +files = [ + {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"}, + {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"}, +] + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pywinpty" +version = "2.0.12" +description = "Pseudo terminal support for Windows from Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pywinpty-2.0.12-cp310-none-win_amd64.whl", hash = "sha256:21319cd1d7c8844fb2c970fb3a55a3db5543f112ff9cfcd623746b9c47501575"}, + {file = "pywinpty-2.0.12-cp311-none-win_amd64.whl", hash = "sha256:853985a8f48f4731a716653170cd735da36ffbdc79dcb4c7b7140bce11d8c722"}, + {file = "pywinpty-2.0.12-cp312-none-win_amd64.whl", hash = "sha256:1617b729999eb6713590e17665052b1a6ae0ad76ee31e60b444147c5b6a35dca"}, + {file = "pywinpty-2.0.12-cp38-none-win_amd64.whl", hash = "sha256:189380469ca143d06e19e19ff3fba0fcefe8b4a8cc942140a6b863aed7eebb2d"}, + {file = "pywinpty-2.0.12-cp39-none-win_amd64.whl", hash = "sha256:7520575b6546db23e693cbd865db2764097bd6d4ef5dc18c92555904cd62c3d4"}, + {file = "pywinpty-2.0.12.tar.gz", hash = "sha256:8197de460ae8ebb7f5d1701dfa1b5df45b157bb832e92acba316305e18ca00dd"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "pyzmq" +version = "24.0.1" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"}, + {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"}, + {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"}, + {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"}, + {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"}, + {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"}, + {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"}, + {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"}, + {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"}, + {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"}, + {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"}, + {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"}, + {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"}, + {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"}, + {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"}, + {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"}, + {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"}, + {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"}, + {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"}, + {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"}, + {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"}, + {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"}, + {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"}, + {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"}, + {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"}, + {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"}, + {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"}, + {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"}, + {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"}, + {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"}, + {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"}, + {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"}, + {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"}, + {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"}, + {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"}, + {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"}, + {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"}, + {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"}, + {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"}, + {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"}, + {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"}, + {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"}, + {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"}, + {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"}, + {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"}, + {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"}, + {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"}, + {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"}, + {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"}, + {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"}, + {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"}, + {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"}, + {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"}, + {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"}, + {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"}, + {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"}, + {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"}, + {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"}, + {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"}, + {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"}, + {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"}, + {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} +py = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "referencing" +version = "0.32.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.32.1-py3-none-any.whl", hash = "sha256:7e4dc12271d8e15612bfe35792f5ea1c40970dadf8624602e33db2758f7ee554"}, + {file = "referencing-0.32.1.tar.gz", hash = "sha256:3c57da0513e9563eb7e203ebe9bb3a1b509b042016433bd1e45a2853466c3dd3"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rfc3339-validator" +version = "0.1.4" +description = "A pure python RFC3339 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"}, + {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"}, +] + +[package.dependencies] +six = "*" + +[[package]] +name = "rfc3986-validator" +version = "0.1.1" +description = "Pure python rfc3986 validator" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"}, + {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"}, +] + +[[package]] +name = "rpds-py" +version = "0.17.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.17.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4128980a14ed805e1b91a7ed551250282a8ddf8201a4e9f8f5b7e6225f54170d"}, + {file = "rpds_py-0.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ff1dcb8e8bc2261a088821b2595ef031c91d499a0c1b031c152d43fe0a6ecec8"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d65e6b4f1443048eb7e833c2accb4fa7ee67cc7d54f31b4f0555b474758bee55"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71169d505af63bb4d20d23a8fbd4c6ce272e7bce6cc31f617152aa784436f29"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:436474f17733c7dca0fbf096d36ae65277e8645039df12a0fa52445ca494729d"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10162fe3f5f47c37ebf6d8ff5a2368508fe22007e3077bf25b9c7d803454d921"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:720215373a280f78a1814becb1312d4e4d1077b1202a56d2b0815e95ccb99ce9"}, + {file = "rpds_py-0.17.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70fcc6c2906cfa5c6a552ba7ae2ce64b6c32f437d8f3f8eea49925b278a61453"}, + {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91e5a8200e65aaac342a791272c564dffcf1281abd635d304d6c4e6b495f29dc"}, + {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:99f567dae93e10be2daaa896e07513dd4bf9c2ecf0576e0533ac36ba3b1d5394"}, + {file = "rpds_py-0.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24e4900a6643f87058a27320f81336d527ccfe503984528edde4bb660c8c8d59"}, + {file = "rpds_py-0.17.1-cp310-none-win32.whl", hash = "sha256:0bfb09bf41fe7c51413f563373e5f537eaa653d7adc4830399d4e9bdc199959d"}, + {file = "rpds_py-0.17.1-cp310-none-win_amd64.whl", hash = "sha256:20de7b7179e2031a04042e85dc463a93a82bc177eeba5ddd13ff746325558aa6"}, + {file = "rpds_py-0.17.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:65dcf105c1943cba45d19207ef51b8bc46d232a381e94dd38719d52d3980015b"}, + {file = "rpds_py-0.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:01f58a7306b64e0a4fe042047dd2b7d411ee82e54240284bab63e325762c1147"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:071bc28c589b86bc6351a339114fb7a029f5cddbaca34103aa573eba7b482382"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ae35e8e6801c5ab071b992cb2da958eee76340e6926ec693b5ff7d6381441745"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149c5cd24f729e3567b56e1795f74577aa3126c14c11e457bec1b1c90d212e38"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e796051f2070f47230c745d0a77a91088fbee2cc0502e9b796b9c6471983718c"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e820ee1004327609b28db8307acc27f5f2e9a0b185b2064c5f23e815f248f8"}, + {file = "rpds_py-0.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1957a2ab607f9added64478a6982742eb29f109d89d065fa44e01691a20fc20a"}, + {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8587fd64c2a91c33cdc39d0cebdaf30e79491cc029a37fcd458ba863f8815383"}, + {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4dc889a9d8a34758d0fcc9ac86adb97bab3fb7f0c4d29794357eb147536483fd"}, + {file = "rpds_py-0.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:2953937f83820376b5979318840f3ee47477d94c17b940fe31d9458d79ae7eea"}, + {file = "rpds_py-0.17.1-cp311-none-win32.whl", hash = "sha256:1bfcad3109c1e5ba3cbe2f421614e70439f72897515a96c462ea657261b96518"}, + {file = "rpds_py-0.17.1-cp311-none-win_amd64.whl", hash = "sha256:99da0a4686ada4ed0f778120a0ea8d066de1a0a92ab0d13ae68492a437db78bf"}, + {file = "rpds_py-0.17.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1dc29db3900cb1bb40353772417800f29c3d078dbc8024fd64655a04ee3c4bdf"}, + {file = "rpds_py-0.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82ada4a8ed9e82e443fcef87e22a3eed3654dd3adf6e3b3a0deb70f03e86142a"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d36b2b59e8cc6e576f8f7b671e32f2ff43153f0ad6d0201250a7c07f25d570e"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3677fcca7fb728c86a78660c7fb1b07b69b281964673f486ae72860e13f512ad"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:516fb8c77805159e97a689e2f1c80655c7658f5af601c34ffdb916605598cda2"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df3b6f45ba4515632c5064e35ca7f31d51d13d1479673185ba8f9fefbbed58b9"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a967dd6afda7715d911c25a6ba1517975acd8d1092b2f326718725461a3d33f9"}, + {file = "rpds_py-0.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dbbb95e6fc91ea3102505d111b327004d1c4ce98d56a4a02e82cd451f9f57140"}, + {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02866e060219514940342a1f84303a1ef7a1dad0ac311792fbbe19b521b489d2"}, + {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2528ff96d09f12e638695f3a2e0c609c7b84c6df7c5ae9bfeb9252b6fa686253"}, + {file = "rpds_py-0.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd345a13ce06e94c753dab52f8e71e5252aec1e4f8022d24d56decd31e1b9b23"}, + {file = "rpds_py-0.17.1-cp312-none-win32.whl", hash = "sha256:2a792b2e1d3038daa83fa474d559acfd6dc1e3650ee93b2662ddc17dbff20ad1"}, + {file = "rpds_py-0.17.1-cp312-none-win_amd64.whl", hash = "sha256:292f7344a3301802e7c25c53792fae7d1593cb0e50964e7bcdcc5cf533d634e3"}, + {file = "rpds_py-0.17.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:8ffe53e1d8ef2520ebcf0c9fec15bb721da59e8ef283b6ff3079613b1e30513d"}, + {file = "rpds_py-0.17.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4341bd7579611cf50e7b20bb8c2e23512a3dc79de987a1f411cb458ab670eb90"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4eb548daf4836e3b2c662033bfbfc551db58d30fd8fe660314f86bf8510b93"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b686f25377f9c006acbac63f61614416a6317133ab7fafe5de5f7dc8a06d42eb"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4e21b76075c01d65d0f0f34302b5a7457d95721d5e0667aea65e5bb3ab415c25"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b86b21b348f7e5485fae740d845c65a880f5d1eda1e063bc59bef92d1f7d0c55"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f175e95a197f6a4059b50757a3dca33b32b61691bdbd22c29e8a8d21d3914cae"}, + {file = "rpds_py-0.17.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1701fc54460ae2e5efc1dd6350eafd7a760f516df8dbe51d4a1c79d69472fbd4"}, + {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9051e3d2af8f55b42061603e29e744724cb5f65b128a491446cc029b3e2ea896"}, + {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:7450dbd659fed6dd41d1a7d47ed767e893ba402af8ae664c157c255ec6067fde"}, + {file = "rpds_py-0.17.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5a024fa96d541fd7edaa0e9d904601c6445e95a729a2900c5aec6555fe921ed6"}, + {file = "rpds_py-0.17.1-cp38-none-win32.whl", hash = "sha256:da1ead63368c04a9bded7904757dfcae01eba0e0f9bc41d3d7f57ebf1c04015a"}, + {file = "rpds_py-0.17.1-cp38-none-win_amd64.whl", hash = "sha256:841320e1841bb53fada91c9725e766bb25009cfd4144e92298db296fb6c894fb"}, + {file = "rpds_py-0.17.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f6c43b6f97209e370124baf2bf40bb1e8edc25311a158867eb1c3a5d449ebc7a"}, + {file = "rpds_py-0.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7d63ec01fe7c76c2dbb7e972fece45acbb8836e72682bde138e7e039906e2c"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81038ff87a4e04c22e1d81f947c6ac46f122e0c80460b9006e6517c4d842a6ec"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:810685321f4a304b2b55577c915bece4c4a06dfe38f6e62d9cc1d6ca8ee86b99"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:25f071737dae674ca8937a73d0f43f5a52e92c2d178330b4c0bb6ab05586ffa6"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa5bfb13f1e89151ade0eb812f7b0d7a4d643406caaad65ce1cbabe0a66d695f"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfe07308b311a8293a0d5ef4e61411c5c20f682db6b5e73de6c7c8824272c256"}, + {file = "rpds_py-0.17.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a000133a90eea274a6f28adc3084643263b1e7c1a5a66eb0a0a7a36aa757ed74"}, + {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d0e8a6434a3fbf77d11448c9c25b2f25244226cfbec1a5159947cac5b8c5fa4"}, + {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efa767c220d94aa4ac3a6dd3aeb986e9f229eaf5bce92d8b1b3018d06bed3772"}, + {file = "rpds_py-0.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:dbc56680ecf585a384fbd93cd42bc82668b77cb525343170a2d86dafaed2a84b"}, + {file = "rpds_py-0.17.1-cp39-none-win32.whl", hash = "sha256:270987bc22e7e5a962b1094953ae901395e8c1e1e83ad016c5cfcfff75a15a3f"}, + {file = "rpds_py-0.17.1-cp39-none-win_amd64.whl", hash = "sha256:2a7b2f2f56a16a6d62e55354dd329d929560442bd92e87397b7a9586a32e3e76"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a3264e3e858de4fc601741498215835ff324ff2482fd4e4af61b46512dd7fc83"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f2f3b28b40fddcb6c1f1f6c88c6f3769cd933fa493ceb79da45968a21dccc920"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9584f8f52010295a4a417221861df9bea4c72d9632562b6e59b3c7b87a1522b7"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c64602e8be701c6cfe42064b71c84ce62ce66ddc6422c15463fd8127db3d8066"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:060f412230d5f19fc8c8b75f315931b408d8ebf56aec33ef4168d1b9e54200b1"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9412abdf0ba70faa6e2ee6c0cc62a8defb772e78860cef419865917d86c7342"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9737bdaa0ad33d34c0efc718741abaafce62fadae72c8b251df9b0c823c63b22"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9f0e4dc0f17dcea4ab9d13ac5c666b6b5337042b4d8f27e01b70fae41dd65c57"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1db228102ab9d1ff4c64148c96320d0be7044fa28bd865a9ce628ce98da5973d"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:d8bbd8e56f3ba25a7d0cf980fc42b34028848a53a0e36c9918550e0280b9d0b6"}, + {file = "rpds_py-0.17.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:be22ae34d68544df293152b7e50895ba70d2a833ad9566932d750d3625918b82"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bf046179d011e6114daf12a534d874958b039342b347348a78b7cdf0dd9d6041"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:1a746a6d49665058a5896000e8d9d2f1a6acba8a03b389c1e4c06e11e0b7f40d"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0b8bf5b8db49d8fd40f54772a1dcf262e8be0ad2ab0206b5a2ec109c176c0a4"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f7f4cb1f173385e8a39c29510dd11a78bf44e360fb75610594973f5ea141028b"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7fbd70cb8b54fe745301921b0816c08b6d917593429dfc437fd024b5ba713c58"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bdf1303df671179eaf2cb41e8515a07fc78d9d00f111eadbe3e14262f59c3d0"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad059a4bd14c45776600d223ec194e77db6c20255578bb5bcdd7c18fd169361"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3664d126d3388a887db44c2e293f87d500c4184ec43d5d14d2d2babdb4c64cad"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:698ea95a60c8b16b58be9d854c9f993c639f5c214cf9ba782eca53a8789d6b19"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:c3d2010656999b63e628a3c694f23020322b4178c450dc478558a2b6ef3cb9bb"}, + {file = "rpds_py-0.17.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:938eab7323a736533f015e6069a7d53ef2dcc841e4e533b782c2bfb9fb12d84b"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e626b365293a2142a62b9a614e1f8e331b28f3ca57b9f05ebbf4cf2a0f0bdc5"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:380e0df2e9d5d5d339803cfc6d183a5442ad7ab3c63c2a0982e8c824566c5ccc"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b760a56e080a826c2e5af09002c1a037382ed21d03134eb6294812dda268c811"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5576ee2f3a309d2bb403ec292d5958ce03953b0e57a11d224c1f134feaf8c40f"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3c3461ebb4c4f1bbc70b15d20b565759f97a5aaf13af811fcefc892e9197ba"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:637b802f3f069a64436d432117a7e58fab414b4e27a7e81049817ae94de45d8d"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffee088ea9b593cc6160518ba9bd319b5475e5f3e578e4552d63818773c6f56a"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ac732390d529d8469b831949c78085b034bff67f584559340008d0f6041a049"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:93432e747fb07fa567ad9cc7aaadd6e29710e515aabf939dfbed8046041346c6"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b7d9ca34542099b4e185b3c2a2b2eda2e318a7dbde0b0d83357a6d4421b5296"}, + {file = "rpds_py-0.17.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:0387ce69ba06e43df54e43968090f3626e231e4bc9150e4c3246947567695f68"}, + {file = "rpds_py-0.17.1.tar.gz", hash = "sha256:0210b2668f24c078307260bf88bdac9d6f1093635df5123789bfee4d8d7fc8e7"}, +] + +[[package]] +name = "secp256k1" +version = "0.14.0" +description = "FFI bindings to libsecp256k1" +optional = false +python-versions = "*" +files = [ + {file = "secp256k1-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f666c67dcf1dc69e1448b2ede5e12aaf382b600204a61dbc65e4f82cea444405"}, + {file = "secp256k1-0.14.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fcabb3c3497a902fb61eec72d1b69bf72747d7bcc2a732d56d9319a1e8322262"}, + {file = "secp256k1-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7a27c479ab60571502516a1506a562d0a9df062de8ad645313fabfcc97252816"}, + {file = "secp256k1-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f4b9306bff6dde020444dfee9ca9b9f5b20ca53a2c0b04898361a3f43d5daf2e"}, + {file = "secp256k1-0.14.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:72735da6cb28273e924431cd40aa607e7f80ef09608c8c9300be2e0e1d2417b4"}, + {file = "secp256k1-0.14.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:87f4ad42a370f768910585989a301d1d65de17dcd86f6e8def9b021364b34d5c"}, + {file = "secp256k1-0.14.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:130f119b06142e597c10eb4470b5a38eae865362d01aaef06b113478d77f728d"}, + {file = "secp256k1-0.14.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:3aedcfe6eb1c5fa7c6be25b7cc91c76d8eb984271920ba0f7a934ae41ed56f51"}, + {file = "secp256k1-0.14.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c91dd3154f6c46ac798d9a41166120e1751222587f54516cc3f378f56ce4ac82"}, + {file = "secp256k1-0.14.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fec790cb6d0d37129ca0ce5b3f8e85692d5fb618d1c440f189453d18694035df"}, + {file = "secp256k1-0.14.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:63eb148196b8f646922d4be6739b17fbbf50ebb3a020078c823e2445d88b7a81"}, + {file = "secp256k1-0.14.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:adc23a4c5d24c95191638eb2ca313097827f07db102e77b59faed15d50c98cae"}, + {file = "secp256k1-0.14.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ce0314788d3248b275426501228969fd32f6501c9d1837902ee0e7bd8264a36f"}, + {file = "secp256k1-0.14.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bc761894b3634021686714278fc62b73395fa3eded33453eadfd8a00a6c44ef3"}, + {file = "secp256k1-0.14.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:373dc8bca735f3c2d73259aa2711a9ecea2f3c7edbb663555fe3422e3dd76102"}, + {file = "secp256k1-0.14.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fe3f503c9dfdf663b500d3e0688ad842e116c2907ad3f1e1d685812df3f56290"}, + {file = "secp256k1-0.14.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4b1bf09953cde181132cf5e9033065615e5c2694e803165e2db763efa47695e5"}, + {file = "secp256k1-0.14.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6af07be5f8612628c3638dc7b208f6cc78d0abae3e25797eadb13890c7d5da81"}, + {file = "secp256k1-0.14.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a8dbd75a9fb6f42de307f3c5e24573fe59c3374637cbf39136edc66c200a4029"}, + {file = "secp256k1-0.14.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:97a30c8dae633cb18135c76b6517ae99dc59106818e8985be70dbc05dcc06c0d"}, + {file = "secp256k1-0.14.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f4062d8c101aa63b9ecb3709f1f075ad9c01b6672869bbaa1bd77271816936a7"}, + {file = "secp256k1-0.14.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9e7c024ff17e9b9d7c392bb2a917da231d6cb40ab119389ff1f51dca10339a4"}, + {file = "secp256k1-0.14.0.tar.gz", hash = "sha256:82c06712d69ef945220c8b53c1a0d424c2ff6a1f64aee609030df79ad8383397"}, +] + +[package.dependencies] +cffi = ">=1.3.0" + +[[package]] +name = "send2trash" +version = "1.8.2" +description = "Send file to trash natively under Mac OS X, Windows and Linux" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "Send2Trash-1.8.2-py3-none-any.whl", hash = "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679"}, + {file = "Send2Trash-1.8.2.tar.gz", hash = "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312"}, +] + +[package.extras] +nativelib = ["pyobjc-framework-Cocoa", "pywin32"] +objc = ["pyobjc-framework-Cocoa"] +win32 = ["pywin32"] + +[[package]] +name = "setuptools" +version = "67.8.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "simple-bson" +version = "0.0.3" +description = "Python Bson Compatible Library" +optional = false +python-versions = ">=3.6,<4.0" +files = [ + {file = "simple-bson-0.0.3.tar.gz", hash = "sha256:5abc3df2047141763abe0ad282f78e88b012566e9196182877f99ad7ef3d42c7"}, + {file = "simple_bson-0.0.3-py3-none-any.whl", hash = "sha256:5cb1921d013b2d4af846d0d385de2cbf2b37e4042d1d9d55e44b5514990dfea1"}, +] + +[[package]] +name = "simplejson" +version = "3.19.2" +description = "Simple, fast, extensible JSON encoder/decoder for Python" +optional = false +python-versions = ">=2.5, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "simplejson-3.19.2-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3471e95110dcaf901db16063b2e40fb394f8a9e99b3fe9ee3acc6f6ef72183a2"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:3194cd0d2c959062b94094c0a9f8780ffd38417a5322450a0db0ca1a23e7fbd2"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8a390e56a7963e3946ff2049ee1eb218380e87c8a0e7608f7f8790ba19390867"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:1537b3dd62d8aae644f3518c407aa8469e3fd0f179cdf86c5992792713ed717a"}, + {file = "simplejson-3.19.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a8617625369d2d03766413bff9e64310feafc9fc4f0ad2b902136f1a5cd8c6b0"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:2c433a412e96afb9a3ce36fa96c8e61a757af53e9c9192c97392f72871e18e69"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f1c70249b15e4ce1a7d5340c97670a95f305ca79f376887759b43bb33288c973"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:287e39ba24e141b046812c880f4619d0ca9e617235d74abc27267194fc0c7835"}, + {file = "simplejson-3.19.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6f0a0b41dd05eefab547576bed0cf066595f3b20b083956b1405a6f17d1be6ad"}, + {file = "simplejson-3.19.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f98d918f7f3aaf4b91f2b08c0c92b1774aea113334f7cde4fe40e777114dbe6"}, + {file = "simplejson-3.19.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d74beca677623481810c7052926365d5f07393c72cbf62d6cce29991b676402"}, + {file = "simplejson-3.19.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7f2398361508c560d0bf1773af19e9fe644e218f2a814a02210ac2c97ad70db0"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ad331349b0b9ca6da86064a3599c425c7a21cd41616e175ddba0866da32df48"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:332c848f02d71a649272b3f1feccacb7e4f7e6de4a2e6dc70a32645326f3d428"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:25785d038281cd106c0d91a68b9930049b6464288cea59ba95b35ee37c2d23a5"}, + {file = "simplejson-3.19.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18955c1da6fc39d957adfa346f75226246b6569e096ac9e40f67d102278c3bcb"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:11cc3afd8160d44582543838b7e4f9aa5e97865322844b75d51bf4e0e413bb3e"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b01fda3e95d07a6148702a641e5e293b6da7863f8bc9b967f62db9461330562c"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:778331444917108fa8441f59af45886270d33ce8a23bfc4f9b192c0b2ecef1b3"}, + {file = "simplejson-3.19.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9eb117db8d7ed733a7317c4215c35993b815bf6aeab67523f1f11e108c040672"}, + {file = "simplejson-3.19.2-cp310-cp310-win32.whl", hash = "sha256:39b6d79f5cbfa3eb63a869639cfacf7c41d753c64f7801efc72692c1b2637ac7"}, + {file = "simplejson-3.19.2-cp310-cp310-win_amd64.whl", hash = "sha256:5675e9d8eeef0aa06093c1ff898413ade042d73dc920a03e8cea2fb68f62445a"}, + {file = "simplejson-3.19.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ed628c1431100b0b65387419551e822987396bee3c088a15d68446d92f554e0c"}, + {file = "simplejson-3.19.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:adcb3332979cbc941b8fff07181f06d2b608625edc0a4d8bc3ffc0be414ad0c4"}, + {file = "simplejson-3.19.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:08889f2f597ae965284d7b52a5c3928653a9406d88c93e3161180f0abc2433ba"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef7938a78447174e2616be223f496ddccdbf7854f7bf2ce716dbccd958cc7d13"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a970a2e6d5281d56cacf3dc82081c95c1f4da5a559e52469287457811db6a79b"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554313db34d63eac3b3f42986aa9efddd1a481169c12b7be1e7512edebff8eaf"}, + {file = "simplejson-3.19.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d36081c0b1c12ea0ed62c202046dca11438bee48dd5240b7c8de8da62c620e9"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a3cd18e03b0ee54ea4319cdcce48357719ea487b53f92a469ba8ca8e39df285e"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:66e5dc13bfb17cd6ee764fc96ccafd6e405daa846a42baab81f4c60e15650414"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:972a7833d4a1fcf7a711c939e315721a88b988553fc770a5b6a5a64bd6ebeba3"}, + {file = "simplejson-3.19.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3e74355cb47e0cd399ead3477e29e2f50e1540952c22fb3504dda0184fc9819f"}, + {file = "simplejson-3.19.2-cp311-cp311-win32.whl", hash = "sha256:1dd4f692304854352c3e396e9b5f0a9c9e666868dd0bdc784e2ac4c93092d87b"}, + {file = "simplejson-3.19.2-cp311-cp311-win_amd64.whl", hash = "sha256:9300aee2a8b5992d0f4293d88deb59c218989833e3396c824b69ba330d04a589"}, + {file = "simplejson-3.19.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b8d940fd28eb34a7084877747a60873956893e377f15a32ad445fe66c972c3b8"}, + {file = "simplejson-3.19.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4969d974d9db826a2c07671273e6b27bc48e940738d768fa8f33b577f0978378"}, + {file = "simplejson-3.19.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c594642d6b13d225e10df5c16ee15b3398e21a35ecd6aee824f107a625690374"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2f5a398b5e77bb01b23d92872255e1bcb3c0c719a3be40b8df146570fe7781a"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:176a1b524a3bd3314ed47029a86d02d5a95cc0bee15bd3063a1e1ec62b947de6"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3c7363a8cb8c5238878ec96c5eb0fc5ca2cb11fc0c7d2379863d342c6ee367a"}, + {file = "simplejson-3.19.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:346820ae96aa90c7d52653539a57766f10f33dd4be609206c001432b59ddf89f"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de9a2792612ec6def556d1dc621fd6b2073aff015d64fba9f3e53349ad292734"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1c768e7584c45094dca4b334af361e43b0aaa4844c04945ac7d43379eeda9bc2"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:9652e59c022e62a5b58a6f9948b104e5bb96d3b06940c6482588176f40f4914b"}, + {file = "simplejson-3.19.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9c1a4393242e321e344213a90a1e3bf35d2f624aa8b8f6174d43e3c6b0e8f6eb"}, + {file = "simplejson-3.19.2-cp312-cp312-win32.whl", hash = "sha256:7cb98be113911cb0ad09e5523d0e2a926c09a465c9abb0784c9269efe4f95917"}, + {file = "simplejson-3.19.2-cp312-cp312-win_amd64.whl", hash = "sha256:6779105d2fcb7fcf794a6a2a233787f6bbd4731227333a072d8513b252ed374f"}, + {file = "simplejson-3.19.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:061e81ea2d62671fa9dea2c2bfbc1eec2617ae7651e366c7b4a2baf0a8c72cae"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4280e460e51f86ad76dc456acdbfa9513bdf329556ffc8c49e0200878ca57816"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11c39fbc4280d7420684494373b7c5904fa72a2b48ef543a56c2d412999c9e5d"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bccb3e88ec26ffa90f72229f983d3a5d1155e41a1171190fa723d4135523585b"}, + {file = "simplejson-3.19.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bb5b50dc6dd671eb46a605a3e2eb98deb4a9af787a08fcdddabe5d824bb9664"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d94245caa3c61f760c4ce4953cfa76e7739b6f2cbfc94cc46fff6c050c2390c5"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d0e5ffc763678d48ecc8da836f2ae2dd1b6eb2d27a48671066f91694e575173c"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:d222a9ed082cd9f38b58923775152003765016342a12f08f8c123bf893461f28"}, + {file = "simplejson-3.19.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8434dcdd347459f9fd9c526117c01fe7ca7b016b6008dddc3c13471098f4f0dc"}, + {file = "simplejson-3.19.2-cp36-cp36m-win32.whl", hash = "sha256:c9ac1c2678abf9270e7228133e5b77c6c3c930ad33a3c1dfbdd76ff2c33b7b50"}, + {file = "simplejson-3.19.2-cp36-cp36m-win_amd64.whl", hash = "sha256:92c4a4a2b1f4846cd4364855cbac83efc48ff5a7d7c06ba014c792dd96483f6f"}, + {file = "simplejson-3.19.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0d551dc931638e2102b8549836a1632e6e7cf620af3d093a7456aa642bff601d"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73a8a4653f2e809049999d63530180d7b5a344b23a793502413ad1ecea9a0290"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:40847f617287a38623507d08cbcb75d51cf9d4f9551dd6321df40215128325a3"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be893258d5b68dd3a8cba8deb35dc6411db844a9d35268a8d3793b9d9a256f80"}, + {file = "simplejson-3.19.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9eb3cff1b7d71aa50c89a0536f469cb8d6dcdd585d8f14fb8500d822f3bdee4"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d0f402e787e6e7ee7876c8b05e2fe6464820d9f35ba3f172e95b5f8b699f6c7f"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fbbcc6b0639aa09b9649f36f1bcb347b19403fe44109948392fbb5ea69e48c3e"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2fc697be37585eded0c8581c4788fcfac0e3f84ca635b73a5bf360e28c8ea1a2"}, + {file = "simplejson-3.19.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b0a3eb6dd39cce23801a50c01a0976971498da49bc8a0590ce311492b82c44b"}, + {file = "simplejson-3.19.2-cp37-cp37m-win32.whl", hash = "sha256:49f9da0d6cd17b600a178439d7d2d57c5ef01f816b1e0e875e8e8b3b42db2693"}, + {file = "simplejson-3.19.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c87c22bd6a987aca976e3d3e23806d17f65426191db36d40da4ae16a6a494cbc"}, + {file = "simplejson-3.19.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e4c166f743bb42c5fcc60760fb1c3623e8fda94f6619534217b083e08644b46"}, + {file = "simplejson-3.19.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0a48679310e1dd5c9f03481799311a65d343748fe86850b7fb41df4e2c00c087"}, + {file = "simplejson-3.19.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0521e0f07cb56415fdb3aae0bbd8701eb31a9dfef47bb57206075a0584ab2a2"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d2d5119b1d7a1ed286b8af37357116072fc96700bce3bec5bb81b2e7057ab41"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c1467d939932901a97ba4f979e8f2642415fcf02ea12f53a4e3206c9c03bc17"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49aaf4546f6023c44d7e7136be84a03a4237f0b2b5fb2b17c3e3770a758fc1a0"}, + {file = "simplejson-3.19.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60848ab779195b72382841fc3fa4f71698a98d9589b0a081a9399904487b5832"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0436a70d8eb42bea4fe1a1c32d371d9bb3b62c637969cb33970ad624d5a3336a"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:49e0e3faf3070abdf71a5c80a97c1afc059b4f45a5aa62de0c2ca0444b51669b"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ff836cd4041e16003549449cc0a5e372f6b6f871eb89007ab0ee18fb2800fded"}, + {file = "simplejson-3.19.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3848427b65e31bea2c11f521b6fc7a3145d6e501a1038529da2391aff5970f2f"}, + {file = "simplejson-3.19.2-cp38-cp38-win32.whl", hash = "sha256:3f39bb1f6e620f3e158c8b2eaf1b3e3e54408baca96a02fe891794705e788637"}, + {file = "simplejson-3.19.2-cp38-cp38-win_amd64.whl", hash = "sha256:0405984f3ec1d3f8777c4adc33eac7ab7a3e629f3b1c05fdded63acc7cf01137"}, + {file = "simplejson-3.19.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:445a96543948c011a3a47c8e0f9d61e9785df2544ea5be5ab3bc2be4bd8a2565"}, + {file = "simplejson-3.19.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a8c3cc4f9dfc33220246760358c8265dad6e1104f25f0077bbca692d616d358"}, + {file = "simplejson-3.19.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af9c7e6669c4d0ad7362f79cb2ab6784d71147503e62b57e3d95c4a0f222c01c"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:064300a4ea17d1cd9ea1706aa0590dcb3be81112aac30233823ee494f02cb78a"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9453419ea2ab9b21d925d0fd7e3a132a178a191881fab4169b6f96e118cc25bb"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e038c615b3906df4c3be8db16b3e24821d26c55177638ea47b3f8f73615111c"}, + {file = "simplejson-3.19.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16ca9c90da4b1f50f089e14485db8c20cbfff2d55424062791a7392b5a9b3ff9"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1018bd0d70ce85f165185d2227c71e3b1e446186f9fa9f971b69eee223e1e3cd"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e8dd53a8706b15bc0e34f00e6150fbefb35d2fd9235d095b4f83b3c5ed4fa11d"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:2d022b14d7758bfb98405672953fe5c202ea8a9ccf9f6713c5bd0718eba286fd"}, + {file = "simplejson-3.19.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:febffa5b1eda6622d44b245b0685aff6fb555ce0ed734e2d7b1c3acd018a2cff"}, + {file = "simplejson-3.19.2-cp39-cp39-win32.whl", hash = "sha256:4edcd0bf70087b244ba77038db23cd98a1ace2f91b4a3ecef22036314d77ac23"}, + {file = "simplejson-3.19.2-cp39-cp39-win_amd64.whl", hash = "sha256:aad7405c033d32c751d98d3a65801e2797ae77fac284a539f6c3a3e13005edc4"}, + {file = "simplejson-3.19.2-py3-none-any.whl", hash = "sha256:bcedf4cae0d47839fee7de344f96b5694ca53c786f28b5f773d4f0b265a159eb"}, + {file = "simplejson-3.19.2.tar.gz", hash = "sha256:9eb442a2442ce417801c912df68e1f6ccfcd41577ae7274953ab3ad24ef7d82c"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "sniffio" +version = "1.3.0" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +files = [ + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, +] + +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "strict-rfc3339" +version = "0.7" +description = "Strict, simple, lightweight RFC3339 functions" +optional = false +python-versions = "*" +files = [ + {file = "strict-rfc3339-0.7.tar.gz", hash = "sha256:5cad17bedfc3af57b399db0fed32771f18fc54bbd917e85546088607ac5e1277"}, +] + +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "terminado" +version = "0.18.0" +description = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library." +optional = false +python-versions = ">=3.8" +files = [ + {file = "terminado-0.18.0-py3-none-any.whl", hash = "sha256:87b0d96642d0fe5f5abd7783857b9cab167f221a39ff98e3b9619a788a3c0f2e"}, + {file = "terminado-0.18.0.tar.gz", hash = "sha256:1ea08a89b835dd1b8c0c900d92848147cef2537243361b2e3f4dc15df9b6fded"}, +] + +[package.dependencies] +ptyprocess = {version = "*", markers = "os_name != \"nt\""} +pywinpty = {version = ">=1.1.0", markers = "os_name == \"nt\""} +tornado = ">=6.1.0" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] +typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] + +[[package]] +name = "testcontainers" +version = "3.7.1" +description = "Library provides lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container" +optional = false +python-versions = ">=3.7" +files = [ + {file = "testcontainers-3.7.1-py2.py3-none-any.whl", hash = "sha256:7f48cef4bf0ccd78f1a4534d4b701a003a3bace851f24eae58a32f9e3f0aeba0"}, +] + +[package.dependencies] +deprecation = "*" +docker = ">=4.0.0" +wrapt = "*" + +[package.extras] +arangodb = ["python-arango"] +azurite = ["azure-storage-blob"] +clickhouse = ["clickhouse-driver"] +docker-compose = ["docker-compose"] +google-cloud-pubsub = ["google-cloud-pubsub (<2)"] +kafka = ["kafka-python"] +keycloak = ["python-keycloak"] +mongo = ["pymongo"] +mssqlserver = ["pymssql"] +mysql = ["pymysql", "sqlalchemy"] +neo4j = ["neo4j"] +oracle = ["cx-Oracle", "sqlalchemy"] +postgresql = ["psycopg2-binary", "sqlalchemy"] +rabbitmq = ["pika"] +redis = ["redis"] +selenium = ["selenium"] + +[[package]] +name = "tinycss2" +version = "1.2.1" +description = "A tiny CSS parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, + {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "toolz" +version = "0.12.0" +description = "List processing tools and functional utilities" +optional = false +python-versions = ">=3.5" +files = [ + {file = "toolz-0.12.0-py3-none-any.whl", hash = "sha256:2059bd4148deb1884bb0eb770a3cde70e7f954cfbbdc2285f1f2de01fd21eb6f"}, + {file = "toolz-0.12.0.tar.gz", hash = "sha256:88c570861c440ee3f2f6037c4654613228ff40c93a6c25e0eba70d17282c6194"}, +] + +[[package]] +name = "tornado" +version = "6.4" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.4-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:02ccefc7d8211e5a7f9e8bc3f9e5b0ad6262ba2fbb683a6443ecc804e5224ce0"}, + {file = "tornado-6.4-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:27787de946a9cffd63ce5814c33f734c627a87072ec7eed71f7fc4417bb16263"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7894c581ecdcf91666a0912f18ce5e757213999e183ebfc2c3fdbf4d5bd764e"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e43bc2e5370a6a8e413e1e1cd0c91bedc5bd62a74a532371042a18ef19e10579"}, + {file = "tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fd03192e287fbd0899dd8f81c6fb9cbbc69194d2074b38f384cb6fa72b80e9c2"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:88b84956273fbd73420e6d4b8d5ccbe913c65d31351b4c004ae362eba06e1f78"}, + {file = "tornado-6.4-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:71ddfc23a0e03ef2df1c1397d859868d158c8276a0603b96cf86892bff58149f"}, + {file = "tornado-6.4-cp38-abi3-win32.whl", hash = "sha256:6f8a6c77900f5ae93d8b4ae1196472d0ccc2775cc1dfdc9e7727889145c45052"}, + {file = "tornado-6.4-cp38-abi3-win_amd64.whl", hash = "sha256:10aeaa8006333433da48dec9fe417877f8bcc21f48dda8d661ae79da357b2a63"}, + {file = "tornado-6.4.tar.gz", hash = "sha256:72291fa6e6bc84e626589f1c29d90a5a6d593ef5ae68052ee2ef000dfd273dee"}, +] + +[[package]] +name = "tqdm" +version = "4.66.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "traitlets" +version = "5.14.1" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.14.1-py3-none-any.whl", hash = "sha256:2e5a030e6eff91737c643231bfcf04a65b0132078dad75e4936700b213652e74"}, + {file = "traitlets-5.14.1.tar.gz", hash = "sha256:8585105b371a04b8316a43d5ce29c098575c2e477850b62b848b964f1444527e"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "types-python-dateutil" +version = "2.8.19.20240106" +description = "Typing stubs for python-dateutil" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-python-dateutil-2.8.19.20240106.tar.gz", hash = "sha256:1f8db221c3b98e6ca02ea83a58371b22c374f42ae5bbdf186db9c9a76581459f"}, + {file = "types_python_dateutil-2.8.19.20240106-py3-none-any.whl", hash = "sha256:efbbdc54590d0f16152fa103c9879c7d4a00e82078f6e2cf01769042165acaa2"}, +] + +[[package]] +name = "typing-extensions" +version = "4.9.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, +] + +[[package]] +name = "uri-template" +version = "1.3.0" +description = "RFC 6570 URI Template Processor" +optional = false +python-versions = ">=3.7" +files = [ + {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"}, + {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"}, +] + +[package.extras] +dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake8-commas", "flake8-comprehensions", "flake8-continuation", "flake8-datetimez", "flake8-docstrings", "flake8-import-order", "flake8-literal", "flake8-modern-annotations", "flake8-noqa", "flake8-pyproject", "flake8-requirements", "flake8-typechecking-import", "flake8-use-fstring", "mypy", "pep8-naming", "types-PyYAML"] + +[[package]] +name = "urllib3" +version = "2.1.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "webcolors" +version = "1.13" +description = "A library for working with the color formats defined by HTML and CSS." +optional = false +python-versions = ">=3.7" +files = [ + {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"}, + {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"}, +] + +[package.extras] +docs = ["furo", "sphinx", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-notfound-page", "sphinxext-opengraph"] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[[package]] +name = "websocket-client" +version = "1.7.0" +description = "WebSocket client for Python with low level API options" +optional = false +python-versions = ">=3.8" +files = [ + {file = "websocket-client-1.7.0.tar.gz", hash = "sha256:10e511ea3a8c744631d3bd77e61eb17ed09304c413ad42cf6ddfa4c7787e8fe6"}, + {file = "websocket_client-1.7.0-py3-none-any.whl", hash = "sha256:f4c3d22fec12a2461427a29957ff07d35098ee2d976d3ba244e688b8b4057588"}, +] + +[package.extras] +docs = ["Sphinx (>=6.0)", "sphinx-rtd-theme (>=1.1.0)"] +optional = ["python-socks", "wsaccel"] +test = ["websockets"] + +[[package]] +name = "wrapt" +version = "1.16.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = ">=3.6" +files = [ + {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, + {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, + {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, + {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, + {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, + {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, + {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, + {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, + {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, + {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, + {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, + {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, + {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, + {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, + {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, + {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, + {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, + {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, + {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, + {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, + {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, + {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, + {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, + {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, + {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, + {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, + {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, + {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, + {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, + {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, + {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, + {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, + {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, + {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, + {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, + {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, + {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, +] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.10,<3.12" +content-hash = "8eddebfa5e9ff4171cb5590b631d897aae7caa35ba1cf3f7a7399afa5ef5c707" diff --git a/etherlink/tezos_contracts/governance/pyproject.toml b/etherlink/tezos_contracts/governance/pyproject.toml new file mode 100644 index 000000000000..10d94ec5ab74 --- /dev/null +++ b/etherlink/tezos_contracts/governance/pyproject.toml @@ -0,0 +1,25 @@ +[tool.poetry] +name = "etherlink-governance" +version = "0.1.0" +description = "TODO" +authors = ["Maxim Kucherov "] +readme = "README.md" +packages = [ + { include = "tests" }, +] + +[tool.poetry.dependencies] +python = ">=3.10,<3.12" +python-dotenv = "^1.0.1" + + +[tool.poetry.group.dev.dependencies] +pytest = "^7.4.4" +pytezos = "^3.10.3" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +deploy_contract = "scripts.governance:deploy_contract" \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/scripts/__init__.py b/etherlink/tezos_contracts/governance/scripts/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/scripts/contract_type.py b/etherlink/tezos_contracts/governance/scripts/contract_type.py new file mode 100644 index 000000000000..9732e40debe3 --- /dev/null +++ b/etherlink/tezos_contracts/governance/scripts/contract_type.py @@ -0,0 +1,3 @@ +from enum import Enum + +ContractType = Enum('ContractType', ['kernel_regular_governance', 'kernel_security_governance', 'sequencer_governance']) diff --git a/etherlink/tezos_contracts/governance/scripts/environment.py b/etherlink/tezos_contracts/governance/scripts/environment.py new file mode 100644 index 000000000000..4b6838e2be7c --- /dev/null +++ b/etherlink/tezos_contracts/governance/scripts/environment.py @@ -0,0 +1,10 @@ +from dotenv import load_dotenv +from getpass import getpass +import os + + +def load_or_ask(var_name: str, is_secret: bool = False) -> str: + load_dotenv() + ask = getpass if is_secret else input + return os.getenv(var_name) or ask(f'Enter {var_name}: ') + diff --git a/etherlink/tezos_contracts/governance/scripts/governance.py b/etherlink/tezos_contracts/governance/scripts/governance.py new file mode 100644 index 000000000000..3597d7e205fb --- /dev/null +++ b/etherlink/tezos_contracts/governance/scripts/governance.py @@ -0,0 +1,141 @@ +import json +from pytezos import pytezos, PyTezosClient +from scripts.contract_type import ContractType +from tests.helpers.contracts.sequencer_governance import SequencerGovernance +from tests.helpers.contracts.kernel_governance import KernelGovernance +from typing import Optional +import click +from scripts.environment import load_or_ask +from tests.helpers.metadata import Metadata +from tests.helpers.utility import normalize_params, validate_percent_value +from scripts.metadata import metadata_by_contract_type + +@click.command() +@click.option( + '--contract', + required=True, + help='"kernel_governance" or "sequencer_governance"', +) +@click.option( + '--period_length', + required=True, + help='The proposal and promotion period life-time counted in blocks', +) +@click.option( + '--adoption_period_sec', + required=True, + help='The duration of the l2 adoption period counted in seconds', +) +@click.option( + '--upvoting_limit', + required=True, + help='The max number of new active proposals for each account', +) +@click.option( + '--proposal_quorum_percent', + required=True, + help='The min proposal proposal_quorum to move the proposal to next promotion phase. Range: [0, 100]', +) +@click.option( + '--promotion_quorum_percent', + required=True, + help='The min promotion_quorum for the proposal to be considered as a winner. Range: [0, 100]', +) +@click.option( + '--promotion_supermajority_percent', + required=True, + help='The min promotion_supermajority for the proposal be considered as a winner. Range: [0, 100]', +) +@click.option('--private-key', default=None, help='Use the provided private key.') +@click.option('--rpc-url', default=None, help='Tezos RPC URL.') +def deploy_contract( + contract: str, + period_length: str, + adoption_period_sec: str, + upvoting_limit: str, + proposal_quorum_percent: str, + promotion_quorum_percent: str, + promotion_supermajority_percent: str, + private_key: Optional[str], + rpc_url: Optional[str], +) -> KernelGovernance: + """Deploys a governance contract using provided key as a manager""" + + contract_type = ContractType[contract] + period_length = int(period_length) + adoption_period_sec = int(adoption_period_sec) + upvoting_limit = int(upvoting_limit) + proposal_quorum = float(proposal_quorum_percent) + promotion_quorum = float(promotion_quorum_percent) + promotion_supermajority = float(promotion_supermajority_percent) + + validate_percent_value(proposal_quorum) + validate_percent_value(promotion_quorum) + validate_percent_value(promotion_supermajority) + + private_key = private_key or load_or_ask('PRIVATE_KEY', is_secret=True) + rpc_url = rpc_url or load_or_ask('RPC_URL') + + manager = pytezos.using(shell=rpc_url, key=private_key) + blockchain_info = get_blockchain_info(manager) + protocol_voting_period_length = blockchain_info['protocol_voting_period_length'] + protocol_voting_started_at_level = blockchain_info['protocol_voting_started_at_level'] + + print('') + print('blockchain_info:', json.dumps(blockchain_info, indent=4)) + + if (protocol_voting_period_length % period_length) != 0: + raise Exception(f'Period length is incorrect, it must be a divisor of the length of the Tezos protocol voting period length. protocol_period_length={protocol_voting_period_length}, period_length={period_length}') + + normalized_params = normalize_params([100, proposal_quorum, promotion_quorum, promotion_supermajority]) + [scale, proposal_quorum, promotion_quorum, promotion_supermajority] = normalized_params + metadata = metadata_by_contract_type[contract_type] + + config = { + 'started_at_level': protocol_voting_started_at_level, + 'period_length': period_length, + 'adoption_period_sec': adoption_period_sec, + 'upvoting_limit': upvoting_limit, + 'scale': scale, + 'proposal_quorum': proposal_quorum, + 'promotion_quorum': promotion_quorum, + 'promotion_supermajority': promotion_supermajority, + } + + print('') + print('smart_contact_config:', json.dumps(config, indent=4)) + + print('') + print('smart_contact_metadata:', json.dumps(metadata, indent=4)) + + print('') + if not click.confirm('Do you want to originate the smart contract?', default=True): + return + + opg = originate_contract(contract_type, manager, config, metadata) + manager.wait(opg) + kernelGovernance = KernelGovernance.from_opg(manager, opg) + return kernelGovernance + +def get_blockchain_info(manager: PyTezosClient) -> dict: + info = manager.shell.head.metadata() + current_level = int(info['level_info']['level']) + protocol_voting_position = int(info['voting_period_info']['position']) + protocol_voting_started_at_level = current_level - protocol_voting_position + protocol_voting_period_length = protocol_voting_position + int(info['voting_period_info']['remaining']) + 1 + + return { + 'rpc_url': manager.shell.node.uri[0], + 'current_level': current_level, + 'protocol_voting_period_length': protocol_voting_period_length, + 'protocol_voting_position': protocol_voting_position, + 'protocol_voting_started_at_level': protocol_voting_started_at_level + } + +def originate_contract(contract_type: ContractType, manager: PyTezosClient, config: dict, metadata: dict): + if contract_type in [ContractType.kernel_regular_governance, ContractType.kernel_security_governance]: + return KernelGovernance.originate(manager, config, metadata).send() + elif contract_type == ContractType.sequencer_governance: + return SequencerGovernance.originate(manager, config, metadata).send() + else: + raise ValueError("Incorrect contract_type") diff --git a/etherlink/tezos_contracts/governance/scripts/metadata.py b/etherlink/tezos_contracts/governance/scripts/metadata.py new file mode 100644 index 000000000000..f9bf4057904e --- /dev/null +++ b/etherlink/tezos_contracts/governance/scripts/metadata.py @@ -0,0 +1,29 @@ +from scripts.contract_type import ContractType + +base_template = { + 'version': '0.1.0', + 'interfaces': ['TZIP-016'], + 'license': {'name': 'MIT'}, + 'homepage': 'https://www.etherlink.com', +} + +kernel_regular_governance_metadata = base_template | { + 'name': 'Etherlink Kernel Governance', + 'description': 'The contract allows bakers to make proposals and vote on the kernel upgrade (kernel hash)', +} + +kernel_security_governance_metadata = base_template | { + 'name': 'Etherlink Kernel Security Governance', + 'description': 'The contract allows bakers to make proposals and vote on the security kernel upgrade (kernel hash)', +} + +sequencer_governance_metadata = base_template | { + 'name': 'Etherlink Sequencer Committee Governance', + 'description': 'The contract allows bakers to make proposals and vote on the sequencer operator', +} + +metadata_by_contract_type = { + ContractType.kernel_regular_governance: kernel_regular_governance_metadata, + ContractType.kernel_security_governance: kernel_security_governance_metadata, + ContractType.sequencer_governance: sequencer_governance_metadata, +} \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/__init__.py b/etherlink/tezos_contracts/governance/tests/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/base.py b/etherlink/tezos_contracts/governance/tests/base.py new file mode 100644 index 000000000000..b8b5f6e091ff --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/base.py @@ -0,0 +1,93 @@ +from pytezos.client import PyTezosClient +from pytezos.sandbox.node import SandboxedNodeTestCase +from tests.helpers.contracts import ( + KernelGovernance, +) +from typing import Optional +from pytezos.rpc import RpcError +from contextlib import contextmanager +from tests.helpers.contracts.internal_test_proxy import InternalTestProxy +from tests.helpers.contracts.rollup_mock import RollupMock +from tests.helpers.contracts.sequencer_governance import SequencerGovernance +from tests.helpers.utility import pkh +from pytezos.contract.result import ContractCallResult +from pytezos.operation.group import OperationGroup + +class BaseTestCase(SandboxedNodeTestCase): + accounts: list = [] + + def setUp(self) -> None: + self.accounts = [] + self.manager = self.bootstrap_baker() + + def get_current_level(self) -> int: + return self.client.shell.head.header()['level'] + + def bootstrap_baker(self, n: Optional[int] = None) -> PyTezosClient: + """Creates baker with given number""" + + accounts_count = n or len(self.accounts) + bootstrap: PyTezosClient = self.client.using(key=f'bootstrap{accounts_count + 1}') + bootstrap.reveal() + self.accounts.append(bootstrap) + return bootstrap + + def bootstrap_no_baker(self) -> PyTezosClient: + """Creates no baker account""" + + no_baker = self.client.using(key='alice') + if no_baker.balance() == 0: + donor = self.manager + donor.transaction(destination=pkh(no_baker), amount=100000000000).autofill().sign().inject() + self.bake_block() + no_baker.reveal().autofill().sign().inject() + return no_baker + + def deploy_rollup_mock(self) -> RollupMock: + """Deploys Rollup Mock contract""" + + opg = RollupMock.originate(self.manager).send() + self.bake_block() + return RollupMock.from_opg(self.manager, opg) + + def deploy_internal_test_proxy(self) -> InternalTestProxy: + """Deploys Internal Test Proxy contract""" + + opg = InternalTestProxy.originate(self.manager).send() + self.bake_block() + return InternalTestProxy.from_opg(self.manager, opg) + + def deploy_kernel_governance(self, custom_config=None) -> KernelGovernance: + """Deploys Kernel Governance contract""" + + opg = KernelGovernance.originate(self.manager, custom_config).send() + self.bake_block() + return KernelGovernance.from_opg(self.manager, opg) + + def deploy_sequencer_governance(self, custom_config=None) -> SequencerGovernance: + """Deploys Committee Governance contract""" + + opg = SequencerGovernance.originate(self.manager, custom_config).send() + self.bake_block() + return SequencerGovernance.from_opg(self.manager, opg) + + @contextmanager + def raisesMichelsonError(self, error_message): + """Asserts that instruction fails in smart contract with the specified error""" + with self.assertRaises(RpcError) as r: + yield r + + failed_with = self.extract_runtime_failwith(r.exception) + self.assertEqual(error_message, failed_with) + + def extract_runtime_failwith(self, e: RpcError): + return e.args[-1]['with']['string'] + + def bake_block_and_get_operation_result(self, opg: OperationGroup) -> ContractCallResult: + self.bake_block() + opg = self.client.shell.blocks['head':].find_operation(opg.hash()) + return ContractCallResult.from_operation_group(opg)[0] + + def bake_blocks(self, count: int): + for _ in range(count): + self.bake_block() \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/common/__init__.py b/etherlink/tezos_contracts/governance/tests/common/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/common/internal/__init__.py b/etherlink/tezos_contracts/governance/tests/common/internal/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/common/internal/test_address_to_key_hash.py b/etherlink/tezos_contracts/governance/tests/common/internal/test_address_to_key_hash.py new file mode 100644 index 000000000000..17f4aaa2c922 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/common/internal/test_address_to_key_hash.py @@ -0,0 +1,17 @@ +from tests.base import BaseTestCase +from tests.helpers.errors import NOT_IMPLICIT_ADDRESS + +class PayloadDecorationTestCase(BaseTestCase): + def test_address_to_key_hash(self) -> None: + proxy = self.deploy_internal_test_proxy() + + assert proxy.address_to_key_hash('tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx') == 'tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx' + assert proxy.address_to_key_hash('tz2VGBaXuS6rnaa5hpC92qkgadRJKdEbeGwc') == 'tz2VGBaXuS6rnaa5hpC92qkgadRJKdEbeGwc' + assert proxy.address_to_key_hash('tz3WEJYwJ6pPwVbSL8FrSoAXRmFHHZTuEnMA') == 'tz3WEJYwJ6pPwVbSL8FrSoAXRmFHHZTuEnMA' + assert proxy.address_to_key_hash('tz4Jxn8MpRndqWUzkuZbQKmE3aNWJzYsSEso') == 'tz4Jxn8MpRndqWUzkuZbQKmE3aNWJzYsSEso' + + with self.raisesMichelsonError(NOT_IMPLICIT_ADDRESS): + proxy.address_to_key_hash('KT1ThEdxfUcWUwqsdergy3QnbCWGHSUHeHJq') + + with self.raisesMichelsonError(NOT_IMPLICIT_ADDRESS): + proxy.address_to_key_hash('sr1EStimadnRRA3vnjpWV1RwNAsDbM3JaDt6') \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/common/internal/test_normalize_params.py b/etherlink/tezos_contracts/governance/tests/common/internal/test_normalize_params.py new file mode 100644 index 000000000000..f5458bf115b0 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/common/internal/test_normalize_params.py @@ -0,0 +1,13 @@ +from tests.base import BaseTestCase +from tests.helpers.utility import normalize_params + +class NormalizeParamsTestCase(BaseTestCase): + def test_normalize_params(self) -> None: + assert normalize_params([100, 1, 2, 3]) == [100, 1, 2, 3] + assert normalize_params([100, 1.0, 2.00, 3.000]) == [100, 1, 2, 3] + assert normalize_params([100, 1.0, 2, 3]) == [100, 1, 2, 3] + assert normalize_params([100, 0.1, 2, 3]) == [1000, 1, 20, 30] + assert normalize_params([100, 5.1, 25, 33.123]) == [100000, 5100, 25000, 33123] + assert normalize_params([100, 1, 0.02, 3]) == [10000, 100, 2, 300] + assert normalize_params([100, 1, 2, 0.003]) == [100000, 1000, 2000, 3] + assert normalize_params([100, 0.1, 0.02, 0.003]) == [100000, 100, 20, 3] diff --git a/etherlink/tezos_contracts/governance/tests/common/internal/test_payload_decoration.py b/etherlink/tezos_contracts/governance/tests/common/internal/test_payload_decoration.py new file mode 100644 index 000000000000..ad8c3b31f501 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/common/internal/test_payload_decoration.py @@ -0,0 +1,39 @@ +from tests.base import BaseTestCase + +class PayloadDecorationTestCase(BaseTestCase): + def test_kernel_upgrade_payload_decoration(self) -> None: + proxy = self.deploy_internal_test_proxy() + + kernel_root_hash = bytes.fromhex('009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606abc') + activation_timestamp = 1708444800 + + expected_upgrade_payload = 'eba1009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606abc8880ccd46500000000' + assert proxy.get_kernel_upgrade_payload(kernel_root_hash, activation_timestamp).hex() == expected_upgrade_payload + + def test_sequencer_upgrade_payload_decoration(self) -> None: + proxy = self.deploy_internal_test_proxy() + + sequencer_pk = 'edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav' + pool_address = '71c7656ec7ab88b098defb751b7401b5f6d8976f' + activation_timestamp = 1709355827 + expected_upgrade_payload = 'f855b66564706b75426b6e5732386e5737324b4736526f48745957377031325436474b63376e4162775958356d3857643973445643397961769471c7656ec7ab88b098defb751b7401b5f6d8976f8833b3e26500000000' + assert proxy.get_sequencer_upgrade_payload(sequencer_pk, pool_address, activation_timestamp).hex() == expected_upgrade_payload + + sequencer_pk = 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X' + pool_address = 'B7A97043983f24991398E5a82f63F4C58a417185' + activation_timestamp = 1709089500 + expected_upgrade_payload = 'f855b66564706b7572636761665a3255527942367a736d35643159716d4c743972314c6b38394a38314e364b70794d61557a5857457376315894b7a97043983f24991398e5a82f63f4c58a41718588dca2de6500000000' + assert proxy.get_sequencer_upgrade_payload(sequencer_pk, pool_address, activation_timestamp).hex() == expected_upgrade_payload + + sequencer_pk = 'sppk7ZZ62L7f1dep7ddYNhM2vsNuzouGzCrv9CRsxmJ6q4Cavys2fsk' + pool_address = 'B7A97043983f24991398E5a82f63F4C58a417185' + activation_timestamp = 1709175900 + expected_upgrade_payload = 'f856b77370706b375a5a36324c376631646570376464594e684d3276734e757a6f75477a43727639435273786d4a36713443617679733266736b94b7a97043983f24991398e5a82f63f4c58a417185885cf4df6500000000' + assert proxy.get_sequencer_upgrade_payload(sequencer_pk, pool_address, activation_timestamp).hex() == expected_upgrade_payload + + sequencer_pk = 'p2pk65aQziqHmuSpoEtEfaMRL4MwBMrSYQYoF3BCebocBKkg1shLepb' + pool_address = 'B7A97043983f24991398E5a82f63F4C58a417185' + activation_timestamp = 1909175900 + expected_upgrade_payload = 'f856b77032706b363561517a6971486d7553706f45744566614d524c344d77424d72535951596f4633424365626f63424b6b673173684c65706294b7a97043983f24991398e5a82f63f4c58a417185885cb6cb7100000000' + assert proxy.get_sequencer_upgrade_payload(sequencer_pk, pool_address, activation_timestamp).hex() == expected_upgrade_payload + \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/common/test_gas_consumption.py b/etherlink/tezos_contracts/governance/tests/common/test_gas_consumption.py new file mode 100644 index 000000000000..0116574f4a51 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/common/test_gas_consumption.py @@ -0,0 +1,195 @@ +import secrets +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import YEA_VOTE +from tests.helpers.operation_result_recorder import OperationResultRecorder +from tests.helpers.utility import find_op_by_hash, get_tests_dir, pkh +from pytezos.operation.result import OperationResult +from os.path import join + +class KernelGovernanceGasConsumptionTestCase(BaseTestCase): + recorder = OperationResultRecorder() + + @classmethod + def tearDownClass(self) -> None: + self.recorder.write_to_file(join(get_tests_dir(), 'gas_consumption.json')) + super().tearDownClass() + + def test_new_proposal_same_baker(self) -> None: + baker = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 500, + 'upvoting_limit': 500, + }) + + for i in range(4): + random_bytes = secrets.token_bytes(33) + opg = governance.using(baker).new_proposal(random_bytes).send() + self.bake_block() + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'new_proposal_same_baker_nth_{i + 1}', op) + + def test_new_proposal_different_baker(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + baker4 = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 500, + 'upvoting_limit': 500, + }) + + for i, baker in enumerate([baker1, baker2, baker3, baker4]): + random_bytes = secrets.token_bytes(33) + opg = governance.using(baker).new_proposal(random_bytes).send() + self.bake_block() + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'new_proposal_different_baker_nth_{i + 1}', op) + + def test_new_proposal_with_event(self) -> None: + baker1 = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20, # 1 baker out of 5 will vote, + 'promotion_quorum': 20, # 1 bakers out of 5 will vote (20%) + 'promotion_supermajority': 50, # 1 baker will vote yea + }) + + random_bytes = secrets.token_bytes(33) + governance.using(baker1).new_proposal(random_bytes).send() + self.bake_blocks(2) + + governance.using(baker1).vote(YEA_VOTE).send() + self.bake_blocks(2) + + opg = governance.using(baker1).new_proposal(secrets.token_bytes(33)).send() + self.bake_block() + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'test_new_proposal_with_event', op) + + def test_upvote_proposal(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + baker4 = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 500, + }) + + random_bytes = secrets.token_bytes(33) + governance.using(baker1).new_proposal(random_bytes).send() + self.bake_block() + + for i, baker in enumerate([baker2, baker3, baker4]): + opg = governance.using(baker).upvote_proposal(random_bytes).send() + self.bake_block() + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'upvote_nth_{i + 1}', op) + + def test_vote_proposal(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + baker4 = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 10, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + random_bytes = secrets.token_bytes(33) + governance.using(baker1).new_proposal(random_bytes).send() + self.bake_blocks(11) + + for i, baker in enumerate([baker1, baker2, baker3, baker4]): + opg = governance.using(baker).vote(YEA_VOTE).send() + self.bake_block() + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'vote_nth_{i + 1}', op) + + def test_new_proposal_with_a_lot_of_proposals_on_previous_voting_period(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + def run_test(prev_voting_proposal_count): + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': prev_voting_proposal_count + 2, + 'upvoting_limit': 500, + 'proposal_quorum': 20, # 1 baker out of 5 will vote, + 'promotion_quorum': 20, # 1 bakers out of 5 will vote (20%) + 'promotion_supermajority': 50, # 1 baker will vote yea + }) + + random_bytes = secrets.token_bytes(33) + governance.using(baker1).new_proposal(random_bytes).send() + self.bake_block() + governance.using(baker2).upvote_proposal(random_bytes).send() + self.bake_block() + for i in range(prev_voting_proposal_count): + governance.using(baker1).new_proposal(secrets.token_bytes(33)).send() + self.bake_block() + + governance.using(baker1).vote(YEA_VOTE).send() + self.bake_blocks(prev_voting_proposal_count + 2) + + opg = governance.using(baker1).new_proposal(secrets.token_bytes(33)).send() + self.bake_block() + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'new_proposal_with_{prev_voting_proposal_count}_proposals_on_previous_voting_period', op) + + for i, prev_voting_proposal_count in enumerate([10, 50, 100]): + run_test(prev_voting_proposal_count) + + def test_trigger_upgrade(self) -> None: + baker = self.bootstrap_baker() + rollup_mock1 = self.deploy_rollup_mock() + rollup_mock2 = self.deploy_rollup_mock() + rollup_mock3 = self.deploy_rollup_mock() + rollup_mock4 = self.deploy_rollup_mock() + rollup_mock5 = self.deploy_rollup_mock() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 6, + 'proposal_quorum': 20, + 'promotion_quorum': 20, + 'promotion_supermajority': 20, + }) + + kernel_root_hash = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_blocks(7) + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(7) + + for i, mock in enumerate([rollup_mock1, rollup_mock2, rollup_mock3, rollup_mock4, rollup_mock5]): + opg = governance.using(baker).trigger_kernel_upgrade(mock.contract.address).send() + self.bake_blocks(10) + op = find_op_by_hash(self.manager, opg) + self.recorder.add_element(f'trigger_upgrade_nth_{i + 1}', op) + + # def test_new_proposal_stress(self) -> None: + # baker = self.bootstrap_baker() + # governance_started_at_level = self.get_current_level() + 1 + # governance = self.deploy_kernel_governance(custom_config={ + # 'started_at_level': governance_started_at_level, + # 'period_length': 5000, + # 'upvoting_limit': 5000, + # }) + + # for i in range(5000): + # random_bytes = secrets.token_bytes(33) + # opg = governance.using(baker).new_proposal(random_bytes).send() + # self.bake_block() + # op = find_op_by_hash(self.manager, opg) + # consumed_gas = OperationResult.consumed_gas(op) + # print('new proposal: ', i, 'consumed_gas', consumed_gas) \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/common/test_promotion_period.py b/etherlink/tezos_contracts/governance/tests/common/test_promotion_period.py new file mode 100644 index 000000000000..f11b04380801 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/common/test_promotion_period.py @@ -0,0 +1,345 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import NAY_VOTE, PASS_VOTE, PROMOTION_PERIOD, PROPOSAL_PERIOD, YEA_VOTE +from tests.helpers.contracts.kernel_governance import KernelGovernance +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER +from pytezos.client import PyTezosClient + +class KernelGovernancePromotionPeriodTestCase(BaseTestCase): + def prepare_promotion_period(self, custom_config=None): + proposer = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + config = { + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 10 # 1 bakers out of 5 voted + } + if custom_config is not None: + config.update(custom_config) + + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config=config) + assert self.get_current_level() == governance_started_at_level + + # Period index: 0. Block: 2 of 3 + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(proposer).new_proposal(kernel_root_hash).send() + self.bake_block() + + self.bake_blocks(2) + + # Period index: 1. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': None + } + + return { + 'governance': governance, + 'proposer': proposer, + 'kernel_root_hash': kernel_root_hash + } + + def test_should_reset_to_proposal_period_if_promotion_period_is_skipped(self) -> None: + test = self.prepare_promotion_period() + governance: KernelGovernance = test['governance'] + kernel_root_hash = test['kernel_root_hash'] + + # Wait to skip the whole promotion period + self.bake_blocks(3) + # Period index: 2. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + # Wait to skip one more period + self.bake_blocks(3) + # Period index: 3. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 3, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_to_proposal_period_if_promotion_quorum_is_not_reached(self) -> None: + test = self.prepare_promotion_period({ + 'promotion_quorum': 50, # 2 bakers out of 5 will vote (40%) + 'promotion_supermajority': 10, # 1 baker will vote yea, 1 baker will vote nay (50%) + }) + governance: KernelGovernance = test['governance'] + proposer: PyTezosClient = test['proposer'] + kernel_root_hash = test['kernel_root_hash'] + baker1 = self.bootstrap_baker() + + # Period index: 1. Block: 2 of 3 + governance.using(proposer).vote(YEA_VOTE).send() + governance.using(baker1).vote(NAY_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Wait to skip one more period + self.bake_blocks(2) + # Period index: 2. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_to_proposal_period_if_promotion_supermajority_is_not_reached(self) -> None: + test = self.prepare_promotion_period({ + 'promotion_quorum': 50, # 3 bakers out of 5 will vote (60%) + 'promotion_supermajority': 51, # 1 baker will vote yea, 1 baker will vote nay (50%) + }) + governance: KernelGovernance = test['governance'] + proposer: PyTezosClient = test['proposer'] + kernel_root_hash = test['kernel_root_hash'] + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + + # Period index: 1. Block: 2 of 3 + governance.using(proposer).vote(YEA_VOTE).send() + governance.using(baker1).vote(NAY_VOTE).send() + governance.using(baker2).vote(PASS_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Wait to skip one more period + self.bake_blocks(2) + # Period index: 2. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_to_proposal_period_if_promotion_phase_has_only_pass_votes(self) -> None: + test = self.prepare_promotion_period({ + 'promotion_quorum': 50, # 1 bakers out of 5 will vote (20%) + 'promotion_supermajority': 51, # 1 baker will vote pass) + }) + governance: KernelGovernance = test['governance'] + kernel_root_hash = test['kernel_root_hash'] + baker2 = self.bootstrap_baker() + + # Period index: 1. Block: 2 of 3 + governance.using(baker2).vote(PASS_VOTE).send() + self.bake_block() + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Wait to skip one more period + self.bake_blocks(2) + # Period index: 2. Block: 1 of 3 + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_to_proposal_period_if_promotion_phase_has_only_pass_votes_which_passes_only_promotion_quorum(self) -> None: + test = self.prepare_promotion_period({ + 'promotion_quorum': 20, # 1 bakers out of 5 will vote (20%) + 'promotion_supermajority': 51, # 1 baker will vote pass + }) + governance: KernelGovernance = test['governance'] + kernel_root_hash = test['kernel_root_hash'] + baker2 = self.bootstrap_baker() + + # Period index: 1. Block: 2 of 3 + governance.using(baker2).vote(PASS_VOTE).send() + self.bake_block() + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Wait to skip one more period + self.bake_blocks(2) + # Period index: 2. Block: 1 of 3 + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + + def test_should_reset_to_proposal_period_with_a_new_winner_and_event_if_promotion_period_passed_successfully(self) -> None: + test = self.prepare_promotion_period({ + 'promotion_quorum': 50, # 3 bakers out of 5 will vote (60%) + 'promotion_supermajority': 40, # 1 baker will vote yea, 1 baker will vote nay (50%) + }) + governance: KernelGovernance = test['governance'] + proposer: PyTezosClient = test['proposer'] + kernel_root_hash = test['kernel_root_hash'] + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + + # Period index: 1. Block: 2 of 3 + governance.using(proposer).vote(YEA_VOTE).send() + governance.using(baker1).vote(NAY_VOTE).send() + governance.using(baker2).vote(PASS_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Wait to skip one more period + self.bake_blocks(2) + # Period index: 2. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': kernel_root_hash + } + } + + # Check that event preserves in future periods + self.bake_blocks(6) + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 4, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': kernel_root_hash + } + } diff --git a/etherlink/tezos_contracts/governance/tests/common/test_proposal_period.py b/etherlink/tezos_contracts/governance/tests/common/test_proposal_period.py new file mode 100644 index 000000000000..6e5cd18aef0f --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/common/test_proposal_period.py @@ -0,0 +1,372 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import PROPOSAL_PERIOD, PROMOTION_PERIOD +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER + +class KernelGovernanceProposalPeriodTestCase(BaseTestCase): + def test_should_reset_proposals_when_no_proposals(self) -> None: + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3 + }) + assert self.get_current_level() == governance_started_at_level + + storage = governance.contract.storage() + assert storage['voting_context'] == None + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 3, + 'finished_voting': None + } + + self.bake_block() + # Period index: 0. Block: 2 of 3 + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 2, + 'finished_voting': None + } + + self.bake_block() + # Period index: 0. Block: 3 of 3 + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } + + self.bake_block() + # Period index: 1. Block: 1 of 3 + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': None + } + + self.bake_block() + # Period index: 1. Block: 2 of 3 + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + self.bake_blocks(10) + # Period index: 4. Block: 3 of 3 + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 4, + 'remaining_blocks': 1, + 'finished_voting': None + } + + def test_should_reset_proposals_when_period_is_finished_with_no_votes_except_proposer(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 40 # 1 baker out of 5 will vote + }) + assert self.get_current_level() == governance_started_at_level + + # Period index: 0. Block: 2 of 2 + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } + + self.bake_block() + # Period index: 1. Block: 1 of 2 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': { + 'finished_at_period_index': 1, + 'finished_at_period_type': PROPOSAL_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_proposals_when_period_is_finished_with_not_enough_votes(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 60 # 2 bakers out of 5 will vote + }) + assert self.get_current_level() == governance_started_at_level + + # Period index: 0. Block: 2 of 3 + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 0. Block: 3 of 3 + governance.using(baker2).upvote_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } + + self.bake_block() + + # Period index: 1. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 1, + 'finished_at_period_type': PROPOSAL_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_proposals_when_period_is_finished_with_2_winners(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 20 # 1 bakers out of 5 will vote for each proposal + }) + assert self.get_current_level() == governance_started_at_level + + # Period index: 0. Block: 2 of 3 + kernel_root_hash1 = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(baker1).new_proposal(kernel_root_hash1).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash1 + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 0. Block: 3 of 3 + kernel_root_hash2 = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + governance.using(baker2).new_proposal(kernel_root_hash2).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == None + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } + + self.bake_block() + + # Period index: 1. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == None + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 1, + 'finished_at_period_type': PROPOSAL_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_reset_proposals_when_promotion_period_is_skipped(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 40 # 2 bakers out of 5 voted + }) + assert self.get_current_level() == governance_started_at_level + + # Period index: 0. Block: 2 of 3 + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 0. Block: 3 of 3 + governance.using(baker2).upvote_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } + + self.bake_blocks(4) + + # Period index: 2. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 2, + 'remaining_blocks': 3, + 'finished_voting': { + 'finished_at_period_index': 2, + 'finished_at_period_type': PROMOTION_PERIOD, + 'winner_proposal_payload': None + } + } + + def test_should_prolong_to_promotion_when_proposal_period_is_finished_with_a_winner(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 40 # 2 bakers out of 5 voted + }) + assert self.get_current_level() == governance_started_at_level + + # Period index: 0. Block: 2 of 3 + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 0. Block: 3 of 3 + governance.using(baker2).upvote_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } + + self.bake_block() + + # Period index: 1. Block: 1 of 3 + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': None + } diff --git a/etherlink/tezos_contracts/governance/tests/gas_consumption.json b/etherlink/tezos_contracts/governance/tests/gas_consumption.json new file mode 100644 index 000000000000..42b994a2010c --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/gas_consumption.json @@ -0,0 +1,98 @@ +{ + "new_proposal_different_baker_nth_1": { + "consumed_gas": 5410, + "paid_storage_size_diff": 409 + }, + "new_proposal_different_baker_nth_2": { + "consumed_gas": 2022, + "paid_storage_size_diff": 197 + }, + "new_proposal_different_baker_nth_3": { + "consumed_gas": 2022, + "paid_storage_size_diff": 235 + }, + "new_proposal_different_baker_nth_4": { + "consumed_gas": 2022, + "paid_storage_size_diff": 235 + }, + "new_proposal_same_baker_nth_1": { + "consumed_gas": 5410, + "paid_storage_size_diff": 409 + }, + "new_proposal_same_baker_nth_2": { + "consumed_gas": 2483, + "paid_storage_size_diff": 130 + }, + "new_proposal_same_baker_nth_3": { + "consumed_gas": 2483, + "paid_storage_size_diff": 168 + }, + "new_proposal_same_baker_nth_4": { + "consumed_gas": 2483, + "paid_storage_size_diff": 168 + }, + "new_proposal_with_10_proposals_on_previous_voting_period": { + "consumed_gas": 1650, + "paid_storage_size_diff": 0 + }, + "new_proposal_with_50_proposals_on_previous_voting_period": { + "consumed_gas": 1650, + "paid_storage_size_diff": 0 + }, + "new_proposal_with_100_proposals_on_previous_voting_period": { + "consumed_gas": 1651, + "paid_storage_size_diff": 0 + }, + "test_new_proposal_with_event": { + "consumed_gas": 1651, + "paid_storage_size_diff": 75 + }, + "trigger_upgrade_nth_1": { + "consumed_gas": 2637, + "paid_storage_size_diff": 43 + }, + "trigger_upgrade_nth_2": { + "consumed_gas": 2766, + "paid_storage_size_diff": 43 + }, + "trigger_upgrade_nth_3": { + "consumed_gas": 2766, + "paid_storage_size_diff": 43 + }, + "trigger_upgrade_nth_4": { + "consumed_gas": 2766, + "paid_storage_size_diff": 107 + }, + "trigger_upgrade_nth_5": { + "consumed_gas": 2766, + "paid_storage_size_diff": 111 + }, + "upvote_nth_1": { + "consumed_gas": 2486, + "paid_storage_size_diff": 134 + }, + "upvote_nth_2": { + "consumed_gas": 2486, + "paid_storage_size_diff": 134 + }, + "upvote_nth_3": { + "consumed_gas": 2486, + "paid_storage_size_diff": 134 + }, + "vote_nth_1": { + "consumed_gas": 1063, + "paid_storage_size_diff": 0 + }, + "vote_nth_2": { + "consumed_gas": 1080, + "paid_storage_size_diff": 0 + }, + "vote_nth_3": { + "consumed_gas": 1080, + "paid_storage_size_diff": 0 + }, + "vote_nth_4": { + "consumed_gas": 1080, + "paid_storage_size_diff": 0 + } +} \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/helpers/__init__.py b/etherlink/tezos_contracts/governance/tests/helpers/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/__init__.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/__init__.py new file mode 100644 index 000000000000..baefb5f54e22 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/__init__.py @@ -0,0 +1,17 @@ +from tests.helpers.contracts.kernel_governance import KernelGovernance +from tests.helpers.contracts.sequencer_governance import SequencerGovernance +from tests.helpers.contracts.rollup_mock import RollupMock +from tests.helpers.contracts.internal_test_proxy import InternalTestProxy +from tests.helpers.contracts.contract import ContractHelper +from tests.helpers.contracts.governance_base import GovernanceBase + + +# Allowing reimporting from this module: +__all__ = [ + 'KernelGovernance', + 'ContractHelper', + 'GovernanceBase', + 'SequencerGovernance', + 'RollupMock', + 'InternalTestProxy', +] diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/contract.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/contract.py new file mode 100644 index 000000000000..53d5a37173e7 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/contract.py @@ -0,0 +1,67 @@ +from pytezos.contract.interface import ContractInterface +from pytezos.client import PyTezosClient +from pytezos.operation.group import OperationGroup +from dataclasses import dataclass, replace +from tests.helpers.utility import ( + load_contract_from_address, + find_op_by_hash, + get_address_from_op, +) +from typing import TypeVar, Type, Any +from abc import ABC + + +T = TypeVar('T', bound='ContractHelper') + + +@dataclass +class ContractHelper(ABC): + contract: ContractInterface + client: PyTezosClient + address: str + + @classmethod + def from_opg( + cls: Type[T], + client: PyTezosClient, + opg: OperationGroup, + **init_params: Any, + ) -> T: + """Creates ContractHelper from given operation group + with given client""" + + op = find_op_by_hash(client, opg) + address = get_address_from_op(op) + print(f'found contract address: {address}') + + return cls( + contract=load_contract_from_address(client, address), + client=client, + address=address, + **init_params, + ) + + def using(self: T, client: PyTezosClient) -> T: + """Returns new ContractHelper with updated client""" + + return replace( + self, + client=client, + contract=client.contract(self.contract.address), + ) + + @classmethod + def from_address( + cls: Type[T], + client: PyTezosClient, + address: str, + **init_params: Any, + ) -> T: + """Loads contract from given address using given client""" + + return cls( + contract=client.contract(address), + client=client, + address=address, + **init_params, + ) diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/governance_base.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/governance_base.py new file mode 100644 index 000000000000..53b34beaf207 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/governance_base.py @@ -0,0 +1,38 @@ +from tests.helpers.contracts.contract import ContractHelper +from typing import ( + Any, +) + +PROPOSAL_PERIOD = 'proposal' +PROMOTION_PERIOD = 'promotion' + +YEA_VOTE = 'yea' +NAY_VOTE = 'nay' +PASS_VOTE = 'pass' + +class GovernanceBase(ContractHelper): + @staticmethod + def make_storage(metadata: dict[str, Any], custom_config=None, last_winner=None) -> dict[str, Any]: + config = { + 'started_at_level': 0, + 'period_length': 10, + 'adoption_period_sec': 60, + 'upvoting_limit': 20, + 'scale': 100, + 'proposal_quorum': 80, + 'promotion_quorum': 80, + 'promotion_supermajority': 80, + } + + if custom_config is not None: + config.update(custom_config) + + return { + 'config': config, + 'voting_context': None, + 'last_winner': last_winner, + 'metadata': metadata + } + + def get_voting_state(self): + return self.contract.get_voting_state().run_view() \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/internal_test_proxy.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/internal_test_proxy.py new file mode 100644 index 000000000000..948a25dd3a29 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/internal_test_proxy.py @@ -0,0 +1,26 @@ +from pytezos.client import PyTezosClient +from tests.helpers.contracts.contract import ContractHelper +from tests.helpers.utility import ( + get_build_dir, + originate_from_file, +) +from pytezos.operation.group import OperationGroup +from os.path import join + + +class InternalTestProxy(ContractHelper): + @classmethod + def originate(self, client: PyTezosClient) -> OperationGroup: + storage = None + filename = join(get_build_dir(), 'test/internal_test_proxy.tz') + + return originate_from_file(filename, client, storage) + + def get_kernel_upgrade_payload(self, kernel_root_hash : bytes, activation_timestamp : int): + return self.contract.get_kernel_upgrade_payload(kernel_root_hash, activation_timestamp).run_view() + + def get_sequencer_upgrade_payload(self, sequencer_pk : str, pool_address : bytes, activation_timestamp : int): + return self.contract.get_sequencer_upgrade_payload(sequencer_pk, pool_address, activation_timestamp).run_view() + + def address_to_key_hash(self, address : str): + return self.contract.address_to_key_hash(address).run_view() \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/kernel_governance.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/kernel_governance.py new file mode 100644 index 000000000000..483c7c4f9493 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/kernel_governance.py @@ -0,0 +1,46 @@ +from pytezos.client import PyTezosClient +from tests.helpers.contracts.governance_base import GovernanceBase +from tests.helpers.utility import ( + get_build_dir, + originate_from_file, +) +from pytezos.operation.group import OperationGroup +from pytezos.contract.call import ContractCall +from os.path import join +from tests.helpers.metadata import Metadata + + +class KernelGovernance(GovernanceBase): + @classmethod + def originate(self, client: PyTezosClient, custom_config=None, metadata=None) -> OperationGroup: + """Deploys Kernel Governance""" + + metadata = metadata if metadata != None else dict() + metadata = Metadata.make_default(**metadata) + storage = self.make_storage(metadata, custom_config=custom_config) + filename = join(get_build_dir(), 'kernel_governance.tz') + + return originate_from_file(filename, client, storage) + + + def trigger_kernel_upgrade(self, rollup_address : str) -> ContractCall: + """Triggers kernel upgrade transaction to rollup with last winner kernel hash""" + + return self.contract.trigger_kernel_upgrade(rollup_address) + + + def new_proposal(self, kernel_root_hash : bytes) -> ContractCall: + """Creates a new proposal""" + + return self.contract.new_proposal(kernel_root_hash) + + + def upvote_proposal(self, kernel_root_hash : bytes) -> ContractCall: + """Upvotes an exist proposal""" + + return self.contract.upvote_proposal(kernel_root_hash) + + def vote(self, vote : str) -> ContractCall: + """Votes for a kernel_root_hash in promotion period""" + + return self.contract.vote(vote) \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/rollup_mock.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/rollup_mock.py new file mode 100644 index 000000000000..b02a6144e8a3 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/rollup_mock.py @@ -0,0 +1,20 @@ +from pytezos.client import PyTezosClient +from tests.helpers.contracts.contract import ContractHelper +from tests.helpers.utility import ( + get_build_dir, + originate_from_file, +) +from pytezos.operation.group import OperationGroup +from os.path import join + + +class RollupMock(ContractHelper): + @classmethod + def originate(self, client: PyTezosClient) -> OperationGroup: + """Deploys Rollup Mock""" + + storage = bytes.fromhex('00') + filename = join(get_build_dir(), 'test/rollup_mock.tz') + + return originate_from_file(filename, client, storage) + \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/helpers/contracts/sequencer_governance.py b/etherlink/tezos_contracts/governance/tests/helpers/contracts/sequencer_governance.py new file mode 100644 index 000000000000..87cb1183f11a --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/contracts/sequencer_governance.py @@ -0,0 +1,44 @@ +from pytezos.client import PyTezosClient +from tests.helpers.contracts.governance_base import GovernanceBase +from tests.helpers.utility import ( + get_build_dir, + originate_from_file, +) +from pytezos.operation.group import OperationGroup +from pytezos.contract.call import ContractCall +from os.path import join +from tests.helpers.metadata import Metadata + + +class SequencerGovernance(GovernanceBase): + @classmethod + def originate(self, client: PyTezosClient, custom_config=None, metadata=None) -> OperationGroup: + """Deploys Sequencer Governance""" + + metadata = metadata if metadata != None else dict() + metadata = Metadata.make_default(**metadata) + storage = self.make_storage(metadata, custom_config=custom_config) + filename = join(get_build_dir(), 'sequencer_governance.tz') + + return originate_from_file(filename, client, storage) + + def new_proposal(self, sequencer_pk : str, pool_address : bytes) -> ContractCall: + """Creates a new proposal""" + + return self.contract.new_proposal(sequencer_pk, pool_address) + + + def upvote_proposal(self, sequencer_pk : str, pool_address : bytes) -> ContractCall: + """Upvotes an exist proposal""" + + return self.contract.upvote_proposal(sequencer_pk, pool_address) + + def vote(self, vote : str) -> ContractCall: + """Votes for a hash in promotion period""" + + return self.contract.vote(vote) + + def trigger_committee_upgrade(self, rollup_address : str) -> ContractCall: + """Triggers upgrade transaction to rollup with last winner committee addresses set""" + + return self.contract.trigger_committee_upgrade(rollup_address) diff --git a/etherlink/tezos_contracts/governance/tests/helpers/errors.py b/etherlink/tezos_contracts/governance/tests/helpers/errors.py new file mode 100644 index 000000000000..8ac4c0bf80fe --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/errors.py @@ -0,0 +1,16 @@ +TEZ_IN_TRANSACTION_DISALLOWED = 'TEZ_IN_TRANSACTION_DISALLOWED' +NO_VOTING_POWER = 'NO_VOTING_POWER' +NOT_PROPOSAL_PERIOD = 'NOT_PROPOSAL_PERIOD' +NOT_PROMOTION_PERIOD = 'NOT_PROMOTION_PERIOD' +PROPOSAL_ALREADY_CREATED = 'PROPOSAL_ALREADY_CREATED' +PROPOSAL_ALREADY_UPVOTED = 'PROPOSAL_ALREADY_UPVOTED' +PROMOTION_ALREADY_VOTED = 'PROMOTION_ALREADY_VOTED' +UPVOTING_LIMIT_EXCEEDED = 'UPVOTING_LIMIT_EXCEEDED' +PROPOSER_NOT_IN_COMMITTEE = 'PROPOSER_NOT_IN_COMMITTEE' +LAST_WINNER_NOT_FOUND = 'LAST_WINNER_NOT_FOUND' +INCORRECT_VOTE_VALUE = 'INCORRECT_VOTE_VALUE' +INCORRECT_KERNEL_ROOT_HASH_LENGTH = 'INCORRECT_KERNEL_ROOT_HASH_LENGTH' +UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED = 'UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED' +INCORRECT_SEQUENCER_PK_LENGTH = 'INCORRECT_SEQUENCER_PK_LENGTH' +INCORRECT_POOL_ADDRESS_LENGTH = 'INCORRECT_POOL_ADDRESS_LENGTH' +NOT_IMPLICIT_ADDRESS = 'NOT_IMPLICIT_ADDRESS' \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/helpers/metadata.py b/etherlink/tezos_contracts/governance/tests/helpers/metadata.py new file mode 100644 index 000000000000..45677fba1818 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/metadata.py @@ -0,0 +1,37 @@ +import json +from typing import Any + + +def to_hex(string: str) -> str: + """Converts given string to bytes and then hex""" + return string.encode().hex() + + +class Metadata: + """Helper to create metadata for the contracts""" + + template = { + 'version': '0.1.0', + 'name': 'Test contract name', + 'description': 'Test contract description', + 'interfaces': ['TZIP-016'], + 'license': {'name': 'MIT'}, + } + + @staticmethod + def make(**kwargs: Any) -> dict: + """Creates metadata from provided kwargs dict""" + + metadata_json = json.dumps(kwargs) + return { + '': to_hex('tezos-storage:contents'), + 'contents': to_hex(metadata_json), + } + + @classmethod + def make_default(cls, **kwargs: str) -> dict: + """Creates metadata using default metadata as a template""" + + metadata = cls.template.copy() + metadata.update(kwargs) + return Metadata.make(**metadata) diff --git a/etherlink/tezos_contracts/governance/tests/helpers/operation_result_recorder.py b/etherlink/tezos_contracts/governance/tests/helpers/operation_result_recorder.py new file mode 100644 index 000000000000..d113ae44f95e --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/operation_result_recorder.py @@ -0,0 +1,17 @@ +import json +from pytezos.operation.result import OperationResult + +class OperationResultRecorder: + def __init__(self): + self.data = {} + + def add_element(self, key, op): + value = { + 'consumed_gas': OperationResult.consumed_gas(op), + 'paid_storage_size_diff': OperationResult.paid_storage_size_diff(op), + } + self.data[key] = value + + def write_to_file(self, filename): + with open(filename, 'w') as f: + json.dump(self.data, f, indent=4) diff --git a/etherlink/tezos_contracts/governance/tests/helpers/utility.py b/etherlink/tezos_contracts/governance/tests/helpers/utility.py new file mode 100644 index 000000000000..4623ef9b5a56 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/helpers/utility.py @@ -0,0 +1,141 @@ +from pytezos.client import PyTezosClient +from pytezos.contract.interface import ContractInterface +from pytezos.operation.group import OperationGroup +from os.path import dirname +from os.path import join +from pytezos.michelson.parse import michelson_to_micheline +from pytezos.michelson.types.base import MichelsonType +from typing import Any + + +DEFAULT_ADDRESS = 'tz1burnburnburnburnburnburnburjAYjjX' +DEFAULT_VOTING_POWER = 4000000000000 +DEFAULT_TOTAL_VOTING_POWER = 20000000000000 + +TEST_ADDRESSES_SET = [ + 'tz1RuHDSj9P7mNNhfKxsyLGRDahTX5QD1DdP', + 'tz1Xf8zdT3DbAX9cHw3c3CXh79rc4nK4gCe8', + 'tz1V16tR1LMKRernkmXzngkfznmEcTGXwDuk', + 'tz1aWXP237BLwNHJcCD4b3DutCevhqq2T1Z9', + 'tz1Qf1pSbJzMN4VtGFfVJRgbXhBksRv36TxW', + 'tz1YgDUQV2eXm8pUWNz3S5aWP86iFzNp4jnD', + 'tz1iZ9LkpAhN8X1L6RpBtfy3wxpEWzFrXz8j', + 'tz1PirbogVqfmBT9XCuYJ1KnDx4bnMSYfGru', + 'tz1cg5EqC3WdZgRSvGJeW328S4KQNrT4jvyv', + 'tz1Zt8QQ9aBznYNk5LUBjtME9DuExomw9YRs', + 'tz3ZmB8oWUmi8YZXgeRpgAcPnEMD8VgUa4Ve', + 'tz1XMiZwHpHZ8a1AfwRWKfzLskJgZNyV8PHs', + 'tz1NiaviJwtMbpEcNqSP6neeoBYj8Brb3QPv', + 'tz1TGKSrZrBpND3PELJ43nVdyadoeiM1WMzb', + 'tz1YtjpWwWsTzjoRpSi56eTQnUdomTAtFJih', + 'tz1bQMn5xYFbX6geRxqvuAiTywsCtNywawxH', + 'tz1NFs6yP2sXd5vAAbR43bbDRpV2nahDZope', + 'tz1e42w8ZaGAbM3gucbBy8iRypdbnqUj7oWY', + 'tz3btDQsDkqq2G7eBdrrLqetaAfLVw6BnPez', + 'tz1cjyja1TU6fiyiFav3mFAdnDsCReJ12hPD', + 'tz1LZVSPJw5taDFBVjvcQMUhwehdWgatKbzK', +] +TEST_ADDRESSES_SET.sort() + + +def pkh(client: PyTezosClient) -> str: + """Returns public key hash of given client""" + + return str(client.key.public_key_hash()) + + +def find_op_by_hash(client: PyTezosClient, opg: OperationGroup) -> dict: + """Finds operation group by operation hash""" + + op = client.shell.blocks[-10:].find_operation(opg.hash()) + return op # type: ignore + + +def get_address_from_op(op: dict) -> str: + """Returns originated contract address from given operation dict""" + + contents = op['contents'] + assert len(contents) == 1, 'multiple origination not supported' + op_result: dict = contents[0]['metadata']['operation_result'] + contracts = op_result['originated_contracts'] + assert len(contracts) == 1, 'multiple origination not supported' + originated_contract = contracts[0] + assert isinstance(originated_contract, str) + return originated_contract + + +def get_build_dir() -> str: + """Returns path to the build directory""" + + return join(dirname(__file__), '..', '..', 'build') + +def get_tests_dir() -> str: + """Returns path to the test directory""" + + return join(dirname(__file__), '..') + + +def load_contract_from_address( + client: PyTezosClient, contract_address: str +) -> ContractInterface: + """Loads contract from given address using given client""" + + contract = client.contract(contract_address) + contract = contract.using(shell=client.shell, key=client.key) + return contract + + +def to_micheline(type_expression: str) -> dict: + """Converts Michelson type expression string to Micheline expression + (reusing pytezos.michelson.parse.michelson_to_micheline) with + type checking + """ + + return michelson_to_micheline(type_expression) # type: ignore + + +def to_michelson_type(object: Any, type_expression: str) -> MichelsonType: + """Converts Python object to Michelson type using given type expression""" + + micheline_expression = to_micheline(type_expression) + michelson_type = MichelsonType.match(micheline_expression) + return michelson_type.from_python_object(object) + + +def pack(object: Any, type_expression: str) -> bytes: + """Packs Python object to bytes using given type expression""" + + return to_michelson_type(object, type_expression).pack() + + +def pack_sequencer_payload(payload): + return { + 'sequencer_pk': payload['sequencer_pk'], + 'pool_address': bytes.fromhex(payload['pool_address']) + } + +def originate_from_file( + filename: str, client: PyTezosClient, storage: Any +) -> OperationGroup: + """Deploys contract from filename with given storage + using given client and returns OperationGroup""" + + print(f'deploying contract from filename {filename}') + raw_contract = ContractInterface.from_file(filename) + contract = raw_contract.using(key=client.key, shell=client.shell) + return contract.originate(initial_storage=storage) + +def get_digits(value: float) -> int: + result = 0 + while(value % 1 != 0): + result += 1 + value *= 10 + return result + +def normalize_params(values : list[float]) -> list[int]: + max_digits = max(map(get_digits, values)) + return list(map(lambda v: int(v * 10**max_digits), values)) + +def validate_percent_value(value : float): + if(not (0 <= value <= 100)): + raise Exception(f'Incorrect percentage value \'{value}\'. Should be in range [0, 100]') diff --git a/etherlink/tezos_contracts/governance/tests/kernel_governance/__init__.py b/etherlink/tezos_contracts/governance/tests/kernel_governance/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/__init__.py b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_new_proposal.py b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_new_proposal.py new file mode 100644 index 000000000000..bd6903ce713a --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_new_proposal.py @@ -0,0 +1,181 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import PROMOTION_PERIOD, PROPOSAL_PERIOD, YEA_VOTE +from tests.helpers.errors import ( + INCORRECT_KERNEL_ROOT_HASH_LENGTH, NO_VOTING_POWER, NOT_PROPOSAL_PERIOD, + PROPOSAL_ALREADY_CREATED, PROPOSER_NOT_IN_COMMITTEE, UPVOTING_LIMIT_EXCEEDED, + TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER, pkh + +class KernelGovernanceNewProposalTestCase(BaseTestCase): + def test_should_fail_if_kernel_root_hash_has_incorrect_size(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + with self.raisesMichelsonError(INCORRECT_KERNEL_ROOT_HASH_LENGTH): + governance.using(baker).new_proposal(bytes.fromhex('009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606a')).send() + with self.raisesMichelsonError(INCORRECT_KERNEL_ROOT_HASH_LENGTH): + governance.using(baker).new_proposal(bytes.fromhex('009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606abcde')).send() + governance.using(baker).new_proposal(bytes.fromhex('009279df4982e47cf101e2525b605fa06cd3ccc0f67d1c792a6a3ea56af9606abc')).send() + self.bake_block() + + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).new_proposal(kernel_root_hash).with_amount(1).send() + + def test_should_fail_if_sender_has_no_voting_power(self) -> None: + no_baker = self.bootstrap_no_baker() + governance = self.deploy_kernel_governance() + + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + with self.raisesMichelsonError(NO_VOTING_POWER): + governance.using(no_baker).new_proposal(kernel_root_hash).send() + + def test_should_not_fail_if_payload_same_as_last_winner(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20, # 1 bakers out of 5 voted + 'promotion_quorum': 20, # 1 bakers out of 5 voted + 'promotion_supermajority': 50, # 1 bakers out of 5 voted + }) + + # Period index: 0. Block: 2 of 2 + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_blocks(2) + + # Period index: 1. Block: 1 of 2 + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(2) + + # Period index: 3. Block: 1 of 2 + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_block() + + def test_should_fail_if_current_period_is_not_proposal(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20 # 1 bakers out of 5 voted + }) + + # Period index: 0. Block: 2 of 2 + governance.using(baker).new_proposal('010101010101010101010101010101010101010101010101010101010101010101').send() + self.bake_block() + + self.bake_block() + # Period index: 1. Block: 1 of 2 + state = governance.get_voting_state() + assert state['period_index'] == 1 + assert state['period_type'] == PROMOTION_PERIOD + + # Period index: 1. Block: 2 of 2 + kernel_root_hash = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + with self.raisesMichelsonError(NOT_PROPOSAL_PERIOD): + governance.using(baker).new_proposal(kernel_root_hash).send() + + def test_should_fail_if_new_proposal_limit_is_exceeded(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + # Period index: 0. Block: 2 of 5 + governance.using(baker).new_proposal('010101010101010101010101010101010101010101010101010101010101010101').send() + self.bake_block() + # Period index: 0. Block: 3 of 5 + governance.using(baker).new_proposal('020202020202020202020202020202020202020202020202020202020202020202').send() + self.bake_block() + + with self.raisesMichelsonError(UPVOTING_LIMIT_EXCEEDED): + governance.using(baker).new_proposal('030303030303030303030303030303030303030303030303030303030303030303').send() + + def test_should_fail_if_new_proposal_already_created(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + kernel_root_hash = '010101010101010101010101010101010101010101010101010101010101010101' + # Period index: 0. Block: 1 of 5 + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_block() + + with self.raisesMichelsonError(PROPOSAL_ALREADY_CREATED): + governance.using(baker).new_proposal(kernel_root_hash).send() + + def test_should_create_new_proposal_with_correct_parameters(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 5, + 'finished_voting': None + } + + kernel_root_hash1 = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + # Period index: 0. Block: 2 of 5 + governance.using(baker1).new_proposal(kernel_root_hash1).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash1 + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 4, + 'finished_voting': None + } + + kernel_root_hash2 = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + # Period index: 0. Block: 3 of 5 + governance.using(baker2).new_proposal(kernel_root_hash2).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == None + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 3, + 'finished_voting': None + } \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_trigger_kernel_upgrade.py b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_trigger_kernel_upgrade.py new file mode 100644 index 000000000000..a88463e459b8 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_trigger_kernel_upgrade.py @@ -0,0 +1,120 @@ +from pytezos.client import PyTezosClient +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import YEA_VOTE +from tests.helpers.contracts.kernel_governance import KernelGovernance +from tests.helpers.errors import ( + LAST_WINNER_NOT_FOUND, + UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED, + TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_ADDRESS +import re + +class KernelGovernanceTriggerKernelUpgradeTestCase(BaseTestCase): + def prepare_last_winner(self, payload): + baker = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20, + 'promotion_quorum': 20, + 'promotion_supermajority': 20, + }) + + # Period index: 0. Block: 2 of 2 + governance.using(baker).new_proposal(payload).send() + self.bake_blocks(2) + + # Period index: 1. Block: 2 of 2 + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(2) + + return { + 'governance': governance, + 'baker': baker, + } + + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).trigger_kernel_upgrade(DEFAULT_ADDRESS).with_amount(1).send() + + def test_should_fail_if_there_is_no_last_winner_payload(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + with self.raisesMichelsonError(LAST_WINNER_NOT_FOUND): + governance.using(baker).trigger_kernel_upgrade(DEFAULT_ADDRESS).send() + + def test_should_allow_no_baker_to_trigger_upgrade(self) -> None: + no_baker = self.bootstrap_no_baker() + rollup_mock = self.deploy_rollup_mock() + governance = self.deploy_kernel_governance() + + kernel_root_hash = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + test = self.prepare_last_winner(kernel_root_hash) + governance : KernelGovernance = test['governance'] + + governance.using(no_baker).trigger_kernel_upgrade(rollup_mock.contract.address).send() + self.bake_block() + + def test_should_fail_to_send_last_winner_second_time_to_the_same_address_but_reset_for_new_winner(self) -> None: + rollup_mock1 = self.deploy_rollup_mock() + rollup_mock2 = self.deploy_rollup_mock() + kernel_root_hash = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + test = self.prepare_last_winner(kernel_root_hash) + governance : KernelGovernance = test['governance'] + baker : PyTezosClient = test['baker'] + + governance.using(baker).trigger_kernel_upgrade(rollup_mock1.contract.address).send() + self.bake_blocks(10) + + governance.using(baker).trigger_kernel_upgrade(rollup_mock2.contract.address).send() + self.bake_blocks(10) + + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock2.contract.address).send() + + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_blocks(2) + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(2) + + governance.using(baker).trigger_kernel_upgrade(rollup_mock1.contract.address).send() + self.bake_blocks(10) + governance.using(baker).trigger_kernel_upgrade(rollup_mock2.contract.address).send() + self.bake_blocks(10) + + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock2.contract.address).send() + + # check that trigger history preserves + self.bake_blocks(21) + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_kernel_upgrade(rollup_mock2.contract.address).send() + + + def test_should_send_last_winner_payload_to_rollup(self) -> None: + rollup_mock = self.deploy_rollup_mock() + kernel_root_hash = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + test = self.prepare_last_winner(kernel_root_hash) + governance : KernelGovernance = test['governance'] + baker : PyTezosClient = test['baker'] + + payload_pattern = rf'^EBA1{kernel_root_hash.hex()}88[\da-f]{{16}}$' + assert not re.match(payload_pattern, rollup_mock.contract.storage().hex(), re.IGNORECASE) + + governance.using(baker).trigger_kernel_upgrade(rollup_mock.contract.address).send() + self.bake_block() + assert re.match(payload_pattern, rollup_mock.contract.storage().hex(), re.IGNORECASE) \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_upvote_proposal.py b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_upvote_proposal.py new file mode 100644 index 000000000000..d4f923750d3b --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_upvote_proposal.py @@ -0,0 +1,215 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import PROMOTION_PERIOD, PROPOSAL_PERIOD +from tests.helpers.errors import ( + NO_VOTING_POWER, NOT_PROPOSAL_PERIOD, PROPOSAL_ALREADY_UPVOTED, + UPVOTING_LIMIT_EXCEEDED, TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER + +class KernelGovernanceUpvoteProposalTestCase(BaseTestCase): + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).upvote_proposal(kernel_root_hash).with_amount(1).send() + + def test_should_fail_if_sender_has_no_voting_power(self) -> None: + no_baker = self.bootstrap_no_baker() + governance = self.deploy_kernel_governance() + + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + with self.raisesMichelsonError(NO_VOTING_POWER): + governance.using(no_baker).upvote_proposal(kernel_root_hash).send() + + def test_should_fail_if_current_period_is_not_proposal(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20 # 1 bakers out of 5 voted + }) + + kernel_root_hash = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + # Period index: 0. Block: 2 of 2 + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_block() + + self.bake_block() + # Period index: 1. Block: 1 of 2 + state = governance.get_voting_state() + assert state['period_index'] == 1 + assert state['period_type'] == PROMOTION_PERIOD + + # Period index: 1. Block: 2 of 2 + with self.raisesMichelsonError(NOT_PROPOSAL_PERIOD): + governance.using(baker).upvote_proposal(kernel_root_hash).send() + + + def test_should_fail_if_upvoting_limit_is_exceeded(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 7 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 7, + 'upvoting_limit': 2 + }) + + kernel_root_hash1 = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + # Period index: 0. Block: 2 of 7 + governance.using(baker1).new_proposal(kernel_root_hash1).send() + self.bake_block() + # Period index: 0. Block: 3 of 7 + kernel_root_hash2 = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + governance.using(baker1).new_proposal(kernel_root_hash2).send() + self.bake_block() + # Period index: 0. Block: 4 of 7 + kernel_root_hash3 = bytes.fromhex('030303030303030303030303030303030303030303030303030303030303030303') + governance.using(baker2).new_proposal(kernel_root_hash3).send() + self.bake_block() + # Period index: 0. Block: 5 of 7 + governance.using(baker3).upvote_proposal(kernel_root_hash1).send() + self.bake_block() + # Period index: 0. Block: 6 of 7 + governance.using(baker3).upvote_proposal(kernel_root_hash2).send() + self.bake_block() + + with self.raisesMichelsonError(UPVOTING_LIMIT_EXCEEDED): + governance.using(baker3).upvote_proposal(kernel_root_hash3).send() + + + def test_should_fail_if_proposal_already_upvoted_by_proposer(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + kernel_root_hash = '010101010101010101010101010101010101010101010101010101010101010101' + # Period index: 0. Block: 1 of 5 + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_block() + + with self.raisesMichelsonError(PROPOSAL_ALREADY_UPVOTED): + governance.using(baker).upvote_proposal(kernel_root_hash).send() + + def test_should_fail_if_proposal_already_upvoted_by_another_baker(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + kernel_root_hash = '010101010101010101010101010101010101010101010101010101010101010101' + # Period index: 0. Block: 1 of 5 + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + + # Period index: 0. Block: 2 of 5 + governance.using(baker2).upvote_proposal(kernel_root_hash).send() + self.bake_block() + + with self.raisesMichelsonError(PROPOSAL_ALREADY_UPVOTED): + governance.using(baker2).upvote_proposal(kernel_root_hash).send() + + def test_should_upvote_proposal_with_correct_parameters(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 5, + 'finished_voting': None + } + + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + # Period index: 0. Block: 2 of 5 + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 4, + 'finished_voting': None + } + + # Period index: 0. Block: 3 of 5 + governance.using(baker2).upvote_proposal(kernel_root_hash).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 3, + 'finished_voting': None + } + + kernel_root_hash2 = bytes.fromhex('020202020202020202020202020202020202020202020202020202020202020202') + # Period index: 0. Block: 4 of 5 + governance.using(baker1).new_proposal(kernel_root_hash2).send() + self.bake_block() + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 0. Block: 5 of 5 + governance.using(baker2).upvote_proposal(kernel_root_hash2).send() + governance.using(baker3).upvote_proposal(kernel_root_hash2).send() + self.bake_block() + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash2 + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 3 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_vote.py b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_vote.py new file mode 100644 index 000000000000..cf7c95fd06a3 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/kernel_governance/entrypoints/test_vote.py @@ -0,0 +1,205 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import NAY_VOTE, PASS_VOTE, PROMOTION_PERIOD, PROPOSAL_PERIOD, YEA_VOTE +from tests.helpers.errors import ( + INCORRECT_VOTE_VALUE, NO_VOTING_POWER, NOT_PROMOTION_PERIOD, PROMOTION_ALREADY_VOTED, + TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_VOTING_POWER, DEFAULT_TOTAL_VOTING_POWER + +class KernelGovernanceNewProposalTestCase(BaseTestCase): + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).vote(YEA_VOTE).with_amount(1).send() + + def test_should_fail_if_sender_has_no_voting_power(self) -> None: + no_baker = self.bootstrap_no_baker() + governance = self.deploy_kernel_governance() + + with self.raisesMichelsonError(NO_VOTING_POWER): + governance.using(no_baker).vote(YEA_VOTE).send() + + def test_should_fail_if_current_period_is_not_promotion(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_kernel_governance() + + with self.raisesMichelsonError(NOT_PROMOTION_PERIOD): + governance.using(baker).vote(YEA_VOTE).send() + + + def test_should_fail_if_vote_parameter_is_incorrect(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + kernel_root_hash = '010101010101010101010101010101010101010101010101010101010101010101' + # Period index: 0. Block: 2 of 3 + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + + # Period index: 0. Block: 3 of 3 + self.bake_block() + # Period index: 1. Block: 1 of 3 + self.bake_block() + + # Period index: 1. Block: 2 of 3 + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("yep").send() + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("no").send() + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("pas").send() + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("NAY").send() + + governance.using(baker1).vote(YEA_VOTE).send() + governance.using(baker2).vote(NAY_VOTE).send() + governance.using(baker3).vote(PASS_VOTE).send() + self.bake_block() + + def test_should_fail_if_proposal_already_voted(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + kernel_root_hash = '010101010101010101010101010101010101010101010101010101010101010101' + # Period index: 0. Block: 2 of 3 + governance.using(baker).new_proposal(kernel_root_hash).send() + self.bake_block() + + # Period index: 0. Block: 3 of 3 + self.bake_block() + # Period index: 1. Block: 1 of 3 + self.bake_block() + + # Period index: 1. Block: 2 of 3 + governance.using(baker).vote(YEA_VOTE).send() + self.bake_block() + + with self.raisesMichelsonError(PROMOTION_ALREADY_VOTED): + governance.using(baker).vote(YEA_VOTE).send() + + def test_should_vote_on_proposal_with_correct_parameters(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + baker4 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_kernel_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 5, + 'finished_voting': None + } + + kernel_root_hash = bytes.fromhex('010101010101010101010101010101010101010101010101010101010101010101') + # Period index: 0. Block: 2 of 5 + governance.using(baker1).new_proposal(kernel_root_hash).send() + self.bake_block() + # Period index: 1. Block: 1 of 5 + self.bake_blocks(4) + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == kernel_root_hash + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 5, + 'finished_voting': None + } + + # Period index: 1. Block: 2 of 5 + governance.using(baker1).vote(YEA_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 4, + 'finished_voting': None + } + + # Period index: 1. Block: 3 of 5 + governance.using(baker2).vote(NAY_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': None + } + + # Period index: 1. Block: 4 of 5 + governance.using(baker3).vote(PASS_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 1. Block: 5 of 5 + governance.using(baker4).vote(YEA_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 1, + 'finished_voting': None + } \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/sequencer_governance/__init__.py b/etherlink/tezos_contracts/governance/tests/sequencer_governance/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/__init__.py b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_new_proposal.py b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_new_proposal.py new file mode 100644 index 000000000000..e93e3fcb778a --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_new_proposal.py @@ -0,0 +1,217 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import PROMOTION_PERIOD, PROPOSAL_PERIOD, YEA_VOTE +from tests.helpers.errors import ( + INCORRECT_POOL_ADDRESS_LENGTH, INCORRECT_SEQUENCER_PK_LENGTH, NO_VOTING_POWER, NOT_PROPOSAL_PERIOD, PROPOSAL_ALREADY_CREATED, PROPOSER_NOT_IN_COMMITTEE, + UPVOTING_LIMIT_EXCEEDED, TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER, pack_sequencer_payload, pkh + +class CommitteeGovernanceNewProposalTestCase(BaseTestCase): + def test_should_fail_if_proposal_payload_has_incorrect_size(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + + with self.raisesMichelsonError(INCORRECT_SEQUENCER_PK_LENGTH): + governance.using(baker).new_proposal('edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1XFF', 'B7A97043983f24991398E5a82f63F4C58a417185').send() + with self.raisesMichelsonError(INCORRECT_POOL_ADDRESS_LENGTH): + governance.using(baker).new_proposal('edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', 'B7A97043983f24991398E5a82f63F4C58a41718543').send() + governance.using(baker).new_proposal('edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', 'B7A97043983f24991398E5a82f63F4C58a417185').send() + self.bake_block() + + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + sequencer_pk = 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X' + pool_address = 'B7A97043983f24991398E5a82f63F4C58a417185' + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).new_proposal(sequencer_pk, pool_address).with_amount(1).send() + + def test_should_fail_if_sender_has_no_voting_power(self) -> None: + no_baker = self.bootstrap_no_baker() + governance = self.deploy_sequencer_governance() + + sequencer_pk = 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X' + pool_address = 'B7A97043983f24991398E5a82f63F4C58a417185' + with self.raisesMichelsonError(NO_VOTING_POWER): + governance.using(no_baker).new_proposal(sequencer_pk, pool_address).send() + + def test_should_not_fail_if_payload_same_as_last_winner(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20, # 1 bakers out of 5 voted + 'promotion_quorum': 20, # 1 bakers out of 5 voted + 'promotion_supermajority': 50, # 1 bakers out of 5 voted + }) + + # Period index: 0. Block: 2 of 2 + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_blocks(2) + + # Period index: 1. Block: 1 of 2 + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(2) + + # Period index: 3. Block: 1 of 2 + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + + def test_should_fail_if_current_period_is_not_proposal(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20 # 1 bakers out of 5 voted + }) + + # Period index: 0. Block: 2 of 2 + payload1 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + + governance.using(baker).new_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + + self.bake_block() + # Period index: 1. Block: 1 of 2 + state = governance.get_voting_state() + assert state['period_index'] == 1 + assert state['period_type'] == PROMOTION_PERIOD + + # Period index: 1. Block: 2 of 2 + payload2 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a4171ff' + } + with self.raisesMichelsonError(NOT_PROPOSAL_PERIOD): + governance.using(baker).new_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + + def test_should_fail_if_new_proposal_limit_is_exceeded(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + # Period index: 0. Block: 2 of 5 + payload1 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + governance.using(baker).new_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + # Period index: 0. Block: 3 of 5 + payload2 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417186' + } + governance.using(baker).new_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + + payload3 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417187' + } + with self.raisesMichelsonError(UPVOTING_LIMIT_EXCEEDED): + governance.using(baker).new_proposal(payload3['sequencer_pk'], payload3['pool_address']).send() + + def test_should_fail_if_new_proposal_already_created(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 5 + }) + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 1 of 5 + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + self.bake_block() + self.bake_block() + + with self.raisesMichelsonError(PROPOSAL_ALREADY_CREATED): + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + + def test_should_create_new_proposal_with_correct_parameters(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 5, + 'finished_voting': None + } + + payload1 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 2 of 5 + governance.using(baker1).new_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == pack_sequencer_payload(payload1) + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 4, + 'finished_voting': None + } + + payload2 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417186' + } + # Period index: 0. Block: 3 of 5 + governance.using(baker2).new_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == None + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 3, + 'finished_voting': None + } \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_trigger_committee_upgrade.py b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_trigger_committee_upgrade.py new file mode 100644 index 000000000000..b681478c7695 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_trigger_committee_upgrade.py @@ -0,0 +1,121 @@ +from pytezos.client import PyTezosClient +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import YEA_VOTE +from tests.helpers.contracts.sequencer_governance import SequencerGovernance +from tests.helpers.errors import ( + LAST_WINNER_NOT_FOUND, + UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED, + TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_ADDRESS +import re + +class CommitteeGovernanceTriggerCommitteeUpgradeTestCase(BaseTestCase): + def prepare_last_winner(self, sequencer_pk, pool_address): + baker = self.bootstrap_baker() + governance_started_at_level = self.get_current_level() + 1 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20, + 'promotion_quorum': 20, + 'promotion_supermajority': 20, + }) + + # Period index: 0. Block: 2 of 2 + governance.using(baker).new_proposal(sequencer_pk, pool_address).send() + self.bake_blocks(2) + + # Period index: 1. Block: 2 of 2 + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(2) + + return { + 'governance': governance, + 'baker': baker, + } + + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).trigger_committee_upgrade(DEFAULT_ADDRESS).with_amount(1).send() + + def test_should_fail_if_there_is_no_last_winner_payload(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + with self.raisesMichelsonError(LAST_WINNER_NOT_FOUND): + governance.using(baker).trigger_committee_upgrade(DEFAULT_ADDRESS).send() + + def test_should_allow_no_baker_to_trigger_upgrade(self) -> None: + no_baker = self.bootstrap_no_baker() + rollup_mock = self.deploy_rollup_mock() + sequencer_pk = 'edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav' + pool_address = '71c7656ec7ab88b098defb751b7401b5f6d8976f' + test = self.prepare_last_winner(sequencer_pk, pool_address) + governance : SequencerGovernance = test['governance'] + + governance.using(no_baker).trigger_committee_upgrade(rollup_mock.contract.address).send() + self.bake_block() + + def test_should_fail_to_send_last_winner_second_time_to_the_same_address_but_reset_for_new_winner(self) -> None: + rollup_mock1 = self.deploy_rollup_mock() + rollup_mock2 = self.deploy_rollup_mock() + sequencer_pk = 'edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav' + pool_address = '71c7656ec7ab88b098defb751b7401b5f6d8976f' + test = self.prepare_last_winner(sequencer_pk, pool_address) + governance : SequencerGovernance = test['governance'] + baker : PyTezosClient = test['baker'] + + governance.using(baker).trigger_committee_upgrade(rollup_mock1.contract.address).send() + self.bake_blocks(10) + + governance.using(baker).trigger_committee_upgrade(rollup_mock2.contract.address).send() + self.bake_blocks(10) + + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock2.contract.address).send() + + governance.using(baker).new_proposal(sequencer_pk, pool_address).send() + self.bake_blocks(2) + governance.using(baker).vote(YEA_VOTE).send() + self.bake_blocks(2) + + governance.using(baker).trigger_committee_upgrade(rollup_mock1.contract.address).send() + self.bake_blocks(10) + governance.using(baker).trigger_committee_upgrade(rollup_mock2.contract.address).send() + self.bake_blocks(10) + + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock2.contract.address).send() + + # check that trigger history preserves + self.bake_blocks(21) + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock1.contract.address).send() + with self.raisesMichelsonError(UPGRADE_FOR_ADDRESS_ALREADY_TRIGGERED): + governance.using(baker).trigger_committee_upgrade(rollup_mock2.contract.address).send() + + + def test_should_send_last_winner_payload_to_rollup(self) -> None: + rollup_mock = self.deploy_rollup_mock() + sequencer_pk = 'edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav' + pool_address = '71c7656ec7ab88b098defb751b7401b5f6d8976f' + test = self.prepare_last_winner(sequencer_pk, pool_address) + governance : SequencerGovernance = test['governance'] + baker : PyTezosClient = test['baker'] + + payload_pattern = rf'^F855B6{sequencer_pk.encode().hex()}94{pool_address}88[\da-f]{{16}}$' + assert not re.match(payload_pattern, rollup_mock.contract.storage().hex(), re.IGNORECASE) + + governance.using(baker).trigger_committee_upgrade(rollup_mock.contract.address).send() + self.bake_block() + assert re.match(payload_pattern, rollup_mock.contract.storage().hex(), re.IGNORECASE) \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_upvote_proposal.py b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_upvote_proposal.py new file mode 100644 index 000000000000..806727037144 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_upvote_proposal.py @@ -0,0 +1,248 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import PROMOTION_PERIOD, PROPOSAL_PERIOD +from tests.helpers.errors import ( + NO_VOTING_POWER, NOT_PROPOSAL_PERIOD, PROPOSAL_ALREADY_UPVOTED, UPVOTING_LIMIT_EXCEEDED, + TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER, pack_sequencer_payload + +class CommitteeGovernanceUpvoteProposalTestCase(BaseTestCase): + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).upvote_proposal(payload['sequencer_pk'], payload['pool_address']).with_amount(1).send() + + def test_should_fail_if_sender_has_no_voting_power(self) -> None: + no_baker = self.bootstrap_no_baker() + governance = self.deploy_sequencer_governance() + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + with self.raisesMichelsonError(NO_VOTING_POWER): + governance.using(no_baker).upvote_proposal(payload['sequencer_pk'], payload['pool_address']).send() + + def test_should_fail_if_current_period_is_not_proposal(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 2 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 2, + 'proposal_quorum': 20 # 1 bakers out of 5 voted + }) + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 2 of 2 + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + + self.bake_block() + # Period index: 1. Block: 1 of 2 + state = governance.get_voting_state() + assert state['period_index'] == 1 + assert state['period_type'] == PROMOTION_PERIOD + + # Period index: 1. Block: 2 of 2 + with self.raisesMichelsonError(NOT_PROPOSAL_PERIOD): + governance.using(baker).upvote_proposal(payload['sequencer_pk'], payload['pool_address']).send() + + def test_should_fail_if_upvoting_limit_is_exceeded(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 7 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 7, + 'upvoting_limit': 2 + }) + + payload1 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 2 of 7 + governance.using(baker1).new_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + # Period index: 0. Block: 3 of 7 + payload2 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417186' + } + governance.using(baker1).new_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + # Period index: 0. Block: 4 of 7 + payload3 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417188' + } + governance.using(baker2).new_proposal(payload3['sequencer_pk'], payload3['pool_address']).send() + self.bake_block() + # Period index: 0. Block: 5 of 7 + governance.using(baker3).upvote_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + # Period index: 0. Block: 6 of 7 + governance.using(baker3).upvote_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + + with self.raisesMichelsonError(UPVOTING_LIMIT_EXCEEDED): + governance.using(baker3).upvote_proposal(payload3['sequencer_pk'], payload3['pool_address']).send() + + + def test_should_fail_if_proposal_already_upvoted_by_proposer(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 5 + }) + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 1 of 5 + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + self.bake_block() + self.bake_block() + + with self.raisesMichelsonError(PROPOSAL_ALREADY_UPVOTED): + governance.using(baker).upvote_proposal(payload['sequencer_pk'], payload['pool_address']).send() + + def test_should_fail_if_proposal_already_upvoted_by_another_baker(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2 + }) + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 1 of 5 + governance.using(baker1).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + + # Period index: 0. Block: 2 of 5 + governance.using(baker2).upvote_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + + with self.raisesMichelsonError(PROPOSAL_ALREADY_UPVOTED): + governance.using(baker2).upvote_proposal(payload['sequencer_pk'], payload['pool_address']).send() + + def test_should_upvote_proposal_with_correct_parameters(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 6, + 'upvoting_limit': 2 + }) + + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 6, + 'finished_voting': None + } + + payload1 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 2 of 6 + governance.using(baker1).new_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == pack_sequencer_payload(payload1) + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 5, + 'finished_voting': None + } + + # Period index: 0. Block: 3 of 6 + governance.using(baker2).upvote_proposal(payload1['sequencer_pk'], payload1['pool_address']).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == pack_sequencer_payload(payload1) + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 4, + 'finished_voting': None + } + + payload2 = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417186' + } + # Period index: 0. Block: 4 of 6 + governance.using(baker1).new_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == pack_sequencer_payload(payload1) + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 3, + 'finished_voting': None + } + + # Period index: 0. Block: 5 of 6 + governance.using(baker2).upvote_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + # Period index: 0. Block: 6 of 6 + governance.using(baker3).upvote_proposal(payload2['sequencer_pk'], payload2['pool_address']).send() + self.bake_block() + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == pack_sequencer_payload(payload2) + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER * 3 + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 1, + 'finished_voting': None + } \ No newline at end of file diff --git a/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_vote.py b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_vote.py new file mode 100644 index 000000000000..9e3692adb719 --- /dev/null +++ b/etherlink/tezos_contracts/governance/tests/sequencer_governance/entrypoints/test_vote.py @@ -0,0 +1,213 @@ +from tests.base import BaseTestCase +from tests.helpers.contracts.governance_base import NAY_VOTE, PASS_VOTE, PROMOTION_PERIOD, PROPOSAL_PERIOD, YEA_VOTE +from tests.helpers.errors import ( + INCORRECT_VOTE_VALUE, NO_VOTING_POWER, NOT_PROMOTION_PERIOD, PROMOTION_ALREADY_VOTED, + TEZ_IN_TRANSACTION_DISALLOWED +) +from tests.helpers.utility import DEFAULT_TOTAL_VOTING_POWER, DEFAULT_VOTING_POWER, pack_sequencer_payload + +class CommitteeGovernanceNewProposalTestCase(BaseTestCase): + def test_should_fail_if_tez_in_transaction(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + with self.raisesMichelsonError(TEZ_IN_TRANSACTION_DISALLOWED): + governance.using(baker).vote(YEA_VOTE).with_amount(1).send() + + def test_should_fail_if_sender_has_no_voting_power(self) -> None: + no_baker = self.bootstrap_no_baker() + governance = self.deploy_sequencer_governance() + + with self.raisesMichelsonError(NO_VOTING_POWER): + governance.using(no_baker).vote(YEA_VOTE).send() + + def test_should_fail_if_current_period_is_not_promotion(self) -> None: + baker = self.bootstrap_baker() + governance = self.deploy_sequencer_governance() + + with self.raisesMichelsonError(NOT_PROMOTION_PERIOD): + governance.using(baker).vote(YEA_VOTE).send() + + def test_should_fail_if_vote_parameter_is_incorrect(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + }# Period index: 0. Block: 2 of 3 + governance.using(baker1).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + + # Period index: 0. Block: 3 of 3 + self.bake_block() + # Period index: 1. Block: 1 of 3 + self.bake_block() + + # Period index: 1. Block: 2 of 3 + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("yep").send() + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("no").send() + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("pas").send() + with self.raisesMichelsonError(INCORRECT_VOTE_VALUE): + governance.using(baker1).vote("NAY").send() + + governance.using(baker1).vote("yea").send() + governance.using(baker2).vote("nay").send() + governance.using(baker3).vote("pass").send() + self.bake_block() + + def test_should_fail_if_proposal_already_voted(self) -> None: + baker = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 3 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 3, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 2 of 3 + governance.using(baker).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + + # Period index: 0. Block: 3 of 3 + self.bake_block() + # Period index: 1. Block: 1 of 3 + self.bake_block() + + # Period index: 1. Block: 2 of 3 + governance.using(baker).vote(YEA_VOTE).send() + self.bake_block() + + with self.raisesMichelsonError(PROMOTION_ALREADY_VOTED): + governance.using(baker).vote(YEA_VOTE).send() + + def test_should_vote_on_proposal_with_correct_parameters(self) -> None: + baker1 = self.bootstrap_baker() + baker2 = self.bootstrap_baker() + baker3 = self.bootstrap_baker() + baker4 = self.bootstrap_baker() + # deploying will take 1 block + governance_started_at_level = self.get_current_level() + 1 + # Period index: 0. Block: 1 of 5 + governance = self.deploy_sequencer_governance(custom_config={ + 'started_at_level': governance_started_at_level, + 'period_length': 5, + 'upvoting_limit': 2, + 'proposal_quorum': 20 # 1 baker out of 5 will vote + }) + + assert governance.get_voting_state() == { + 'period_type': PROPOSAL_PERIOD, + 'period_index': 0, + 'remaining_blocks': 5, + 'finished_voting': None + } + + payload = { + 'sequencer_pk': 'edpkurcgafZ2URyB6zsm5d1YqmLt9r1Lk89J81N6KpyMaUzXWEsv1X', + 'pool_address': 'B7A97043983f24991398E5a82f63F4C58a417185' + } + # Period index: 0. Block: 2 of 5 + governance.using(baker1).new_proposal(payload['sequencer_pk'], payload['pool_address']).send() + self.bake_block() + # Period index: 1. Block: 1 of 5 + self.bake_blocks(4) + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 0 + assert storage['voting_context']['period']['proposal']['winner_candidate'] == pack_sequencer_payload(payload) + assert storage['voting_context']['period']['proposal']['max_upvotes_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['proposal']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 5, + 'finished_voting': None + } + + # Period index: 1. Block: 2 of 5 + governance.using(baker1).vote(YEA_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 4, + 'finished_voting': None + } + + + # Period index: 1. Block: 3 of 5 + governance.using(baker2).vote(NAY_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == 0 + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 3, + 'finished_voting': None + } + + # Period index: 1. Block: 4 of 5 + governance.using(baker3).vote(PASS_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 2, + 'finished_voting': None + } + + # Period index: 1. Block: 5 of 5 + governance.using(baker4).vote(YEA_VOTE).send() + self.bake_block() + + storage = governance.contract.storage() + assert storage['voting_context']['period_index'] == 1 + assert storage['voting_context']['period']['promotion']['yea_voting_power'] == DEFAULT_VOTING_POWER * 2 + assert storage['voting_context']['period']['promotion']['nay_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['pass_voting_power'] == DEFAULT_VOTING_POWER + assert storage['voting_context']['period']['promotion']['total_voting_power'] == DEFAULT_TOTAL_VOTING_POWER + assert governance.get_voting_state() == { + 'period_type': PROMOTION_PERIOD, + 'period_index': 1, + 'remaining_blocks': 1, + 'finished_voting': None + } \ No newline at end of file -- GitLab